【问题标题】:when exactly does a git merge conflict arisegit合并冲突究竟是什么时候出现的
【发布时间】:2017-03-09 11:01:40
【问题描述】:

我正在使用 git 来跟踪我的 LaTeX 文档的更改。我倾向于将来自共同作者的反馈保存在一个单独的分支中,并在以后将其合并。到目前为止,事情似乎神奇地正确合并,但我想知道何时发生合并冲突,以便我可以在合并过程中获得一些真正的信任(我当然不希望文本变得时髦)。

StackOverflow 上有很多问题似乎都在问同样的问题,但没有一个答案非常具体。例如this answer 指定如果对同一区域进行更改会发生冲突,但这让我想知道这些区域到底是什么。只是对同一行进行了更改,还是考虑了某些上下文?

【问题讨论】:

  • 当两个提交以任何方式修改同一个文件的相同行时,这些提交属于不同的分支。当合并那个分支时,git 不知道该怎么做,所以你必须自己修复它
  • @kowsky 例如this answer指出发生冲突,你看到这部分问题了吗?

标签: git merge merge-conflict-resolution


【解决方案1】:

它是逐行的,答案是肯定的和否定的:上下文确实很重要,但重要的数量却很棘手。它比你最初想象的要多和少。

您可能想先浏览this answer 到一个相关问题,作为背景。我现在假设我们将base 作为(单个)合并基础(也许我们通过标记特定提交来设置名称base,例如git tag base $(git merge-base HEAD <em>other</em>))和HEAD 作为我们在分支b1 上的提交,以及其他一些分支名称 b2 命名其他提交。

接下来,我们看看这两个差异:

git diff base HEAD
git diff base b2

如果我们看到文件 F 的所有三个版本都不同(因此 F 出现在两个输出中,并且更改不同),那么我们必须工作,在本质,diff-hunk-by-diff-hunk。在 diff hunks 重叠但做出不同更改的地方,Git 会声明冲突。但是——这似乎是你的问题——“做出不同的改变”究竟是什么意思?

我认为这是最好的例子。例如:

$ git checkout b1
[checkout messages here - but I was already on b1]
$ git diff base HEAD
diff --git a/basefile b/basefile
index df781c1..e4f9e4b 100644
--- a/basefile
+++ b/basefile
@@ -4,6 +4,7 @@
 # Redistribution and use in source and binary forms, with or without
 # modification, are permitted provided that the following conditions
 # are met:
+# added line in b1
 # 1. Redistributions of source code must retain the above copyright
 #    notice, this list of conditions and the following disclaimer.
 # 2. Redistributions in binary form must reproduce the above copyright

和:

$ git diff base b2
diff --git a/basefile b/basefile
index df781c1..c96620e 100644
--- a/basefile
+++ b/basefile
@@ -4,7 +4,6 @@
 # Redistribution and use in source and binary forms, with or without
 # modification, are permitted provided that the following conditions
 # are met:
-# 1. Redistributions of source code must retain the above copyright
 #    notice, this list of conditions and the following disclaimer.
 # 2. Redistributions in binary form must reproduce the above copyright
 #    notice, this list of conditions and the following disclaimer in the

请注意,虽然这些更改不会触及 same 行,但从某种意义上说,它们也 确实 触及同一行。我添加了第 7 行(将旧第 7 行推到第 8 行),并删除了旧第 7 行。这些显然是“相同”行。所以:

$ git merge b2
Auto-merging basefile
CONFLICT (content): Merge conflict in basefile
Automatic merge failed; fix conflicts and then commit the result.

让我们中止此合并并考虑分支b3 的尖端(在我的设置中b1b3 的合并基础与b1b2 的合并基础相同)。

$ git merge --abort
$ git diff base b3
diff --git a/basefile b/basefile
index df781c1..e2b8567 100644
--- a/basefile
+++ b/basefile
@@ -5,7 +5,6 @@
 # modification, are permitted provided that the following conditions
 # are met:
 # 1. Redistributions of source code must retain the above copyright
