Close
Glad You're Ready. Let's Get Started!

Let us know how we can contact you.

Thank you!

We'll respond shortly.

LABS
rewinding git commit –amend

It may come to pass that you will amend HEAD with changes that were meant to go on a commit earlier than HEAD via git commit --amend. In this case, you’ll want to rewind that operation you just did, and apply it to the correct commit. With simple changes you may find git reset -p handy. For times when the changes are far too large and intertwined to the commit, you will want to refer to git reflog for help.

The reflog records when the tip of a branch is updated. The tip is updated any time you create a new commit, amend a commit, reset a commit, switch branches, etc. Basically, any time HEAD changes, you will get a reflog entry. The reflog therefore is a great tool for understanding how the repository came to be in a particular state.

git reflog -2 will give you the last two operations that Git performed. In this case, it will look something like:

8751261 HEAD@{0}: commit (amend): Something something something commit message
9d3a192 HEAD@{1}: reset: moving to HEAD~1

git commit --amend is kind of shorthand for (given changes have been made, and are either in the index or in the working directory):

git stash
git reset HEAD~1
git stash pop
git add .
git commit

Or, in English:

  • Save the changes that you want to apply to the HEAD commit off in the stash
  • Remove the HEAD commit and put its contents in the index
  • Apply the stashed changes to the working directory, adding them to the changes from the commit that was reset
  • Make a new commit.

Thus, the last two operations in the reflog are reset and commit.

So, what can we do with this? Well, 9d3a192 was HEAD before the amend (specifically, before the reset) happened. 8751261 was the commit that resulted at the end of the amend process. git diff 8751261..9d3a192 will show you what changes were applied as part of the amend.

From here, you can use git apply to apply the difference from before the amend to after the amend to your working tree via git diff:

git diff 8751261..9d3a192 | git apply -
  • Note: The hyphen in git apply - causes git apply to take stdin as input.
  • Extra Note: The arguments here are given in reverse order, with the later commit happening first to show the reverse of the amend. It’s the same as doing git diff 9d3a192..8751261 -R, which reverses the diff output. Additionally, the -R argument may be applied to git apply instead of git diff to achieve the same effect.

Now we can do another amend to put the commit back to where it was before we did the previous amend:

git commit -a --amend -CHEAD

And then, by reversing the order of the SHAs to git diff, get the changes we want to apply to the correct commit back:

git diff 9d3a192..8751261 | git apply -

And commit as necessary, this time using –fixup to indicate the correct commit (in this example, 1234567):

git commit -a --fixup 1234567

Then you can rebase at a later time (or now) to do the ‘amend’ you had originally intended:

git rebase --i --autosquash 1234567~1

So don’t fret when you do an accidental amend. It’s just a couple commands away from being unwound and applied to the correct commit.

Comments
  1. John Barker says:

    Note that if you try and apply this patch and there is a conflict, you might find the –reject option useful. It will save the rejected hunks as .rej files alongside the files those hunks would apply to.

    I then open up the rejected hunks (using :argl `find . -iname *.rej`) and their corresponding files (with :argl `find . -iname *.rej | sed s/.rej//g`) in two side by side vim windows to see what’s changed. Though I feel like there might be a better way to do this with git + mergetool.

Post a Comment

Your Information (Name required. Email address will not be displayed with comment.)

* Copy This Password *

* Type Or Paste Password Here *