我有一个很大的Git存储库,几个月前就已经引入了一个bug
并且我想bisect
它,通过在过去首先引入一个提交
存储库然后重放合并(将rebase
添加到新的
commit),如下图所示。
据我所知,由于合并,Git似乎没有那么好用 期待,但我想更好地了解为什么会发生这种情况(如果有的话) 可以帮助它更好地工作的参数。)
patch
中的任何提交都不会再次修改master
中修改的文件
我尝试使用rebase
时有--preserve-merges
,但都失败了
合并距离提交patch
冲突中显示的差异毫无意义,例如:一些空白 一个文件,另一个不相关的行...是否有任何有用的信息 尝试从中提取,或者它只是垃圾而我不应该花费任何东西 时间试图理解它?
是否有不同的参数/合并策略可以帮助推进 合并
注意:最后,我git apply; git bisect
的组合确实有效,但我是
仍然对Git行为的替代解决方案或解释感兴趣。
答案 0 :(得分:3)
基本问题很容易描述但很难解决。
你在master
的尖端。那些提交图很好,但很难输入:-)所以让我们在这里使用一个非常简化的ASCII。 (这只是对问题的重述,简化并使用不同的标签。)
D
/ \
A - B ----- C F - G <-- master
\ /
E
这里,在提交B
中引入了一个错误,因此存在于每个子提交中(C
到G
)。要进行修复,我们要创建一个新的提交序列(我将使用小写字母而不是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
的树进行比较:这只是合并的一半。它无法将D
与F
进行比较:这只是合并的另一半。所以它不能使用E
,因为这需要选择原始合并的一面或另一面。
rebase使用的解决方案是运行git cherry-pick
(或者更确切地说是git merge
运行的内部位)。这样,git merge
在新x
和d
中继续引入的所有更改也会得到正确处理。
(这确实引入了一个完全不同的问题:如果e
是一个“邪恶的合并”,即一个合并改变了父级中未改变的东西,合并的再生树F
赢了“ t匹配f
的树,因为git永远不会看到“邪恶合并”的变化。需要的是F
的变体,可以将合并提交的树与其所有父项进行比较 - 作为组合差异排序,除了比git的标准组合差异更完整 - 并将差异应用于所有输入树。但是没有这样的章鱼樱桃选择[cherry-pick
?],所以它不可用。)< / p>
无论如何,这种rebase使用merge,在这里你会看到同样的合并冲突,可能是在原始合并期间发生的。如果您只是以相同的方式再次解决它 - 例如使用git calamari-pick
- 这将允许您继续。不幸的是,没有办法追溯开启git rerere
(尽管我认为写这样的事情很容易)。