-#    notice, this list of conditions and the following disclaimer.
 # 2. Redistributions in binary form must reproduce the above copyright
 #    notice, this list of conditions and the following disclaimer in the
 #    documentation and/or other materials provided with the distribution.
 $ git merge --no-edit b3
Auto-merging basefile
Merge made by the 'recursive' strategy.
 basefile | 1 -
 1 file changed, 1 deletion(-)

这一次没有冲突,尽管两个 diff hunks 触及了相同的一般区域。第二个差异删除了一个没有“接触”添加行的行,所以 Git 认为这是安全的。

如果您以同样的方式进行更多试验,您会确切地发现哪些看似重叠的更改被成功组合,哪些会导致冲突。显然,直接重叠的更改,例如,删除原始行 42 并插入不同的新行 42,将发生冲突。但是所有更改总是表示为“删除一些现有行,尽管可能为零”,然后是“添加一些新行,尽管可能为零”。 更改——即使是更改、添加或删除一行中的一个单词——删除非零数量的现有行并添加非零数量的新行。纯删除(一个或多个完整行)添加零行,纯插入删除零行。最后,归结为:“我们和他们的更改是否触及相同的行号?”上下文变得几乎无关紧要,除了在删除零行或插入零行时,上下文本身在某种意义上“就是”行。 (我不确定这种说法有多大意义,所以如果它难以理解,那是我的错。;-))

(还请记住,如果您在工作时修改“合并至今”文件,则在查看更改是否触及“相同”时,您必须使用 原始基本文件的行号行。由于“我们的”和“他们的”都有相同的基本版本,这是我们可以在这里使用的简单快捷方式。)

三路合并不是补丁

请注意,这与应用 patch 不同,后者是在没有通用基础版本的情况下完成的。在补丁的情况下,上下文被更多地使用:diff hunk 标头提供了搜索上下文的位置,但由于它可能应用于文件的不同版本,上下文允许我们(和 Git)只要上下文仍然匹配,在不同的行进行相同的更改。

patch 实用程序在这里使用了不同的算法(“最大模糊”因子,看起来 +/- 那么多行)。 Git 不做模糊因素;如果必须,它将一直搜索到文件的开头或结尾。但是,它确实具有在确定上下文不匹配之前调整空白的常用选项。

(当使用git apply 应用补丁时,您可以添加-3--3way 以允许Git 读取index 行,这些行提供文件blob 的部分或完整哈希ID。左侧哈希ID 是文件先前版本的哈希值:请注意,在上面的所有差异中,basefile 的“基本”版本的 ID 为 df781c1。如果 Git 可以从该 ID 中找到唯一的 blob,它可以假设那是合并基础,并且仅将一个合并基础与HEAD进行比较,将补丁本身视为其他 diff,并以这种方式进行三向合并。这有时允许@ 987654347@ 成功,patch 失败。)

【讨论】:

  • 感谢您非常详尽的回答。如果我理解正确,相邻行的更改通常会导致冲突。此外,事情纯粹是逐行评估的,因此测试一些临界案例不应该花费太多时间。您是否碰巧知道是否可以调整上下文以考虑相邻的两条线?再次感谢。
  • 在所有现有的合并策略和驱动中,没有这样的选项。你可以写你自己的策略,但是doing so is not simple;您可以编写自己的驱动程序,这更简单(参见相同的问题)但仍然不是很简单。
  • 这很有帮助,但我有点困惑,直到我发现 HEAD 指向 b1 并且 other 实际上是示例开头的 b2。对吗?
  • @clapas:是的;我可能应该在示例命令中的git merge b2 之前添加一个git checkout b1
猜你喜欢
  • 2014-09-11
  • 1970-01-01
  • 2019-11-01
  • 2018-01-29
  • 2011-08-19
  • 1970-01-01
  • 2021-11-13
  • 2018-05-23
  • 1970-01-01
相关资源
最近更新 更多