撤消Git Rebase

Undoing a git rebase

有人知道如何轻松撤消git-rebase吗?

唯一能想到的方法就是手动操作:

  • Git将提交父级签出到两个分支
  • 然后从那里创建一个临时分支
  • Cherry用手挑选所有承诺
  • 用手动创建的分支替换我在其中重新定位的分支

在我目前的情况下,这是可行的,因为我可以很容易地发现来自两个分支的提交(一个是我的东西,另一个是我同事的东西)。

然而,我的方法让我觉得是次优和容易出错的(假设我刚刚用自己的两个分支重新调整了平衡)。

有什么想法吗?

澄清:我说的是一个REBASE,在此期间重播了大量提交。不止一个。


最简单的方法是找到分支的头提交,因为它就在reflog中启动rebase之前……

1
git reflog

并将当前分支重置为它(在使用--hard选项重置之前,通常需要确保绝对可靠)。

假设引用日志中的旧提交是HEAD@{5}

1
git reset --hard HEAD@{5}

在Windows中,可能需要引用引用:

1
git reset --hard"HEAD@{5}"

你只需做一个git log HEAD@{5}(windows:git log"HEAD@{5}")就可以检查候选老人头的历史。

如果您没有禁用每个分支回流,那么您应该能够简单地执行git reflog branchname@{1},因为在重新连接到最后一个分支之前,钢筋会分离分支头。我会仔细检查这个,因为我最近还没有核实过。

默认情况下,为非裸存储库激活所有重新登录:

1
2
[core]
    logAllRefUpdates = true


实际上,rebase将您的起点保存到ORIG_HEAD,因此这通常简单如下:

1
git reset --hard ORIG_HEAD

但是,resetrebasemerge都将原来的HEAD指针保存到ORIG_HEAD中,因此,如果您在尝试撤消的rebase之后执行了这些命令,则必须使用reflog。


查尔斯的回答很有效,但你可能想这样做:

1
git rebase --abort

清理后的reset

否则,您可能会收到消息"Interactive rebase already started"。


git reflog将显示重新平衡前后的所有更改,并允许您找到要重置的正确更改。但我很惊讶没有人提到这另一个非常简单的方法:

rebase将旧状态保留为ORIG_HEAD,因此可以通过运行以下命令恢复最后一个rebase:

1
git reset --hard ORIG_HEAD


将分支重置为其旧提示的悬空提交对象当然是最佳解决方案,因为它可以在不花费任何精力的情况下恢复以前的状态。但是,如果您碰巧丢失了那些提交(例如,因为您同时垃圾收集了存储库,或者这是一个新的克隆),那么您总是可以再次重新调整分支的基址。关键是--onto开关。

假设你有一个主题分支,想象中叫做topic,当master的尖端是0deadbeef的承诺时,你把master分支了。在某个时候,在topic分支上,你做了git rebase master。现在要撤消此操作。以下是如何:

1
git rebase --onto 0deadbeef master topic

这将接受所有不在master上的topic的承诺,并将其重放在0deadbeef之上。

使用--onto,您可以将历史重新排列成几乎任何形状。

玩得高兴。-)


实际上,在执行任何重要的操作之前,我在分支上放置了一个备份标记(大多数Rebase都是很小的,但是如果它看起来很复杂,我会这样做)。

然后,恢复和git reset --hard BACKUP一样简单。


如果您已将分支推送到远程存储库(通常是源站),然后成功执行完全重新平衡(不合并)(git rebase --abort给出"没有正在进行的重新平衡"),则可以使用命令:

git reset --hard origin/{branchName}

例子:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
$ ~/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


如果您还没有完成钢筋,在钢筋中间,以下工作:

1
git rebase --abort


使用reflog对我来说不起作用。

对我有用的东西和这里描述的相似。在.git/logs/refs中打开文件,该文件以重新设定基的分支命名,并找到包含"重新设定基finsihed"的行,如下所示:

1
5fce6b51 88552c8f Kris Leech <[email protected]> 1329744625 +0000  rebase finished: refs/heads/integrate onto 9e460878

签出该行上列出的第二个提交。

1
git checkout 88552c8f

一旦证实这包含了我丢失的变化,我就支支吾吾,松了一口气。

1
2
git log
git checkout -b lost_changes


对于多个提交,请记住,任何提交都引用了该提交之前的所有历史记录。所以在查尔斯的回答中,把"旧承诺"读作"旧承诺中的最新承诺"。如果您重置为该提交,则该提交之前的所有历史记录都将重新出现。这应该是你想要的。


如果您成功地对远程分支进行了重新平衡,并且不能执行ecx1(0),那么您仍然可以使用一些技巧来保存您的工作,并且没有强制执行。假设您当前错误地重新平衡的分支称为your-branch,正在跟踪origin/your-branch

  • git branch -m your-branch-rebased重命名当前分支
  • git checkout origin/your-branch结帐到已知来源的最新状态
  • git checkout -b your-branch
  • 检查git log your-branch-rebased,与git log your-branch比较,定义your-branch缺少的承诺。
  • git cherry-pick COMMIT_HASH中的每一个承诺
  • 推动你的改变。请注意,有两个本地分支机构与remote/your-branch关联,您只需推your-branch即可。


在@allan和@zearin的解决方案之后,我希望我可以简单地做一个评论,但是我没有足够的声誉,所以我使用了以下命令:

我不做git rebase -i --abort(注-i),只做git rebase --abort(没有-i)。

同时使用-i--abort会导致git向我显示使用/选项列表。

因此,我以前和现在使用此解决方案的分支状态是:

1
2
3
4
5
matbhz@myPc /my/project/environment (branch-123|REBASE-i)
$ git rebase --abort

matbhz@myPc /my/project/environment (branch-123)
$

比如说,我将master重置为我的功能分支,我得到了30个新的提交,这些提交会破坏一些东西。我发现,通常消除错误的承诺是最容易的。

1
git rebase -i HEAD~31

最后31次提交的交互式REBASE(如果您选择太多的方式,不会有任何影响)。

只需接受您想要摆脱的承诺,并用"d"而不是"pick"标记它们。现在,提交被有效地删除,从而撤消了重新平衡(如果只删除重新平衡时得到的提交)。


如果您在分支机构,可以使用:

1
git reset --hard @{1}

不仅有一个head的参考日志(由git reflog获得),也有每个分支的reflogs(由git reflog 获得)。所以,如果你在master上,那么git reflog master将列出对该分支的所有更改。您可以参考master@{1}master@{2}等所做的更改。

git rebase通常会多次更改头部,但当前分支只会更新一次。

@{1}只是当前分支的一个捷径,所以如果你在master上,它等于master@{1}

如果您在交互的rebase期间使用git resetgit reset --hard ORIG_HEAD将不起作用。


如果您在Git-Rebase中搞乱了某些东西,例如git rebase --abort,而您有未提交的文件,这些文件将丢失,git reflog将无济于事。这件事发生在我身上,你需要跳出这个框框来思考。如果你像我一样幸运,并且使用intellij webstorm,那么无论你在版本控制软件上犯了什么错误,你都可以执行cx1(2)并恢复到文件/文件夹的以前状态。再次运行故障保护总是很好的。