Undoing a git rebase

1,483,136

Solution 1

The easiest way would be to find the head commit of the branch as it was immediately before the rebase started in the reflog...

git reflog

and to reset the current branch to it (with the usual caveats about being absolutely sure before reseting with the --hard option).

Suppose the old commit was HEAD@{2} in the ref log:

git reset --hard HEAD@{2}

In Windows, you may need to quote the reference:

git reset --hard "HEAD@{2}"

You can check the history of the candidate old head by just doing a git log HEAD@{2} (Windows: git log "HEAD@{2}").

If you've not disabled per branch reflogs you should be able to simply do git reflog branchname@{1} as a rebase detaches the branch head before reattaching to the final head. I would double check this, though as I haven't verified this recently.

Per default, all reflogs are activated for non-bare repositories:

[core]
    logAllRefUpdates = true

Solution 2

Actually, rebase saves your starting point to ORIG_HEAD so this is usually as simple as:

git reset --hard ORIG_HEAD

However, the reset, rebase and merge all save your original HEAD pointer into ORIG_HEAD so, if you've done any of those commands since the rebase you're trying to undo then you'll have to use the reflog.

Solution 3

Charles's answer works, but you may want to do this:

git rebase --abort

to clean up after the reset.

Otherwise, you may get the message “Interactive rebase already started”.

Solution 4

Resetting the branch to the dangling commit object of its old tip is of course the best solution, because it restores the previous state without expending any effort. But if you happen to have lost those commits (f.ex. because you garbage-collected your repository in the meantime, or this is a fresh clone), you can always rebase the branch again. The key to this is the --onto switch.

Let’s say you had a topic branch imaginatively called topic, that you branched off master when the tip of master was the 0deadbeef commit. At some point while on the topic branch, you did git rebase master. Now you want to undo this. Here’s how:

git rebase --onto 0deadbeef master topic

This will take all commits on topic that aren’t on master and replay them on top of 0deadbeef.

With --onto, you can rearrange your history into pretty much any shape whatsoever.

Have fun. :-)

Solution 5

