Thursday, 17 October 2013

Modifying a file in a previous Git commit

Let's say we have project with a Git master branch and a topic branch named master-awesomo; in this topic branch we have the following commits:

Commit #1: some foo 
modified foo.js

Commit #2: foobar
modified bar.py
modified foo.js

Commit #3: only bar
modified bar.py

(where Commit #3 is the latest)

The issue is that we realized that there is an issue with bar.py introduced in Commit #2; the issue is not that big to introduce a new commit, and we want to keep the changes done to foo.js. Here's what we can do:

Start an interactive rebase:

# make sure we are in the correct branch
git checkout master-awesomo 

# actually start the rebase (interactive)
git rebase master -i

Depending on Git's configuration (usually ~/.gitconfig) an editor will start up, looking something like this:

pick SHA(Commit #1) some foo
pick SHA(Commit #2) foobar
pick SHA(Commit #3) only bar

Underneath this we can find some further explanations; what we want to do is change the second line to:

edit SHA(Commit #2) foobar

save, and close the editor. A message will be displayed:

Stopped at SHA(Commit #2)... foobar

This is what we want; we are now at the second commit and we can re-edit bar.py. First, we need to unstage it:

git reset HEAD^ bar.py

Now, we can go ahead and modify the file. After that, we need to amend the commit:

# notice that we don't do a standard commit, but we amend the
# existing one, as we are rebasing 
git commit --amend

Great, all that remains is to finish the rebase:

git rebase --continue

And we are done. Some notes:

  1. During the rebase, we might get some conflicts at Commit #3 (as we modified the same file in Commit #2) and we'll have to fix them before finishing the rebase.
  2. Assuming that bar.py was added, and not modified in Commit #2, we will need to re-add it when amending the commit during the rebase.
  3. If we are going to push master-awesomo to a remote location, we will have to --force it.
  4. If we realize that we did something wrong, we can at anytime abort the rebase with:
     git rebase --abort

     This will reset everything to its initial state (original Commit #3 and sub-tree).

No comments:

Post a Comment