git 合并之间的变基导致完全不相关的文件发生冲突
git rebase between merges results in conflicts in completely unrelated files
我有一个很大的 Git 存储库,其中几个月前引入了一个错误
我想 bisect
它,首先在过去引入一个提交
存储库,然后重放合并(对新的执行 rebase
提交),如下图所示。
我知道由于合并,Git 似乎没有那么好用
预期的,但我想更好地了解为什么会发生这种情况(如果有
可以帮助它更好地工作的参数)。
patch
中修改的文件永远不会被 master
中的任何提交再次修改
我尝试了 rebase
有和没有 --preserve-merges
,但都失败了
合并离提交不远 patch
冲突中显示的差异毫无意义,例如一些空白
一个文件,另一个不相关的行......有什么有用的信息吗?
尝试从中提取,还是只是垃圾,我不应该花任何钱
花时间去理解它?
是否有不同的 parameter/merge 策略可以帮助推进
合并?
注意:最后,我的 git apply; git bisect
组合确实奏效了,但我
仍然对 Git 行为的替代解决方案或解释感兴趣。
基本问题说起来简单,解决起来却很难。
您正处于 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
在这种情况下——注意 typical rebase removes 合并提交!)必须根据现有提交进行新提交。对于像新提交 c
这样的非合并,这并不太棘手:rebase 得到 C
与 B
的差异,然后将该补丁应用于附加到提交 [=20] 的源代码树=].也就是说,rebase 在新的匿名分支上执行 git cherry-pick master~3
。到目前为止没问题!现在 rebase 需要创建提交 d
,这也不是问题,它只需要做 git cherry-pick master~2
,它确实做到了,给出:
d
/
A - B - x - c
制作 e
有点棘手,因为它的父提交应该是 c
。原则上,rebase 离开 d
挂起,倒回 c
,并 git cherry-pick master~1^2
复制 E
。 (我认为 rebase 脚本实际上执行了它自己的 git commit-tree
操作,因此它不必倒回匿名分支,但这同样有效,它只是涉及一些内部毛羽。)这给了我们:
d
/
A - B - x - c
\
e
这是我们遇到问题的地方:变基将如何创建合并提交f
?它无法将提交 F
的树与 D
的树进行比较:这只是合并的一半。它也无法将 F
与 E
进行比较:这只是合并的另一半。所以它不能使用 git cherry-pick
因为这需要选择原始合并的一侧或另一侧。
变基使用的解决方案是 运行 git merge
(或者说 git merge
运行 的内部位)。这样,由 x
引入并继续通过新的 d
和 e
的任何更改也会得到正确处理。
(这确实引入了一个完全不同的问题:如果 F
是一个 "evil merge",即,一个合并改变了父代中没有改变的东西,合并的复制树 f
不会与 F
的树匹配,因为 git 永远不会看到 "evil merge" 的变化。需要的是 cherry-pick
的变体,它可以比较合并提交的将树与其所有父树进行比较——作为某种组合差异,除了比 git 的标准组合差异更完整——并将该差异应用于所有输入树。但是没有这样的八足动物樱桃选择 [git calamari-pick
?], 所以它只是不可用。)
无论如何,这种 rebase 使用合并,在这里您看到的合并冲突可能与原始合并期间发生的相同。如果您简单地以相同的方式再次解决它——例如使用 git rerere
——那将允许您继续。不幸的是,没有办法追溯打开git rerere
(尽管我认为写这样的东西很容易)。
我有一个很大的 Git 存储库,其中几个月前引入了一个错误
我想 bisect
它,首先在过去引入一个提交
存储库,然后重放合并(对新的执行 rebase
提交),如下图所示。
我知道由于合并,Git 似乎没有那么好用 预期的,但我想更好地了解为什么会发生这种情况(如果有 可以帮助它更好地工作的参数)。
patch
中修改的文件永远不会被master
中的任何提交再次修改
我尝试了
rebase
有和没有--preserve-merges
,但都失败了 合并离提交不远patch
冲突中显示的差异毫无意义,例如一些空白 一个文件,另一个不相关的行......有什么有用的信息吗? 尝试从中提取,还是只是垃圾,我不应该花任何钱 花时间去理解它?
是否有不同的 parameter/merge 策略可以帮助推进 合并?
注意:最后,我的 git apply; git bisect
组合确实奏效了,但我
仍然对 Git 行为的替代解决方案或解释感兴趣。
基本问题说起来简单,解决起来却很难。
您正处于 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
在这种情况下——注意 typical rebase removes 合并提交!)必须根据现有提交进行新提交。对于像新提交 c
这样的非合并,这并不太棘手:rebase 得到 C
与 B
的差异,然后将该补丁应用于附加到提交 [=20] 的源代码树=].也就是说,rebase 在新的匿名分支上执行 git cherry-pick master~3
。到目前为止没问题!现在 rebase 需要创建提交 d
,这也不是问题,它只需要做 git cherry-pick master~2
,它确实做到了,给出:
d
/
A - B - x - c
制作 e
有点棘手,因为它的父提交应该是 c
。原则上,rebase 离开 d
挂起,倒回 c
,并 git cherry-pick master~1^2
复制 E
。 (我认为 rebase 脚本实际上执行了它自己的 git commit-tree
操作,因此它不必倒回匿名分支,但这同样有效,它只是涉及一些内部毛羽。)这给了我们:
d
/
A - B - x - c
\
e
这是我们遇到问题的地方:变基将如何创建合并提交f
?它无法将提交 F
的树与 D
的树进行比较:这只是合并的一半。它也无法将 F
与 E
进行比较:这只是合并的另一半。所以它不能使用 git cherry-pick
因为这需要选择原始合并的一侧或另一侧。
变基使用的解决方案是 运行 git merge
(或者说 git merge
运行 的内部位)。这样,由 x
引入并继续通过新的 d
和 e
的任何更改也会得到正确处理。
(这确实引入了一个完全不同的问题:如果 F
是一个 "evil merge",即,一个合并改变了父代中没有改变的东西,合并的复制树 f
不会与 F
的树匹配,因为 git 永远不会看到 "evil merge" 的变化。需要的是 cherry-pick
的变体,它可以比较合并提交的将树与其所有父树进行比较——作为某种组合差异,除了比 git 的标准组合差异更完整——并将该差异应用于所有输入树。但是没有这样的八足动物樱桃选择 [git calamari-pick
?], 所以它只是不可用。)
无论如何,这种 rebase 使用合并,在这里您看到的合并冲突可能与原始合并期间发生的相同。如果您简单地以相同的方式再次解决它——例如使用 git rerere
——那将允许您继续。不幸的是,没有办法追溯打开git rerere
(尽管我认为写这样的东西很容易)。