首页 > 解决方案 > 修复删除的合并

问题描述

我有一个场景,当 2 个并行功能分支合并到其父分支时,某些更改已被删除。像这样的东西,

     C1-D1-E1
    /        \
A--B          F*-G
    \        /
     C2-D2-E2

F* - 合并冲突已解决

C2-D2-E2分支的更改正在以上述方式完成,由于错误的解决方案,我丢失了在分支中完成的所有更改。这里提到了更改丢失但日志仍然包含提交 ID 的原因。

为了解决这个问题,当我尝试合并回包含这些文件的分支时,它不会因为来自分支的提交已经是日志的一部分。将丢失的更改带回主分支的最佳方法是什么?

标签: git

解决方案


恢复丢失的更改的最佳方法是什么...

吃鸡蛋的最佳方法是什么?从大端开始,还是从小端开始?(参考

或者,换句话说,没有最好的方法。有一些可行的方法,或者不可行的方法。这些方法可能更容易,也可能更难,或者对于您遇到的某些特定情况可能更好,或者没有。

两个相对简单的选择是:

  • 使用git cherry-pick, 或
  • 从合并中挑选使用git revert -m(但这个解释起来有点棘手)。

采摘樱桃

Cherry-picking 本质上是复制提交的过程。本质上,我们让 Git 将提交与其父提交进行比较。也就是说,假设我们有一系列这样的提交:

...--o--o   <-- master
      \
       o--o--P--C--o--o   <-- feature (HEAD)

在提交时P(父级),在处理分支feature时,我们发现了一些讨厌的错误并在子提交中修复它C。我们想立即修复master. 我们可以git checkout master; git merge <hash-of-C>合并,C但这会带来另外三个提交:两个 before P,然后是P本身。所以我们运行git checkout master,给我们:

...--o--o   <-- master (HEAD)
      \
       o--o--P--C--o--o   <-- feature

现在我们运行git cherry-pick <hash-of-C>. Git 将提交P中的快照与提交中的快照进行比较,C以查看我们如何修复错误,然后对我们当前的索引和工作树进行相同的更改,并使用提交消息的副本提交结果C,给我们:

...--o--o--C'  <-- master (HEAD)
      \
       o--o--P--C--o--o   <-- feature

实际上,我们已经将commit复制C到了 new commit C'。它具有与 相同的消息C并且对代码执行与对 相同的操作CP它是不同的提交,在图中的不同位置。

使用它来更正您的合并

你有:

     C1-D1-E1
    /        \
A--B          F--G   <-- somebranch (HEAD)
    \        /
     C2-D2-E2

哪里F是一个错误的合并(可能是用 完成的git merge -s ours),它会从 . 中删除部分或全部工作C2-D2-E2。挑选这三个提交将产生三个新的提交,每个提交都执行这三个提交所做的事情。

要cherry-pick C2, D2, 并E2使用一个简单的命令,假设它F^2E2(即,它E2是 的第二个父级F),您可以运行:

git cherry-pick F^2~3..F^2

(替换F为适当的哈希 ID,或使用HEAD^通过 commit 命名G,例如,git cherry-pick HEAD^^2~3..HEAD^^2)。

樱桃采摘与恢复

有时,我们不想复制提交,而是想撤消它。也就是说,假设我们有:

...--o--P--C--o--o   <-- somebranch (HEAD)

回顾历史,我们意识到提交C只是一个错误。如果我们可以撤消它,我们会没事的。这就是git revert进来的地方。我们告诉 Gitgit revert <hash-of-C>和 Git 比较PC看看有什么变化,然后取消那个变化。结果是一个与以下相反的新提交C(我将其绘制为3不如 Ↄ 但 Ↄ 可能不是所有字体,并且在我的浏览器中以计算机文本的形式呈现奇怪):

...--o--P--C--o--o--3   <-- somebranch (HEAD)

从技术上讲,cherry-pick 和 revert 都使用 Git 的合并引擎。他们将合并基础提交设置P为cherry-pick,两个输入是HEADand C; 或者,对于还原,合并基数是C并且两个输入是HEADP。然后 Git 进行一次完整的三向合并,如果一切顺利,将结果作为普通提交提交,并将HEAD提交作为新提交的父提交。但是,如果您必须解决合并冲突,则仅需要此技术说明 — 挑选或恢复的效果是重新应用或撤消通过比较提交与其父项发现的更改。

樱桃采摘或恢复合并

合并提交是一个至少有两个父级(并且大多数只有两个父级)的提交。由于通过将提交与其父级进行比较来进行挑选工作,因此没有明显的方法来挑选合并。它有两个父母,Git 无法同时与两者进行比较。1 但这也意味着没有明显的方法可以恢复合并,Git 需要一种方法来恢复合并。所以两者都git cherry-pick允许git revert一个选项,-m. 当你给出这个选项时,你也给出了一个父母号码。然后,Git 在cherry-pick 或 merge 命令期间假装合并提交只有一个父级:您选择的那个。

这意味着如果我们运行:

git revert -m 2 <hash-of-F>

您的错误合并在哪里F,Git 会将快照 inF与快照进行比较E2,以查看发生了什么变化。如果您手动运行相同的差异,则使用F第一个提交和E2第二个提交:

git diff F F^2

您将看到 Git 将尝试应用的更改。

如果你确实运行了这个git revert,你可能想要添加--edit,以便在 Git 能够自行应用这些更改的情况下编辑提交消息。这是因为在这种情况下,恢复的默认消息特别糟糕:Git 只会声称新的提交会恢复提交F,而实际上,您正在做的是恢复沿途丢失的代码。


推荐阅读