这些Git合并标记的简单解释是什么?

时间:2019-05-15 13:44:03

标签: git git-merge

参考代码段1、2和3解释以下Git合并标记的含义。

/* Code from beginning of file */

<<<<<<< HEAD
      /* code segment 1 */
||||||| merged common ancestors
      /* code segment 2 */
=======
      /* code segment 3 */
>>>>>>> master

/* code to end of file */

该问题旨在引起一个简单的解释,而不涉及其他问题中发现的令人费解的因素。

2 个答案:

答案 0 :(得分:0)

这些人字形标记(<<<<<<<等)是冲突标记。包含|||||||标记的特定集合来自diff3冲突样式。默认的merge冲突样式省略了中间部分。

第一部分<<<<<<<|||||||中的部分来自当前提交。第二部分|||||||=======的部分来自合并基础(我们将在稍后定义)。第三部分=======>>>>>>>的部分来自 other 提交。

更长,但更有用

要了解这些含义,请记住,任何git merge操作都没有两个输入,而是三个输入。三个输入之一是您当前的结帐,也就是HEAD@提交。通常,这是您已签出的分支中的最新提交。第二个输入基于您运行的git merge命令。 1 例如,如果您运行了:

git merge theirbranch

然后第二个输入是在分支theirbranch的顶端的提交;如果您运行了:

git merge origin/master

然后第二个输入是您的origin/master指向的提交。无论哪种方式,这两个都是提交-快照充满了文件,其中HEAD提交中的文件与提交中的文件相同或不同。不过,您的文件与其文件之间的区别并不直接相关:关键提交是 third 提交,称为 merge base

Git自动为您找到合并基础提交。实际上,合并基数是最佳共享提交,它位于其他两个之前。请记住,合并的目标是合并工作,为此,Git需要找出您所做的更改他们所做的更改。但是每个提交都是一个快照,而不是一组更改—因此,Git必须从您的提交及其提交中向后进行工作,以查找开始时你们俩都共享的提交。这就是合并的基础。

找到合并基础后,Git现在执行两个差异。一个将合并基础与您当前的提交进行比较:这就是所做的更改。第二个差异将合并基础与提交进行比较:这就是他们的更改。然后,Git结合了两组更改。合并的更改将应用​​于合并基础,以给出最终的合并结果。

当您更改文件而他们根本不触摸文件时,将您的更改与未进行任何更改组合在一起就意味着您所做的更改。将其应用于基本文件将生成您的文件。同样,当他们更改文件而您不更改文件时,将您的所有内容与更改组合在一起意味着结果就是更改,并将这些更改应用于基本文件将生成其文件。所以这些非常容易。

当您俩都更改了 same 文件时,困难的部分就会出现。现在,Git确实必须结合不同的更改。如果您的更改是对他们没有碰过的行的更改,而您的更改是对您没有碰过的行的更改,那么Git可以将它们结合起来:只需进行两项更改即可。如果您更改了某些行,并且他们使完全相同更改,那么Git也可以将其合并:只需更改的一个副本。 really 硬部分,会导致合并冲突,发生在您更改某些行,而它们以不同的方式更改了 same 行时。

在这种情况下,Git将冲突的更改写入文件的工作树副本中,并用这些冲突标记包围。冲突标记区域上方的部分已成功组合(或至少Git 认为具有),并且标记区域下方的部分也是如此。介于两者之间的部分是Git无法决定是在第一个细分市场中还是在最后一个细分市场中选择您的更改。仅当您选择diff3样式时,中间部分才是原始线条的样子。


1 请注意,如果您运行git pull到这一点,则git pull会为您运行git merge。因此,您可能没有直接运行git merge,但是您确实调用了git merge

cherry-pick和revert命令也使用Git合并机制。 git stash以及git applygit am的某些情况也是如此。因此,您也可以看到这些命令的合并冲突。但是,这些操作的合并基础的定义是不同的,因此,很难看清冲突的产生方式。

diff3与merge的另一个副作用

发生冲突时,如果选择了diff3样式,则Git必须向您显示基本版本-发生冲突的整个部分。但是,当您选择了merge样式时,Git可以省略基本版本,而仅显示--ours--theirs版本。这意味着,如果它可以部分部分合并有冲突的区域,那么它可以这样做,只留下 uncombined 由标记包围的区域。例如:

<<<<<<< HEAD
please fix a spelling error
and ok, I changed this
||||||| merged common ancestors
please fix a speeling error
and change this
=======
please fix a spelling error
and change this to something different
>>>>>>> theirs

在这里,我们和他们用相同的方式解决了拼写错误 (将speeling替换为spelling),但我们不同地更改了第二行 。使用diff3样式,您将看到基本版本和两个端点版本。

如果我们选择merge样式,Git会发现我们和他们以相同的方式解决了拼写错误,而是看到了:

please fix a spelling error
<<<<<<< HEAD
and ok, I changed this
=======
and change this to something different
>>>>>>> theirs

通常,这很好,但是有时它意味着您根本无法告诉 最初的基础是什么,因为冲突是什么与什么都不是 ,即我们一个人或他们更改时,一行删除。我发现diff3样式通常更容易阅读,但是merge样式是默认样式。

答案 1 :(得分:0)

我正在寻找的初学者级答案是这样的:

段1是您当前签出的分支中存在的代码-位于<< HEAD,<<<<<-当前与段3冲突的“ HEAD”位置。

第3段是您要与之合并的另一个分支中的代码->>>>>>>指出的“ master”分支-与第1段冲突。

段2是两个合并分支的共同祖先中存在的代码。 Git会显示它,以帮助您更轻松地决定如何解决段1和段3之间的合并。

有几种方法可以决定解决段1和段3之间的合并冲突。

  1. 删除段1并保留段3;

  2. 删除第3段并保留第1段;

  3. 手动合并分段1和3,以同时包含两者中的更改。

  4. 从公共祖先返回到段2,丢弃 段1和3;

  5. 删除所有段并编写全新的代码

最终,您需要使用自己的判断来决定解决冲突的方法。只需确保在提交合并之前从代码中删除所有合并标记即可。