【问题标题】:How do I undo a git rebase and redo as a git merge如何撤消 git rebase 并作为 git merge 重做
【发布时间】:2014-02-14 00:25:56
【问题描述】:

我在一个分支上运行了 git rebase 并修复了所有冲突,然后意识到对于这个特定的分支我需要运行 git merge 来保留历史记录。有没有办法“撤消”变基但在运行 git merge 时自动重新应用我的修复?

【问题讨论】:

  • 如果您将rerere.enabled 设置为true,那应该已经发生了。

标签: git git-merge git-rebase undo-redo


【解决方案1】:

作为Amber said in a comment,如果您打开 rerere,git 将“重新”记录您之前的“重新”解决方案(三个重新中的两个)。然后,如果您将事物重置为预变基状态并“git merge”,它应该“重新”使用它们(最后一个“重新”)。

但如果没有,就不会。

那该怎么办?假设您对自己的解决方案非常有信心 :-) 您可以试试这个。

ORIG_HEAD 可能仍指向原始提交链(预变基)。如果没有,请在 reflogs 中找到旧的分支提示。给它一个标签(分支或标签名称),同时在后变基链上保留一个标签。也就是我们要复活旧的枝尖,也要保留新的枝尖。 (确切的为什么在你理解了其余部分之后应该是显而易见的。)

我假设在 rebase 时,您修改了提交 CF 并完全删除了 DE,因为不再需要。并不是说这真的很重要。 F' 是唯一关键的提交。关键是提交F' 捕获了工作树的“最终、全部解决”版本:

        C - D - E - F   <-- feature_orig
      /
A - B - G - H - I - J   <-- mainline
                      \
                        C' - F'  <-- feature

以上是您在执行git branch feature_orig ORIG_HEAD 之后可以看到的内容(或从 reflogs 中恢复原始提示并使用它来创建 feature_orig)。

您现在(根据原始问题)想要的是合并:“将功能合并到主线”或“将主线合并到功能”。除了,您希望它发生在/与feature_orig 上,而不是重新定位的feature

还有一个问题:你想保留feature 分支吗? (如果你在这里将 mainline 合并到 feature 中,你可能会这样做。如果将功能合并到主线中,可能不会。但至多,我怀疑你会想要保留 feature_orig,而不是重新定位的线。)让我们现在再移动一个分支名称,以——我希望——使画面更清晰:

$ git branch -m feature feature_rebased

现在我们有了这个:

        C - D - E - F   <-- feature_orig
      /
A - B - G - H - I - J   <-- mainline
                      \
                        C' - F'  <-- feature_rebased

现在进行合并。进入您希望合并提交显示的分支:

$ git checkout ...

(我不知道这是哪个分支,feature_origmainline!)

然后进行合并,忽略结果而不提交:

$ git merge --no-commit ...

(无论您要合并哪个分支)。

现在只需将每个文件替换为来自提交 F' 的版本(注意,我假设您在此处的顶级工作目录中):

$ git rm -rf .; git checkout feature_rebased -- .

rm 步骤完全清空索引,包括所有冲突以及工作树。然后checkout 步骤使用提交F' 中的任何内容(通过分支名称feature_rebased 获得)完全重新填充索引和工作树。

您现在可以在您所在的任何分支上提交合并。具体来说,假设您在 feature_orig 上并要求 git 合并 mainline。在git commit 之后,您应该将其作为您的提交图:

        C - D - E - F - M  <-- feature_orig
      /               /
A - B - G - H - I - J   <-- mainline
                      \
                        C' - F'  <-- feature_rebased

我认为这里值得一提的是,这只是提交图tree 的内容——当你git checkout 任何这些提交时你在你的工作目录中获得的文件——由提交时索引/暂存区域的内容决定已创建。

这就是为什么我们可以git rm 一切,然后git checkout <em>id</em> -- . 来设置合并提交的内容。当我们提交合并时,我们所做的就是创建一个提交M,其父级是FJ,其内容是“索引中现在的任何内容”。

(父FJ顺序,以及新提交ID写入哪个分支名称,由我们开始和结束时所在的分支决定git merge 进程。如果我们“在分支feature_orig 上,那么F 是第一个父级,M 转到“在分支feature_orig”上。如果我们在“在分支mainline 上,那么J是第一个父母,M 转到“分支mainline”。当然,准备好的提交文本,你可以在提交发生之前编辑,有点不同。但是你可以编辑它来阅读你的任何内容喜欢。)


此时(或者甚至更早)您现在可以将 feature_orig 重命名为 feature,如果您想保留该名称。您也可以删除分支feature_rebased,因为不再需要保存提交C'F'。事实上,我们只是真的想坚持F',以便我们可以git checkout 它的树——我们可以在完成checkout 后立即删除分支。

【讨论】:

    猜你喜欢
    • 2014-10-01
    • 2017-11-08
    • 2012-06-10
    • 2011-01-13
    • 2012-09-27
    • 2012-11-08
    • 1970-01-01
    相关资源
    最近更新 更多