首页 > 解决方案 > Git合并策略什么是“解决”策略?

问题描述

git merge 的合并策略之一是resolve

这只能使用 3 路合并算法解决两个头(即当前分支和您从中拉出的另一个分支)。它试图仔细检测交叉合并歧义,并且通常被认为是安全和快速的。

这个策略似乎是基于 3-way 合并算法以及默认的递归,但与递归不同,它如何处理交叉合并情况尚不清楚。

解决交叉合并的算法是什么?

标签: gitgit-merge

解决方案


首先,让我们注意什么是“交叉合并”。在 Git 中,分支名称只是标识属于该分支的最后一个(或tip)提交。属于分支的其余提交由提交的父级、其父级的父级(祖父级)、下一步的父级(曾祖父级)等确定:

... <-F <-G <-H   <--branch

这里的分支名称branch标识了一个提交,其真正的哈希 ID 是大而丑陋的,但我们只称它为H。也就是说,Git 读取 name 的内容branch

$ git rev-parse branch
<some big ugly hash ID here>

Git 使用该哈希 IDH从存储库中读取提交。CommitH说它的父提交是另一个看起来很丑的随机散列 ID,但我们只称它为G,因此 Git 可以使用它H来查找G的散列 ID。Git 现在可以G从存储库中读取 -<code>H 的父级。提交G存储F的哈希 ID,以便 Git 可以读取F,等等。

当我们有两个具有一个最佳共同祖先的分支时,这往往看起来像这样:

          I--J   <-- branch1
         /
...--G--H
         \
          K--L   <-- branch2

通过从 at 开始J并向后工作,Git 枚举提交J,然后I,然后H,然后G,等等。通过从 at 开始L并向后工作,Git 枚举L, then K, then H, thenG等等。

提交H和更早在两个分支上。CommitH是最后一次这样的提交,所以它是合并基础。两者都-s resolve-s recursive因此选择提交H作为合并基础。(然后合并将进行一个新的提交M其父级将是 。)J L

但并非所有图表都那么好。特别是,我们可以进行以下一系列提交:

...--G--H---K--L   <-- branch1
         \ /
          x
         / \
...--I--J---M--N   <-- branch2

为了确定将哪个提交用作合并基础,Git 从以下位置开始L并返回:LKH-and- JG-and- I。也就是说,Git 遵循merge commit 的两个父母K。同时,Git 从 , 开始N并向后工作:N, M,然后H-and- J,依此类推。

显然H-and-JG-and-更好I,但没有简单的方法可以打破HJ作为“最佳”共同祖先之间的联系。这就是递归和解析不同的地方。

递归策略选择两个提交作为合并基础。为了实现这一点,它调用了一个内部的,inner git mergeon commitsHJ. 此合并操作找到 and 的合并基础HJ并将它们合并以进行临时提交,该提交位于 is 的正确位置x。这个新的但临时的提交现在是外部合并的合并基础。

解决策略是您在主题行中询问的策略。H显然,它会随机选择其中之一J。您得到哪一个取决于所使用的算法,该算法未指定,并且可能会从一个 Git 版本更改为另一个。

解决交叉合并的算法是什么?

-s recursive就是默认的策略。如上所述,它通过合并合并基础来处理它们。

您可以运行git merge-base --all branch1 branch2(使用上面的示例),您将看到两个合并库的两个哈希 ID。在某些情况下(很难绘制或就此而言难以实现),可能存在三个或更多合并基础。(这里没有理论上的上限。)每个合并碱基对也可能有多个合并碱基。递归策略通过重复合并合并基础来处理所有这些情况,直到最终留下一个最佳(但临时)提交。

当递归合并进行递归合并时,内部合并期间发生的冲突被悄悄地提交(带有冲突标记)到用于合并的最终合并基础中。结果很混乱


推荐阅读