In case you had pushed your branch to remote repository (usually it's origin) and then you've done a succesfull rebase (without merge) (git rebase --abort gives "No rebase in progress") you can easily reset branch using command:

git reset --hard origin/{branchName}

Example:

$ ~/work/projects/{ProjectName} $ git status
On branch {branchName}
Your branch is ahead of 'origin/{branchName}' by 135 commits.
  (use "git push" to publish your local commits)

nothing to commit, working directory clean

$ ~/work/projects/{ProjectName} $ git reset --hard origin/{branchName}
HEAD is now at 6df5719 "Commit message".

$ ~/work/projects/{ProjectName} $ git status
On branch {branchName}
Your branch is up-to-date with 'origin/{branchName}.

nothing to commit, working directory clean
Share:
1,483,136
webmat
Author by

webmat

10 Mathieu's life as a programmer began with GWBasic. After an unfortunate journey taking him through the restricted lands of Pacal, Delphi, VB, Java, C++, C#, he finally discovered Ruby. Going from not knowing Ruby to knowing Ruby was for him a revelation of roughly the same order of magnitude as discovering programming. He discovered Git at about the same time he started working with Ruby professionally, and had the same kind of revelation for source control. Needless to say, both tools are now the underpinnings of most of the things he undertakes programmatically. Mathieu can be observed in the wild, sometimes going under the name of webmat. He will often be rambling (programblings.com) about programming, Git or working on open source projects. He is the author of git_remote_branch, a tool that helps common mortals like him trivially manipulate branches published in shared repositories.

Updated on July 08, 2022

Comments

  • webmat
    webmat almost 2 years

    Does anybody know how to easily undo a git rebase?

    The only way that comes to mind is to go at it manually:

    • git checkout the commit parent to both of the branches
    • then create a temp branch from there
    • cherry-pick all commits by hand
    • replace the branch in which I rebased by the manually-created branch

    In my current situation this is gonna work because I can easily spot commits from both branches (one was my stuff, the other was my colleague's stuff).

    However my approach strikes me as suboptimal and error-prone (let's say I had just rebased with 2 of my own branches).

    Any ideas?

    Clarification: I'm talking about a rebase during which a bunch of commits were replayed. Not only one.

  • karmi
    karmi almost 14 years
    Git reflog is awesome, just remember you can get better formatted output with git log -g (tip from Scott Chacon's progit.org/book).
  • Hazok
    Hazok about 13 years
    Per Allan's answer below a git rebase -i --abort is needed as well. The above alone is not enough.
  • CB Bailey
    CB Bailey about 13 years
    @Zach: git rebase --abort (-i makes no sense with --abort) is for abandoning a rebase that hasn't been completed - either because there were conflicts or because it was interactive or both; it's not about undoing a successful rebase which is what the question is about. You would either use rebase --abort or reset --hard depending on which situation you were in. You shouldn't need to do both.
  • ripper234
    ripper234 almost 13 years
    I think this is the best option because of its flexibility. I branched b1 off master, then rebased b1 into a new branch b2, then wanted to revert b1 to be based on master again. I just love git - thanks!
  • kolypto
    kolypto over 11 years
    Just in case, make a backup first: git tag BACKUP. You can return to it if something goes wrong: git reset --hard BACKUP
  • Admin
    Admin about 11 years
    You actually don't even need to make a backup branch, you can simply use the branchName@{n} syntax, here n is the nth prior position of the branch pointer. So for example, if you rebase featureA branch onto your master branch, but you don't like the result of the rebase, then you can simply do git reset --hard featureA@{1} to reset the branch back to exactly where it was before you did the rebase. You can read more about the branch@{n} syntax at the official Git docs for revisions.
  • Admin
    Admin about 11 years
    In case ORIG_HEAD is no longer useful, you can also use the branchName@{n} syntax, where n is the nth prior position of the branch pointer. So for example, if you rebase featureA branch onto your master branch, but you don't like the result of the rebase, then you can simply do git reset --hard featureA@{1} to reset the branch back to exactly where it was before you did the rebase. You can read more about the branch@{n} syntax at the official Git docs for revisions.
  • Warpling
    Warpling almost 11 years
    If you've made a lot of commits the HEAD@{#} you're looking for will be prefaced with commit: as opposed to rebase:. Sounds obvious but it confused me for a bit.
  • Seph
    Seph almost 9 years
    This is the easiest. Follow it up with a git rebase --abort though.
  • Alicia Tang
    Alicia Tang over 8 years
    This is the best option here! It kept all changes I have on my current branch, and removed all the unwanted ones!
  • Arunav Sanyal
    Arunav Sanyal over 7 years
    That was not the question. The question asks how to undo a finished rebase.
  • dudewad
    dudewad about 7 years
    git rebase --abort aborts an active rebase, it doesn't undo a rebase. Also, using two VCS's at the same time is a bad idea. Its a nice feature in Jetbrains software but you shouldn't use both. It's better to just learn Git, particularly when answering questions on Stack Overflow that are about Git.
  • UpTheCreek
    UpTheCreek over 5 years
    @Seph Can you explain why you suggest following up with git rebase --abort?
  • Devin Rhode
    Devin Rhode over 3 years
    for some reason your answer made me realize I can do a git rebase -i commitish and then EDIT the commit I wasn't satisfied with :)
  • Adrian
    Adrian almost 3 years
    This is a very clean solution. Thank you for posting. I always push to remote before doing a rebase and this post saved my bacon, as I was ~3 days out of date w/ master on a big project. Thank you :)
  • Jacopo Tedeschi
    Jacopo Tedeschi almost 3 years
    @Seph I agree with UpTheCreek as in my case it was not necessary. Maybe it is needed when things get odd during an interactive rebase? I would suggest anyone to try a git status to see if it mentions about the rebase or not first. Anyway doing a git rebase --abort should be harmless. If there is no ongoing rebase it will just fail complaining "fatal: No rebase in progress?".
  • PatPatchPatrick
    PatPatchPatrick over 2 years
    Thanks man, you saved my life. For me I had rebase (finish): followed by 3 commit IDs. The second ID was the correct one.
  • Onewildgamer
    Onewildgamer over 2 years
    This can cause problems if there are local commits that weren't pushed. Be warned
  • alper
    alper over 2 years
    This does not help
  • SherylHohman
    SherylHohman about 2 years
    Mine listed 2 commit id's, and said rebase (finish). Since I wanted the commit BEFORE I rebased, I used the 2nd commit id on the line PRIOR to the rebase (=== the 1st commit id on the line WITH the rebase command). Then I used the command git reset --hard <commit id>. Viola! Restored as if I never performed the rebase. The commit IDs seem to be in the format of idBeforeCommand idAfterCommand Who Date/time Command
  • questionto42standswithUkraine
    questionto42standswithUkraine about 2 years
    This did not help me (just in my case), I got back by two commits to an older one, though I needed the newer two commits. The accepted answer with taking the right line from reflog made it.
  • Simon
    Simon about 2 years
    Is it possible to check what the commit of ORIG_HEAD is first?