合并之间的git rebase导致完全不相关的文件中的冲突

时间:2015-10-14 17:40:41

标签: git git-rebase

我有一个很大的Git存储库,几个月前就已经引入了一个bug 并且我想bisect它,通过在过去首先引入一个提交 存储库然后重放合并(将rebase添加到新的 commit),如下图所示。

据我所知,由于合并,Git似乎没有那么好用 期待,但我想更好地了解为什么会发生这种情况(如果有的话) 可以帮助它更好地工作的参数。)

  • patch中的任何提交都不会再次修改master中修改的文件

  • 我尝试使用rebase时有--preserve-merges,但都失败了 合并距离提交patch

  • 不远
  • 冲突中显示的差异毫无意义,例如:一些空白 一个文件,另一个不相关的行...是否有任何有用的信息 尝试从中提取,或者它只是垃圾而我不应该花费任何东西 时间试图理解它?

  • 是否有不同的参数/合并策略可以帮助推进 合并

注意:最后,我git apply; git bisect的组合确实有效,但我是 仍然对Git行为的替代解决方案或解释感兴趣。

  

Summary of my issues with git-rebase

1 个答案:

答案 0 :(得分:3)

基本问题很容易描述但很难解决。

你在master的尖端。那些提交图很好,但很难输入:-)所以让我们在这里使用一个非常简化的ASCII。 (这只是对问题的重述,简化并使用不同的标签。)

                D
              /   \
A - B ----- C       F - G   <-- master
              \   /
                E

这里,在提交B中引入了一个错误,因此存在于每个子提交中(CG)。要进行修复,我们要创建一个新的提交序列(我将使用小写字母而不是C'D'等)并将修复x安装为新的提交:

                d
              /   \
A - B - x - c       f - g   <-- [anonymous; will become master]
              \   /
                e

为了做到这一点,在这种情况下git(git rebase -p - 注意典型的 rebase 删除合并提交!)必须根据提交进行新的提交现有的提交。对于像new commit c这样的非合并,这不是太棘手:rebase获得C vs B的差异,然后将该补丁应用于附加到commit {{1 }}。也就是说,rebase在新的匿名分支上执行x。到目前为止没问题!现在rebase需要创建提交git cherry-pick master~3,这也不是问题,它只需要做d,它确实提供:

git cherry-pick master~2

使 d / A - B - x - c 变得有点棘手,因为它的父提交应该是e。原则上,rebase将c挂起,回到d,并c复制git cherry-pick master~1^2。 (我认为rebase脚本实际上执行了自己的E操作,因此它不需要倒回匿名分支,但这样做也一样,它只涉及一些内部毛羽。)这给了我们:< / p>

git commit-tree

这就是我们遇到问题的地方:rebase如何创建合并提交 d / A - B - x - c \ e ?它无法将提交f的树与F的树进行比较:这只是合并的一半。它无法将DF进行比较:这只是合并的另一半。所以它不能使用E,因为这需要选择原始合并的一面或另一面。

rebase使用的解决方案是运行git cherry-pick(或者更确切地说是git merge运行的内部位)。这样,git merge在新xd中继续引入的所有更改也会得到正确处理。

(这确实引入了一个完全不同的问题:如果e是一个“邪恶的合并”,即一个合并改变了父级中未改变的东西,合并的再生树F赢了“ t匹配f的树,因为git永远不会看到“邪恶合并”的变化。需要的是F的变体,可以将合并提交的树与其所有父项进行比较 - 作为组合差异排序,除了比git的标准组合差异更完整 - 并将差异应用于所有输入树。但是没有这样的章鱼樱桃选择[cherry-pick?],所以它不可用。)< / p>

无论如何,这种rebase使用merge,在这里你会看到同样的合并冲突,可能是在原始合并期间发生的。如果您只是以相同的方式再次解决它 - 例如使用git calamari-pick - 这将允许您继续。不幸的是,没有办法追溯开启git rerere(尽管我认为这样的事情很容易)。