Rebasing allows you to move branches around and alter commit history by re-writing commits. This can be useful for cleaning up a messy history or updating a topic branch with the main branch.
However, a rebase can sometimes introduce bugs or issues you want to undo. Or perhaps you rebased the wrong branch by accident. Let's explore some options for undoing the effects of a rebase in Git.
Using git reflog and git reset to undo rebase
The easiest way to undo a rebase is to find the commit SHA of the branch tip before the rebase occurs. We can use git reflog
to find this:
$ git reflogf0a0f6f HEAD@{245}: rebase (finish): returning to refs/heads/mainf0a0f6f HEAD@{246}: rebase (pick): Cleaned up the folder a little0e911ec HEAD@{247}: rebase (start): checkout refs/remotes/origin/main
Here, we see f0a0f6f
was the tip of origin/main right before we started the rebase. We can reset back to this state with:
$ git reset --hard f0a0f6fHEAD is now at f0a0f6f Cleaned up the folder a little
The branch now looks as if we never performed the rebase.
When to avoid git reset
Resetting works well for local experimentation. However, git reset --hard
re-writes history, which can cause issues if working on a shared branch that's been pushed to GitHub. The git revert
approach mentioned below will be safer for published branches since it preserves history.
Using git reset ORIG_HEAD
Git also saves the starting point of a rebase in ORIG_HEAD. So, an alternative way to undo is:
$ git reset --hard ORIG_HEAD
One caveat is that ORIG_HEAD will get overwritten by subsequent git commands like merge, rebase, etc. So, if other commands have run since, the reflog method may be better.
Rebase again onto the original branch point
If previous commits are no longer available, we can rebase back onto the original base again. Suppose the feature was branched from main at commit abcd123:
$ git rebase --onto abcd123 main feature
This replays the feature commits on top of the commit it was originally branched from, effectively undoing the rebase.
Using git revert
To undo a rebase while preserving history, we can revert the new commits that were brought in:
$ git log main..feature$ git revert <commit 1> <commit 2>
This will introduce new commits that cancel out the changes from the rebase.
Choose the appropriate strategy based on whether the branch has been shared publicly or exists only locally. Resetting with git reset --hard
is ideal for throwaway branches.
But if a branch has been pushed online where others may depend on it, use git revert
to cleanly undo changes without rewriting history. The key is being able to identify the commit(s) prior to the rebase through git reflog
, ORIG_HEAD, or other means.