62

最近我启用了 diff3,现在解决冲突要容易得多。

以前在某些情况下,我必须检查日志以了解人们为什么这样做和那样进行合并。但是使用 diff3 信息将全部显示在一个地方

<<<<<<< HEAD
THIS IS USEFUL
||||||| merged common ancestors
This is useful
=======
This is really useful
>>>>>>> c2392943.....

从中我们可以很容易地看到结果应该是“这真的很有用”

我想知道diff3是否有任何缺点?为什么它不是 git 的默认行为?

4

4 回答 4

66

对于其他读者(以及来自这篇文章):

git 有一个以diff3格式显示合并冲突的选项(默认情况下它只显示要合并的两个文件)。您可以像这样启用它:

git config --global merge.conflictstyle diff3

确实没有理由不启用 diff3 样式,因为您经常需要祖先来确定正确的合并是什么。

这是相当早(2008 年)引入的,我想它不是默认的,因为默认的 Unixdiff不会显示为 3-way diff。

使用Git 2.35,您还拥有zdiff3(" zealous diff3 ")。


该线程中所述,如果您想在不设置配置的情况下运行此命令,以便您可以轻松地在普通 diff 和 diff3 之间切换,这在一种特定情况下是可能的:

如果在索引中标记了冲突(即,您在冲突合并之后但在将路径标记为已解决之前所处的状态),您可以执行以下操作:

git checkout --conflict=diff3 <path...>

请注意,这实际上是将索引内容检出到工作树中,因此您可能对冲突的工作树副本所做的任何编辑都将被覆盖。


请注意,|||||| merged common ancestors它将随着 git 2.24(2019 年第四季度)的发展而发展

请参阅提交 b657047(2019 年 10 月 7 日)、提交 8e4ec33(2019 年 10 月 1 日)和提交 4615a8c提交 45ef16f提交 f3081da提交 5bf7e57提交 e95e481 提交a779fb8提交 8599ab4提交 7c0a6c8提交 c7fa、提交babab2687b ,提交 4d7101e ,提交 724dd76 ,提交 345480d ,提交 b4db8a2 ,提交 98a1d3d ,提交 9822175 ,提交 10f751c(2019 年 8 月 17 日),作者Elijah Newren ( newren)
(由Junio C Hamano 合并 -- gitster--提交 280bd44中,2019 年 10 月 15 日)

merge-recursive: 为 diff3 共同祖先提供更好的标签

签字人:以利亚·纽伦

提交 7ca56aa07619(“ merge-recursive:为祖先添加标签”,2010-03-20,Git v1.7.1-rc0 -- merge)中,为 ' ||||||' 行添加了一个标签,使其具有更多信息标题 ' |||||| merged common ancestors',声明:

使用信息量更大的标签会更好。
也许有一天有人会提供一个。

当递归开始时,这个选择的标签是完全合理的,即当有多个合并基础时。

(在这种情况下,我想不出更好的标签。)

但是当有唯一的合并基础或没有合并基础时,它实际上有点误导。

根据合并基数更改此设置:

>=2: "merged common ancestors"
  1:   <abbreviated commit hash>
  0:   "<empty tree>"

还添加了测试以检查我们是否为这三种情况中的每一种都获得了正确的祖先名称。


在 Git 2.25(2020 年第一季度)中,“ git apply --3way”学会了尊重merge.conflictStyle配置变量,就像合并一样。

参见Denton Liu ( )的提交 091489d提交 aa76ae4提交 9580620提交 b006968提交 fa87b81(2019 年 10 月 23 日) 。(由Junio C Hamano 合并 -- --eff313f 提交中,2019 年 11 月 10 日)Denton-L
gitster

apply: 尊重 --3way 中的 merge.conflictStyle

签字人:Denton Liu

以前,在进行 3 路合并时,该merge.conflictStyle选项不受尊重,并且merge始终使用 " " 样式,即使diff3指定了 " " 也是如此。

git_xmerge_config()在结束时调用,git_apply_config()以便读取 merge.conflictStyle 配置。

于 2014-12-11T07:57:22.827 回答
13

