Undoing a git rebase
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
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, 2022Comments
-
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 almost 14 yearsGit reflog is awesome, just remember you can get better formatted output with
git log -g
(tip from Scott Chacon's progit.org/book). -
Hazok about 13 yearsPer Allan's answer below a
git rebase -i --abort
is needed as well. The above alone is not enough. -
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 userebase --abort
orreset --hard
depending on which situation you were in. You shouldn't need to do both. -
ripper234 almost 13 yearsI 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 over 11 yearsJust in case, make a backup first:
git tag BACKUP
. You can return to it if something goes wrong:git reset --hard BACKUP
-
Admin about 11 yearsYou actually don't even need to make a backup branch, you can simply use the
branchName@{n}
syntax, heren
is the nth prior position of the branch pointer. So for example, if you rebasefeatureA
branch onto yourmaster
branch, but you don't like the result of the rebase, then you can simply dogit reset --hard featureA@{1}
to reset the branch back to exactly where it was before you did the rebase. You can read more about thebranch@{n}
syntax at the official Git docs for revisions. -
Admin about 11 yearsIn case
ORIG_HEAD
is no longer useful, you can also use thebranchName@{n}
syntax, wheren
is the nth prior position of the branch pointer. So for example, if you rebasefeatureA
branch onto yourmaster
branch, but you don't like the result of the rebase, then you can simply dogit 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 almost 11 yearsIf you've made a lot of commits the HEAD@{#} you're looking for will be prefaced with
commit:
as opposed torebase:
. Sounds obvious but it confused me for a bit. -
Seph almost 9 yearsThis is the easiest. Follow it up with a
git rebase --abort
though. -
Alicia Tang over 8 yearsThis is the best option here! It kept all changes I have on my current branch, and removed all the unwanted ones!
-
Arunav Sanyal over 7 yearsThat was not the question. The question asks how to undo a finished rebase.
-
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 over 5 years@Seph Can you explain why you suggest following up with
git rebase --abort
? -
Devin Rhode over 3 yearsfor 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 almost 3 yearsThis 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 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 agit rebase --abort
should be harmless. If there is no ongoing rebase it will just fail complaining "fatal: No rebase in progress?
". -
PatPatchPatrick over 2 yearsThanks man, you saved my life. For me I had
rebase (finish):
followed by 3 commit IDs. The second ID was the correct one. -
Onewildgamer over 2 yearsThis can cause problems if there are local commits that weren't pushed. Be warned
-
alper over 2 yearsThis does not help
-
SherylHohman about 2 yearsMine 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 commandgit 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 about 2 yearsThis 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 about 2 yearsIs it possible to check what the commit of ORIG_HEAD is first?