Javaexercise.com

How To Undo A Git Rebase?

The git rebase command re-bases or changes the base of a branch. The commit from where a Branch originates is called it's base. We prefer rebasing over merging when we wish to maintain a linear commit history.

An example of rebasing the feature branch onto the master branch is shown below.

Before Rebase:
​
A -- B -- C -- D -- E <- master
          \
           F -- G <- feature
​
After Rebase
​
A -- B -- C -- D -- E <- master
          \         \
           \         F' -- G' <- feature <- HEAD
             \
              F -- G

Sometimes we may want to undo the Git Rebase command. Let's learn how to undo a Git Rebase.

Undo Git Rebase using the Git Reset Command

The Git Reset command resets our repository to a previous state. It rewrites the history of our project. We can use the Git Reset command to undo the effects of a Git Rebase.

The Git Reset command needs a commit hash or reference to the original commit. Git Reset requires a reference to the commit where the branch HEAD was before the Rebase. To find the commit hash, we can use the Git Reflog command.

git reflog

We can also use the ORIG_HEAD. The Git Rebase command saves our the previous HEAD(before the rebase) of our feature branch as ORIG_HEAD. Note that Git Reset, Git Rebase, and Git Merge commands update the ORIG_HEAD. So, if we have used any of these commands after the initial rebase, our only option is to use the Git Reflog command.

Next, use the Git Reset command with the --hard option to undo the Rebase. This will reset our current branch to point to the given commit. Note that the --hard option will reset any uncommitted changes. Make sure to stash any uncommitted changes by using the Git Stash command.

git reset --hard <commit-hash>
git reset --hard ORIG_HEAD

Example

Let's take an example to understand the process discussed above. Consider a repository with two branches - master and feature. The initial state of the repo is shown below.

A -- B -- C -- D -- E <- master
          \
           F -- G <- feature <- HEAD

Let's Rebase the feature branch onto the master branch.

A -- B -- C -- D -- E <- master
          \         \
           \         F' -- G' <- feature <- HEAD
             \
              F -- G

Now, we want to undo the Git Rebase that we just performed. First, we require the hash of the original commit where the feature branch HEAD was, that is, the hash of commit G. The commit G is not part of any branch, so we need to use the Git Reflog command to find its commit hash. Or we can use the ORIG_HEAD notation as we have not used any other Git command that updates the ORIG_HEAD(like Reset or Merge).

git reflog

Let's reset our feature branch back to commit G.

git reset --hard <hash-of-commit-G>
git reset --hard ORIG_HEAD

The final state of our repository is shown below.

A -- B -- C -- D -- E <- master
          \
           F -- G <- feature <- HEAD

Undo Git Rebase using the Git Rebase --onto Command

After a while, the Git garbage collector removes all the dangling commits(commits without a reference). So, we may not find the required commit in the reflog. In these cases, we can use the Git Rebase command with the --onto option. By using the --onto option, we are rebasing the branch back to its original base.

Example

Consider a repository with two branches - master and feature. The feature branch was rebased on the master branch.

Before Rebase:
​
A -- B -- C -- D -- E <- master
          \
           F -- G <- feature
​
After Rebase
​
A -- B -- C -- D -- E <- master
          \         \
           \         F' -- G' <- feature <- HEAD
             \
              F -- G

Let's undo the rebase operation. We will use the --onto option. We also need the hash of the commit C, that is, the hash of the base of the feature branch before the rebase.

git rebase --onto <hash-of-commit-C> master feature

The above command rebases all the commits of the feature branch that are not present on the master branch(commit F' and G') onto commit X.

A -- B -- C -- D -- E <- master
          \
           F'' -- G'' <- feature

Conclusion

The Git Rebase command is used to "rebase" or change the base of a branch. Rebasing is preferred over merging when we want to maintain a linear commit history. Sometimes, mistakes occur and we may need to undo the rebase. The Git Reset command can undo the effects of a Git Rebase. We need to pass the commit hash of the tip of the branch before the rebase to the Git Reset command. Use the Git Reflog command to find this commit hash. Note the Git Reset --hard will delete uncommitted changes. Stash such changes by using the Git Stash command.

Alternatively, we can use the Git Rebase --onto command. This is helpful when the original HEAD is removed from the repo by the garbage collector.