diff3应该是默认值。它不仅对解决冲突有用,而且使解决冲突成为可能。(仅)使用默认的合并冲突样式来正确解决冲突实际上是不可能的。我建议大家设置diff3他们的全局选项。

git config --global merge.conflictStyle diff3

为什么从字面上看是不可能的?foo1考虑一个在特定源文件位置添加函数的分支

def foo1():
    print("foo1")

foo2和另一个在同一位置添加功能的分支

def foo2():
    print("foo2")

如果我在另一个基础上重新设置基础,我会遇到冲突。默认的合并冲突样式将显示

++<<<<<<< HEAD
 +def foo1():
 +    print("foo1")
++=======
+ def foo2():
+     print("foo2")
++>>>>>>> Add foo2

冲突标记告诉我什么?他们告诉我我需要同时添加foo1foo2文件中,对吗?不幸的是没有!考虑一个已经存在的文件,foo1以及foo2两个分支,一个是 removes foo1,一个是 removes foo2。如果我在另一个基础上重新定位,结果是什么?默认的合并冲突样式将显示

++<<<<<<< HEAD
 +def foo1():
 +    print("foo1")
++=======
+ def foo2():
+     print("foo2")
++>>>>>>> Remove foo1

在默认的冲突风格下,删除两个函数的情况与添加两个函数的情况完全没有区别(除了提交消息的文本,它只能是一个提示)!因此,它不足以解决冲突。这可能解释了为什么解决冲突被视为一门黑暗的艺术。 diff3不仅使之成为可能,而且通常使之变得容易。

于 2020-09-04T10:47:17.900 回答
9

默认合并冲突样式的另一个竞争者:zdiff3从 Git 2.35(2022 年第一季度)开始:添加了“ Zealousdiff3 ”样式的合并冲突表示。

请参阅Elijah Newren ( ) 的提交 ddfc44a(2021 年 12 月 1 日。 请参阅Phillip Wood ( ) 的提交 4496526(2021 年 12 月 1 日(由Junio C Hamano 合并——提交 4ce498b中,2021 年 12 月 15 日)newren
phillipwood
gitster

xdiff:实现一个热心的 diff3,或“zdiff3”

基于补丁,作者:Uwe Kleine-König
合着者:Elijah Newren 署名
者:Phillip Wood
署名者:Elijah Newren

"zdiff3" 与普通相同,diff3只是它允许在冲突块的开始或结束时压缩历史两侧的公共线。
比如下面的diff3冲突:

1
2
3
4
<<<<<<
A
B
C
D
E
||||||
5
6
======
A
X
C
Y
E
>>>>>>
7
8
9

两侧有共同线' A'、' C'和' '。 如果使用,则会出现以下冲突:E
zdiff3

1
2
3
4
A
<<<<<<
B
C
D
||||||
5
6
======
X
C
Y
>>>>>>
E
7
8
9

请注意,公共线“ A”和“ E”已移出冲突。

与 'merge' 的双向冲突不同conflictStylezdiff3冲突不会被拆分为多个冲突区域,以允许在C冲突之外显示公共 ' ' 行,因为zdiff3也显示了基本版本,而基本版本不能被合理分割.

另请注意,删除两侧共有的行可能会使冲突区域内的剩余文本与冲突区域内的基本文本匹配(例如,如果冲突在冲突的右侧diff3有 ' ',则共同5 6 E' E' 行将被移到外面,而底部和右侧的剩余冲突文本将是 ' 5' 和 ' 6' 行)。
这有可能让用户感到惊讶并让他们认为不应该发生冲突,但肯定存在冲突并且应该继续存在。

于 2021-12-17T01:20:31.520 回答
2

为什么它不是 git 的默认行为?

我认为这不是默认设置,因为git mergetool无论如何都会在顶部显示 3 个面板:本地、基本(共同祖先)和远程 + 底部的第 4 个面板,其中包含您在问题中所写的内容。

因此,如果您打开diff3并使用mergetool,那么您会在中间顶部面板和 ||||||| 之间的部分中复制信息 和 ======== 在底部面板中。

于 2020-05-21T20:52:14.077 回答