Recovering from a bad git-rebase

Posted by Ross Burton on July 19, 2012

Being a good Git citizen I often use git add -p and git rebase -i to produce a perfect patch series that doesn't reflect the reality of creating it, but is far easier to review and understand later. Then, of course, a rebase can go terribly wrong...

Today I was doing one last rebase to squash a few typo fix commits, and accidentally squashed the wrong commits.  I was left with a single commit that claimed to do one thing, but actually has several unrelated (but more important) changes.  Urgh.  One solution would be to do another interactive rebase and use git add -p to split the commit, but I thought I'd try using the reflog.

The Git reflog is a log of all changes that have happened to the tree, including all the stages of apparently destructive and deep rebase operations.

$ git reflog
 9f46daa HEAD@{142}: rebase -i (finish): returning to refs/heads/gtkdoc
 8d7f266 HEAD@{166}: rebase -i (squash): glib-2.0: cleanup thanks to new gtk-doc.bbclass
 a8f06b1 HEAD@{167}: rebase -i (squash): updating HEAD
 0ac2f59 HEAD@{168}: rebase -i (fixup): # This is a combination of 3 commits.
 a8f06b1 HEAD@{169}: rebase -i (fixup): updating HEAD
 cccef4d HEAD@{170}: rebase -i (fixup): # This is a combination of 2 commits.
 a8f06b1 HEAD@{171}: rebase -i (fixup): updating HEAD
 c7ef1a6 HEAD@{172}: checkout: moving from gtkdoc to c7ef1a6
 14bdd14 HEAD@{173}: commit: glib squash

From the bottom up, the checkout of a hash is the start of the rebase. Then there are some fixups and squashes. whoops! The top squash shouldn't be squashed, but picked. Never mind, we can checkout the tree as it was before the rebase with git checkout -b gtkdoc2 14bdd14, which I've highlighted. Double check that the tree is what you expect, and then the old branch can be deleted and the new one renamed. Braver people may want to simply git reset --hard 14bdd14, but the double safety net is useful.

Update: for a more concise method, see glandium's reply in the comments.

tags: git, tech