假设我有两个分支,A
和B
。以下属性是否成立?
- 将
A
合并到B
中会冲突,当且仅当将B
合并到A
中会冲突。 - 在将
A
合并到B
之后,我的文件内容与将B
合并到A
之后的文件内容相同。
cmaster的答案是正确的,但有一些限制条件。让我们先注意以下这些条款/假设:
--ours
)和右侧/远程(--theirs
)的L和R。第一个假设不一定成立。如果有多个合并基础候选项,则由合并策略来处理此问题。两种标准的两头合并策略是recursive
和resolve
。 resolve
策略只是随机选择其中一个。recursive
策略每次合并两个合并基础,然后使用生成的提交作为合并基础。由resolve
选择的可以受到传递给git merge-base
和git merge
参数顺序的影响,因此这里有一个限制条件。因为递归策略可以执行多个合并,所以这里有第二个限制条件,但仅适用于存在超过两个合并基础的情况。
git merge
会告诉你必须先提交,所以通常这不是问题。-s ours
合并策略完全忽略所有其他提交,因此合并顺序显然非常重要:结果始终是L。(我相当确定-s ours
甚至不会费心计算合并基础B。)-s ours
一样。git diff --find-renames B L
git diff --find-renames B R
这里的重命名检测是独立的——我的意思是它们互不影响;但两者都使用相同的规则。主要问题在于,在B中可能检测到同一文件在两个更改集中被重命名,在这种情况下,我们就会得到我所说的高级冲突,具体来说是重命名/重命名冲突。(我们还可以在重命名/删除和其他几种情况下得到高级冲突。)对于重命名/重命名冲突,Git选择的最终名称是L中的名称,而不是R中的名称。因此,在最终文件名方面,顺序很重要。但这不会影响工作树合并的内容。
因此,现在Git提取三个内容并执行合并。这是逐行进行的(当多个相邻行发生更改时,将它们分组在一起):
如果左右两侧只改动了不同的源代码行,Git将会接受这两个更改。这显然是对称的。
如果左右两侧同时改动了相同的源代码行,Git将会检查这两个更改是否相同。如果相同,Git将会接受一个更改。这也是对称的。
如果左右两侧改动了相同的代码行,但是做出了不同的更改,Git将会宣布合并冲突。工作区内容将取决于更改的顺序,因为工作区内容有<<<<<<< HEAD ... ||||||| base ... ======= ... other >>>>>>>
标记(如果选择了diff3
样式,则会出现base
部分)。
“相同的代码行”的定义有点棘手。这取决于差异算法(您可以选择),因为某些文件的某些部分可能会重复。但是,Git始终使用单个算法计算L和R,因此这里的顺序不重要。
您可以使用-X ours
或-X theirs
来覆盖合并冲突的投诉。这些指令让Git分别在L或R更改方面解决冲突。
即使考虑到上述警告,这个对称原则在单个合并中也是可行的。但是,一旦您进行了合并,下一个要运行的合并将使用修改后的提交图来计算新的合并基础。如果您有两个要执行的合并,并且按以下方式执行它们:
git merge one (and fix conflicts and commit if needed)
git merge two (fix conflicts and commit if needed)
即使每次合并都是对称的,也不意味着你一定会得到与运行以下命令相同的结果:
git merge two
git merge one
-s recursive 在处理多个合并基础时具有潜在的顺序差异的原因。假设有三个合并基础,Git将合并前两个(无论它们以何种顺序从合并基础计算中弹出),提交结果(即使存在合并冲突,在这种情况下只需提交冲突),然后将该提交与第三个提交合并并提交结果。这里的最终提交然后是输入{{B}}。只有当此过程的所有部分都对称时,最终的{{B}}结果才是无序的。大多数合并都是对称的,但我们在上面看到了所有的警告。
git merge
的bug。git
构建的根本目的。这就是git
从一开始就使用3路合并的原因:这是提供正确合并结果的唯一方法。这种3路合并在数学上是对称的,它基本上基于一个基础提交B
,计算出状态R = (A - B) + (C - B) + B
,而A
和C
则来自于不同的状态。只有合并顺序的区别才会影响合并提交的父项顺序。(C - B)
后跟(A - B)
应用于B
会产生与以相反顺序执行相同的结果。由于Git没有补丁的正式理论,声称所有合并都是对称的,并且其他任何情况都是错误的,应该有文件支持。 - user4815162342将A视为主分支,B视为子分支。
由于您无法在子分支B中看到readme.txt文件中的文本“更改3”,也不会将文本“更改4”附加到readme.txt文件中。相反,您正在覆盖readme.txt,即通过将具有“更改3”的文本readme.txt的内容与文本“更改4”合并。
从上面的例子可以看出,这两个属性都是好的。