1 <- 2 <- 5 (merge commit) <- master <- HEAD
\ /
3 <-- 4 <- dev
- 在合并过程中,双向合并是否仅使用提交“2”和“4”?如果我是正确的,那么什么情况下会使用双向合并?
- 什么是双向差异?
- 什么是三向差异?
1 <- 2 <- 5 (merge commit) <- master <- HEAD
\ /
3 <-- 4 <- dev
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 -3
和git cherry-pick <child>
的主要区别在于前者在回退“三方补丁”操作期间无法检测重命名,并且如果能够在不进行三方合并的情况下应用补丁,则甚至不会尝试对任何一个文件进行三方合并。我认为很难(但不是不可能)构造出人工示例,使得它们产生非常不同的结果,但我现在没有时间这样做。
1由于“当前版本”不一定是HEAD版本,因此情况会变得有点复杂。具体来说,git apply
使用工作树版本作为--ours
变量,而git apply --index
则使用索引版本作为--ours
变量。然而,git cherry-pick
命令默认要求索引和工作树处于“干净”状态,即与HEAD
提交匹配。在这种情况下,“HEAD版本”、“索引版本”和“工作树版本”通常没有区别。
git diff --full-index ... | git apply -3
本质上就是非交互式git rebase
所做的事情(除了它使用git format-patch
和git am
而不是git diff
和重复的git apply
)。只有在缩短的索引不明确时才需要完整的索引。Git 版本 1.7.10 中有一个修复程序,使git diff
生成对于当前存储库来说是无歧义的哈希值,但如果存储库中存储更多对象,则它们可能变得模糊不清。此外,如果您被困在 Git 1.7 或 1.7.1(例如 CentOS)中,则git diff | ...
可能无法提供足够长的索引哈希。 - torekgit apply -3
中,实际上是-3
将git apply
转换成三方合并。在大多数情况下,您不需要使用--full-index
,因为现代 Git 会在“index”行中生成足够长的缩写。但是,如果你要编写一些脚本,使用--full-index
是一个好习惯。例如,git-rebase--am.sh
脚本就是这样做的。 - torek