Undo a git rebase using onto

2019-03-19 23:39发布

问题:

I rebased my branch version2 against master using:

git rebase --onto master version1 version2

How can I undo this?

To undo it I did git reflog

Currently, git status (on version2) gives me :

Your branch and 'origin/version2' have diverged,
and have 2563 and 222 different commits each, respectively.
nothing to commit (working directory clean)

I want to undo this rebase.

回答1:

Assuming you haven't modified the version2 branch since you rebased it, all you need to do is a hard reset of the branch to its 1st prior position, using <reference>@{n} syntax, where n is the Nth prior position of the reference:

git checkout version2
git reset --hard version2@{1}


回答2:

A very quick and easy way to undo a git rebase is to put the branch labels back.

If you're sure you want to abandon the current version2 branch tip, you can start with git reflog (like you did). I will include the rebase step here too, and I'll leave in a few "real" abbreviated refs:

$ git checkout branch
$ git rebase --onto master start-after branch
... rebase output ...
# oops! dag-nab-it! didn't mean to do that!

$ git reflog
<rev..> HEAD@{0}: rebase finished: returning to refs/heads/branch
<rev..> HEAD@{1}: rebase: some commit msg...
05f7dc8 HEAD@{2}: rebase: checkout master
aa4e140 HEAD@{3}: checkout: moving from master to branch

Here aa4e140 is where the HEAD of the branch was. This is also available in ORIG_HEAD:

$ git log -1 --oneline ORIG_HEAD
aa4e140 some commit msg...

(use more of the log if you need to, to make sure you're going to the right place.)

If you've done some other git things since the rebase, ORIG_HEAD may have moved, but the reflog will have the right value. If ORIG_HEAD and what you see in the reflog agree, you definitely have the right value. Either way, make sure you have the right value (and that you have no un-saved changes, that git status is clean—you can use git stash if needed, here).

Also try git reflog version2, which will show you the history of the label version2.

Now just force the current branch—make sure that's still the one you want changed—to the target commit:

$ git branch
... see that you're still on "branch" or "version2" or whatever
$ git reset --hard aa4e140

Voila, things are back to exactly the way they were before you ran git rebase.

If you have not done anything to change ORIG_HEAD, it's even easier than all this:

$ git log ORIG_HEAD # make sure that's what you want
...
$ git branch        # make sure you're on `version2`
...
$ git reset --hard ORIG_HEAD
HEAD is now at ...

but the reflog method is more general (works for about a month1 after the rebase, no matter what you have done in between).

(1The time period here is configurable; see git reflog documentation. The default 30 day expiration is for reflog entries "not reachable from the current tip of the branch", which is usually the case for the old commits from before a rebase.)


The key to understanding why this works is simple: git rebase keeps your old commits. It just adds new commits to the commit-graph, then moves the label. With the label moved, it's harder to see your old commits—they don't show up by default, they're only in the "reflog"—but they are still in there. Put the label back, and the new commits are the ones that don't show up, and the old ones are all back!



标签: git rebase