如何修复错误合并中的历史记录

Posted

技术标签:

【中文标题】如何修复错误合并中的历史记录【英文标题】:How to fix the history in a wrong merge 【发布时间】:2013-05-18 17:43:40 【问题描述】:

我在 Git 中有一个我无法解决的问题。我已经搜索了类似的案例,但我无法找到适合我的情况的好的解决方案。

我基本上有 2 个分支,master 和 bugfix。错误修复是在我们完成发布时从 master 派生的。每次我们在 bugfix 中修复某些内容并进行 bugfix 发布时,我们都需要将其合并到 master 中。 Master 包含新功能(当然不应该合并到错误修复中)。碰巧有人错误地将master与bugfix合并。

This is what happened:

 master: x1---x2
                \
 bugfix: y1--y2--M

where M is the merge between bugfix and master

对此的解决方案是恢复我使用“git revert -m 1 M”所做的合并(M 是来自合并的 SHA),如 here 所述。我进行了还原,因为我们已经在 bugfix 分支中进行了其他我们不想丢失的更改,这对于 bugfix 分支来说效果很好。

Current state:

 master: x1--x2------------x---x

 bugfix: y1--x1--y2--x2--M--y--y--R1

where R1 is the revert of M

当我们需要在 master 中合并 bugfix 分支时,问题会出现。如我发布的链接中所述,revert 修复了代码更改但不修复历史记录,这意味着当我在 master 中合并 bugfix 时,revert 将生效并从 master(x1 和 x2)中删除更改。我能做的是在我将它合并到master之前恢复bugfix中的revert。

Solution:

 master: x1--x2------------x---x--------M
                                       /
 bugfix: y1--x1--y2--x2--M--y--y--R1--R2

where R2 is the revert of R1

这可行,但不是最终解决方案,因为每次我们进行合并时,我们都需要执行“revert of the revert”。几天来,我一直在寻找永久解决方案,似乎唯一的选择是从错误修复分支的历史记录中删除主提交(x1 和 x2)。但是这里使用 x1 和 x2 只是作为示例,实际上我们有更多的提交,并且剖析 bugfix 分支的历史非常困难且容易出错。我确信 Git 可以帮助我做到这一点,但我不知道如何。

任何想法都会非常有帮助。

【问题讨论】:

您的历史在第一张和第二张照片中看起来不同。哪一个?在第一张图片中有适当的合并,在第二张图片中是快进。 我想表明错误修复中的历史现在与大师的历史混合在一起。 您展示了它在显示为线性(按时间顺序)历史时的外观,而不是它的样子 【参考方案1】:

我个人建议重写历史(见Useless 的答案)并告诉你的团队。但这需要每个人都具备一定程度的 git 知识。如果重写方法对您来说风险太大,这里有一个替代方案:

发生了什么

当你将A 合并到B 时,git 会将所有可以从A 访问但不是B 的提交/更改添加到B。你的回复就是其中之一。正如您所注意到的,如果不重写,您将无能为力。

解决办法

您必须将还原合并到主文件中。由于您希望将恢复的内容保留在 master 中,因此您还需要在 master 上撤消该恢复(=可从 master 访问)。实现这一目标的最佳方法是使用以下命令:

git checkout -b bugfix-revert bugfix
git revert R1
git checkout master
git merge bugfix-revert
git branch -d bugfix-revert

在这些命令之后,每个分支都将处于您想要的状态,并且您可以从现在开始再次合并错误修复。您的历史记录将如下所示:

 [master] x1---x2----------------------H
                 \                    /
 [bugfix-revert]  \                  M''
                   \                /
 [bugfix] y1--y2----M--y3--y4--M'--y5

如您所见,master 包含M',但其更改不在H 中,因为M'' 取消了这些。 M' 永远不会应用于master,因为它已经包含它。 bugfix 状态没有改变,也不必改变。

【讨论】:

我们最终选择了这个解决方案,它已经奏效了。感谢您的帮助!【参考方案2】:

为什么不首先创建一个没有错误合并的新错误修复分支?不过,您需要与每个人协调切换分支,以确保不会丢失任何提交

所以你有:

 [master] x1---x2
                 \
 [bugfix]  y1--y2--M--y3--y4--M'

(其中M'M 的回归)。但是,您可以创建一个新分支:

$ git branch bugfix-fix y4

 [master] x1---x2
                 \
 [bugfix]  y1--y2--M--y3--y4--M'
                          ^^
                     [bugfix-fix]

将它从有问题的合并和还原中分离出来

$ git rebase --onto y2 M bugfix-fix

 [master] x1---x2
                 \
 [bugfix]  y1--y2--M--y3--y4--M'
                 \
 [bugfix-fix]     y3'--y4'

然后,一旦您验证了您需要的所有内容都在 bugfix-fix 上,您就可以重命名两个分支

$ git branch -m bugfix bugfix-broken
$ git branch -m bugfix-fix bugfix

(您需要强行推动,只要您与可能检查过它的每个人协调,这是安全的)。

【讨论】:

协调部分比较难。如果你不小心,有人拉扯,你最终会陷入同样的​​境地,历史会更加混乱。 我不知道可以像这样使用变基。我们选择了其他解决方案,但我一定会记住您的。谢谢。【参考方案3】:

您的解决方案是正确的...您需要“还原还原”,然后与您的错误修复分支进行另一次合并(以提取在第一次错误合并后完成的任何错误修复提交),正如您所展示的.这将从您的 y1 和 y2 提交中恢复修复,保持您的历史正确并提取在第一个错误合并点之后执行的更新更改。

您不必担心未来的合并,因为最后一个合并点是历史上 git 尝试进行合并的地方,而不是之前的任何地方(与您需要执行“还原”的确切原因相同)的还原')...


不知道你为什么说这会使错误修复处于损坏状态。以下工作正常。您可以根据需要继续在错误修复分支上工作,而不必担心必须再恢复任何内容(除非您显然再次做同样的事情......)。如果您将来需要再次与 master 合并,您可以毫无问题(不需要做任何特别的事情),因为 git 知道历史,并且只会从两个分支最后共同的点查找合并问题/冲突(这最后一次合并)。

https://github.com/g19fanatic/***-16713251-496405


这是一个link,Linus 描述了这个问题,并提出了我上面提出的解决方案作为纠正它的一种可能方法......

【讨论】:

以上是关于如何修复错误合并中的历史记录的主要内容,如果未能解决你的问题,请参考以下文章

如何将记录与汇总的历史数据合并?

如何执行 git revert 并删除合并历史记录?

删除 git 历史记录中包含合并的特定提交

合并两个 Git 存储库而不破坏文件历史记录

sh 修复损坏的zsh历史记录

合并后的 Git 分支和提交历史记录