什么是两路和三路的差异/合并?

4
1 <- 2 <- 5 (merge commit) <- master <- HEAD
 \       /
  3 <-- 4 <- dev
  1. 在合并过程中,双向合并是否仅使用提交“2”和“4”?如果我是正确的,那么什么情况下会使用双向合并?
  2. 什么是双向差异?
  3. 什么是三向差异?
1个回答

5
我认为没有人真正谈论“双向差异”; 它们只是“差异”。在实践中,我也没有看到“三路差异”这个短语的使用,但在版本控制中,它是从共同合并基础开始的一对差异的明显标签,并查看两个后续但不同的快照。 (您还可以查找“interdiff”。请参见如何获取这两个git提交之间的interdiff?https://linux.die.net/man/1/interdiff。)
术语“合并”具有多重含义,并且(例如,在与Git无关的情况下)在谈论K路归并排序时定义良好。然而,当涉及版本控制(比Git更普遍)时,短语“三路合并”非常具体,并且指的是从一个“合并基础”版本开始的合并,其中存在两个分歧。
利用版本控制系统定义的“三方合并”概念,有些人发明了一种反构词法,将应用单个差异的过程称为“双向合并”。在我看来,这不是一个好术语,因为实际上并没有真正的合并。只需称其为“应用差异”或“应用补丁”。
另请参见为什么三方合并优于双方合并?请注意,谈论四方甚至五方合并的评论并不适用于Git。
您可以使用git diff --full-index <commit1> <commit2> | git apply -3命令对单个文件进行三方合并,其中每个文件的合并基础版本都是从index行中单独选择的。但是,这与选择与<commit1>相关联的所有文件作为合并基础本质上是相同的。其工作原理是git diff在其输出中打印每个blob的哈希ID,如果git apply无法直接应用补丁,则Git将使用打印的blob ID查找原始文件,然后从该合并基础版本计算第二个差异到当前文件的版本。然后将两个差异输入合并机制。(另请参见git merge-file命令。)但请注意,<commit1>中每个文件中的blob哈希值严格由附加到<commit1>tree对象确定。因此,除了一个例外,这与说<commit1>关联的文件没有区别:如果Git有提交哈希ID或相应的树ID,则Git可以执行整个树的文件比较以寻找重命名操作,之后Git可以将合并基础文件路径PB与不同的路径PL(本地或--ours文件)相关联。
换句话说,git diff --full-index <parent> <child> | git apply -3git cherry-pick <child>的主要区别在于前者在回退“三方补丁”操作期间无法检测重命名,并且如果能够在不进行三方合并的情况下应用补丁,则甚至不会尝试对任何一个文件进行三方合并。我认为很难(但不是不可能)构造出人工示例,使得它们产生非常不同的结果,但我现在没有时间这样做。

1由于“当前版本”不一定是HEAD版本,因此情况会变得有点复杂。具体来说,git apply使用工作树版本作为--ours变量,而git apply --index则使用索引版本作为--ours变量。然而,git cherry-pick命令默认要求索引和工作树处于“干净”状态,即与HEAD提交匹配。在这种情况下,“HEAD版本”、“索引版本”和“工作树版本”通常没有区别。


首先,这是一个很好的答案。我需要更多时间来完全理解它,所以稍等一下;-)这种类型的答案给了我一个很好的作业。现在我已经学会了blob和tree,也正在从头开始学习diff,但我不明白为什么你要谈论“full-index”。从文档中可以看出,它只是打印完整的blob名称。为什么你要强调它的重要性,以及“--full-index <commit1> <commit2> | git apply -3”与三方合并之间的联系是什么? - Stav Alfi
首先,一些背景:git diff --full-index ... | git apply -3 本质上就是非交互式 git rebase 所做的事情(除了它使用 git format-patchgit am 而不是 git diff 和重复的 git apply)。只有在缩短的索引不明确时才需要完整的索引。Git 版本 1.7.10 中有一个修复程序,使 git diff 生成对于当前存储库来说是无歧义的哈希值,但如果存储库中存储更多对象,则它们可能变得模糊不清。此外,如果您被困在 Git 1.7 或 1.7.1(例如 CentOS)中,则 git diff | ... 可能无法提供足够长的索引哈希。 - torek
1
现在:在 git apply -3 中,实际上是 -3git apply 转换成三方合并。在大多数情况下,您不需要使用 --full-index,因为现代 Git 会在“index”行中生成足够长的缩写。但是,如果你要编写一些脚本,使用 --full-index 是一个好习惯。例如,git-rebase--am.sh 脚本就是这样做的。 - torek

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接