Terminus by Warp
Undo a Git Rebase

Undo a Git Rebase

Philip Wilkinson
Philip Wilkinson
Software Engineer, Amazon

A key feature of Git is the ability to rebase commits onto another branch to ensure a streamlined, linear commit history and keep the repository organized. However, there may be situations where you need to undo the effects of a `git rebase` operation. This may be because you have accidentally performed the rebase on the wrong branch, the rebase has introduced bugs or issues, or the changes introduced are not desirable or are no longer necessary.

The short answer

The easiest way to undo a rebase is to find the head of the commit of the branch as it was immediately before the rebase and use the [.inline-code]git reset[.inline-code] command to rewind the commit history to that specific commit. This commit can be found using the [.inline-code]git reflog[.inline-code] command, which shows the history of the HEAD pointers.

For example, if the commit before the rebase was [.inline-code]HEAD@{2}[.inline-code] in the reflog, you can use the following command:

$ git reset --hard HEAD@{2}

This command allows you to reset the branch to the state it was before the rebase, because a rebased branch detaches the original branch head, before reattaching it to the final head.

[#easily-recall-with-ai]Easily retrieve this command using Warp’s AI Command Search[#easily-recall-with-ai]

If you’re using Warp as your terminal, you can easily retrieve this command using the Warp AI Command Search feature:

Entering [.inline-code]git reset hard[.inline-code] in the AI Command Search will prompt a [.inline-code]git[.inline-code] command that can then quickly be inserted into your shell by doing [.inline-code]CMD+ENTER[.inline-code].

[#using-org-head] Using the [.inline-code]ORIG_HEAD[.inline-code] pointer [#using-org-head]

Alternatively, when performing a rebase, [.inline-code]git[.inline-code] saves your starting point before the rebase as [.inline-code]ORIG_HEAD[.inline-code].

This means that you can also use the following command:

 $ git reset --hard ORIG_HEAD

It must be noted however that the [.inline-code]git reset[.inline-code], [.inline-code]git rebase[.inline-code], and [.inline-code]git merge[.inline-code] commands all save the original [.inline-code]HEAD[.inline-code] pointer into [.inline-code]ORIG_HEAD[.inline-code]. This means that if you have used any of these commands following the rebase, you will instead have to use the [.inline-code]reflog[.inline-code] to identify how to reset the branch.

[#using-a-remote-repository] Using the remote repository [#using-a-remote-repository]

If the branch you are trying the rollback has been pushed to the remote repository before the rebase operation, you can use it as a backup to reset the branch using the following command:

 $ git reset --hard origin <branch_name>

Where <branch_name> is the reference you use in the remote repository. However, note that this can cause conflicts if your local branch contains commits that haven't been pushed to the remote repository.

[#undoing-with-git-rebase] Undoing a rebase with [.inline-code]git rebase[.inline-code] [#undoing-with-git-rebase]

In some cases the previous state of the branch before the rebase may be no longer available. An alternative is to rebase the branch again back onto the original base of the branch. This can be done using the [.inline-code]--onto[.inline-code] flag if you know the commit where the branch originated from.

For example, a branch named [.inline-code]feature[.inline-code] was originally branched off [.inline-code]main[.inline-code] when the tip of [.inline-code]main[.inline-code] was [.inline-code]xcommit[.inline-code]. A rebase was then performed back onto the [.inline-code]main[.inline-code] branch using [.inline-code]git rebase main[.inline-code].

To undo this rebase, you can use the following command:

 $ git rebase --onto xcommit master feature

This will take all of the commits on the [.inline-code]feature[.inline-code] branch that aren’t on the [.inline-code]main[.inline-code] branch and  move them on top of [.inline-code]xcommit[.inline-code].

[#undoing-with-git-revert] Undoing a rebase with [.inline-code]git revert[.inline-code][#undoing-with-git-revert]

A more complicated but history preserving way of undoing a rebase is to use the [.inline-code]git revert[.inline-code] command that will revert the new commits (i.e. create new opposing commits) introduced from the branch you rebased onto.

For example, a [.inline-code]feature[.inline-code] branch was originally branched off [.inline-code]main[.inline-code] at [.inline-code]xcommit[.inline-code]. A rebase was then performed back onto [.inline-code]main[.inline-code] at [.inline-code]ycommit[.inline-code]. In this case, you can use the [.inline-code]git log[.inline-code] command to find the commits between [.inline-code]xcommit[.inline-code] and [.inline-code]ycommit[.inline-code],  and undo them one by one using the [.inline-code]git revert[.inline-code] command as follows:

$ git revert <xcommit+1> <xcommit+2>…<ycommit>

Alternatively, you can also take advantage of the commit range feature of [.inline-code]git revert[.inline-code] by specifying the commit after the original and the latest commit on the [.inline-code]main[.inline-code] branch:

$ git revert <xcommit+1>..<ycommit>

Which will create revert commits from <xcommit+1> up until <ycommit>.

[#undoing-local-vs-remote]Undoing local vs remote rebase [#undoing-local-vs-remote]

When you haven’t pushed the changes to a remote repository then the process of undoing a rebase becomes simpler. This is because you don’t have to worry about the effects on other developers or the impact on the history of the repository. The simplest solution would be to use any of the [.inline-code]git reset[.inline-code] or [.inline-code]git rebase[.inline-code] options presented above.

If you have pushed the rebased branch up to the remote repository, other developers may already be using the rebased branch. In such cases, changing the branch history can lead to conflicts and confusion within the team. In this case, the best solution is to use the [.inline-code]git revert[.inline-code] solution presented above, which preserves the branch's history and creates new commits that other developers can then use.

[#undoing-squashed-rebase]Undo a squashed rebase[#undoing-squashed-rebase]

A common rebase operation is a squash rebase where all, or some of the commits in the branch are squashed together into a single commit before they are rebased onto a new branch. This discards the original commits and creates a new consolidated single commit. The only way to resolve this and to restore the original commit structure is to use the [.inline-code]reset[.inline-code] option, which will restore the branch to its original condition.

Experience the power of Warp

  • Write with an IDE-style editor
  • Easily navigate through output
  • Save commands to reuse later
  • Ask Warp AI to explain or debug
  • Customize keybindings and launch configs
  • Pick from preloaded themes or design your own
brew install --cask warp
Copied!
Join the Windows waitlist:
Success! You will receive an email from Warp when the release is available to download.
Oops! Something went wrong while submitting the form.
Join the Linux waitlist:
Success! You will receive an email from Warp when the release is available to download.
Oops! Something went wrong while submitting the form.
Join the Linux waitlist or join the Windows waitlist
Join the Windows waitlist:
Success! You will receive an email from Warp when the release is available to download.
Oops! Something went wrong while submitting the form.