Undoing an errant 'git commit --amend'

June 13, 2014

Suppose, not entirely hypothetically, that late some evening you commit a change and somewhat later that evening notice that you left something out of it. Sleepily confident that you haven't pushed your first commit you fix the omission with 'git commit --amend', start updating your copy of the repo at work only to have it throw you into a merge, and discover that not only did you propagate the first commit, you pushed it to the public Github repo. Oops. Now you need to reverse or undo the 'git commit --amend' (and discard the update that you pulled into your repo copy at work).

I don't know if the procedure I followed to fix my oops is the completely right one, but it worked and repaired things. Here is what I did:

  • Use 'git reflog' to look at recent changes in your repo (cf). If you literally committed and then amended, the top two commits are the relevant ones. For me, I saw:
    ae22c04 HEAD@{0}: commit (amend): ....
    9cae7d1 HEAD@{1}: commit: ...

    This is the amended commit and then the original one. We want to get back to the original commit (which is currently orphaned, cf).

  • Get your repo back to the original commit. For me:
    git reset "HEAD@{1}"

    Various Internet sources suggest using 'git reset --soft' instead. If I understand Git right, this will leave your amended version of the commit sitting in the git index ready to be immediately committed again. I personally would rather roll all the way back to the stage where I have to 'git add' things again, which is what the command here did.

  • Inspect the output of 'git diff', then make a real (non-amended) commit with 'git add' and 'git commit' as usual.

  • Push the new commit to Github et al.

(There is probably some way to get Github and your other repos to accept your new amended commit and forget the old one, but I don't know it offhand, I didn't feel like working it out at the time, and I shouldn't assume that no one has pulled a copy from my Github repo.)

To clean up my work repo, I aborted the in-flight merge with 'git merge --abort' and then re-pulled the master with 'git pull'. Presumably the work repo now has an orphaned copy of the amended commit just as my home repo does, but I don't really care. If I was really curious I could probably find it with some git command, especially as I know (part of) its hash.

(The work and home repos are exact mirrors of each other and I'm only making changes in one at any given point, in this case in the home repo. I have to say that git handily beats rsync for this, although I have to overcome my twitch about possibly committing incomplete work.)

PS: The right search terms to find this stuff on the Internet are apparently [undo git commit amend]. Searching for [reverse git commit amend] mostly got me discussions about how to use git commit -amend.

PPS: There may well be better ways to do this in Git (and if so, feel free to mention them in the comments). I'm not entirely hep to Git yet, partly because I want my repos to have a straight linear history if at all possible. Someday I may start doing rebases off private branches to get this, but not so far.

(This is the kind of entry that I write because someday I'm going to make this mistake again someday.)

Comments on this page:

I'm not sure if public Github will support this (I know Enterprise does), but if you have the right permissions to a git repository you can just `git push -f $REMOTE $BRANCH`, which just tells $REMOTE to forget whatever it has as the tip of $BRANCH and instead use whatever you have locally.

Written on 13 June 2014.
« An init system has two jobs
I'm not very impressed with Ubuntu 14.04 LTS so far »

Page tools: View Source, View Normal, Add Comment.
Login: Password:
Atom Syndication: Recent Comments.

Last modified: Fri Jun 13 00:59:02 2014
This dinky wiki is brought to you by the Insane Hackers Guild, Python sub-branch.