【问题标题】:Git Merge: parallel identical additions are merged without conflict by including the same code block TWICE in the merged file without complaint. Why?Git Merge:通过在合并文件中包含相同的代码块 TWICE 来合并并行相同的添加,而不会发生冲突。为什么?
【发布时间】:2014-03-30 01:17:26
【问题描述】:

我的 Git 日志中有一段有点棘手的历史,我正试图完全理解它。

在解释提交顺序之前,让我粘贴相关文件的 Git 日志图像(使用 SmartGit 可视化历史):

...

显示的是与我的问题相关的 Git 历史记录,不相关的中间部分被剪掉了。

两名开发人员对相关文件进行了代码更改,开发人员 1 和开发人员 2。

开发者 1

  • 签出图片中标记为“origin/staging”的分支(但在签出时也是“origin/development”)李>
  • 添加一个小代码块(见下文)
  • 提交并推送 - 此推送标记为“jon-dev-test-merge”,上面
  • 对上一次提交的代码进行简单的空白更改,并提交/推送此空白更改,上面标记为“jon-dev-test-merge-2
  • 意识到他应该在一个单独的分支上工作,所以重新开始并检查“origing/staging”(当时,'origin/development'),进入一个名为 'jons_dev' 的新分支,他将其推送到该分支,并在 origin 上设置跟踪
  • 将相同的小代码块(不包括空白更改)添加到这个新分支(蓝线)(在标记为“test-merge-sales”之前的某个时间提交)李>
  • 后来,看到 Developer 2 对 'origin/development' 分支进行了更改,将 'origin/development' 合并到他的 'jons_dev' 分支

同时...

开发者 2

  • 签出图片中标记为“origin/staging”的分支(但在签出时也是“origin/development”)李>
  • 对另一个文件进行代码更改(与上述开发人员 1 中的代码更改完全无关) - 这是在他的本地开发机器上的工作副本中
  • 将开发人员 1 对“origin/development”分支的代码更改拉到他的本地计算机并合并到一个仅限本地的分支/工作副本中;合并成功而没有冲突。请注意,我们没有看到开发人员 2 合并到他的本地分支(因为他没有将该分支推送到原点),但只有从他的本地分支合并(参见下一个项目符号点)回到原来的 '起源/发展'当时的分支。
  • 在他的本地机器上从原点合并到跟踪的开发分支,并将合并推回原点 - 上面标记为“vladimir-test-merge

到目前为止,一切都很好。

这是我的问题。

在了解上述事件顺序的过程中,我注意到了一些奇怪的事情 - 'origin/development' 分支对于有问题的文件没有任何变化需要被合并到标记为“origin/development”的合并中 - 结果证明,在这个文件中,对这个文件的相同更改,并行进行,不包括空格,因此是存在于两个文件中,因此只需要来自“jons_dev”分支的更改(这就是执行合并的方式)。

但是,我从合并中注意到了一些东西,涉及 Git 用于合并和确定冲突的方法,我无法解释。

为了以最简单的方式演示我的问题,我首先创建了屏幕截图中指示的测试分支 - 'test-merge-sales' 和 'jon-dev-测试合并'/'jon-dev-test-merge-2'。然后,我检查了分支“test-merge-sales”并在该分支中执行了两次单独的合并(取消了两个测试之间的合并)。

这两次合并的相关结果如下所示。 (附录:由于问题下方有cmets,第二个合并场景很容易解释。但是,FIRST合并场景仍然是一个问题。)


(0) 基础文件

在显示两个合并的 3 向屏幕截图之前,这里是文件相关部分的屏幕截图因为它存在于分支之前的“origin/staging”分支中分歧

基础文件:

该图显示了在任何一个开发者进行任何更改之前,该文件对于两个开发者的外观。

还存在 cmets,它们准确地解释了每个开发人员为了达到下面案例 (1) 中所示的合并前状态所做的代码更改。

从 cmets 中可以看出,开发人员 1 在文件中的给定位置添加了一个函数 - print_customer_part_order_history,然后是第二个函数 print_sales_analysis_page。同时,另一个分支添加了一个函数 - print_customer_part_order_history - 在文件中完全相同的位置。代码是相同的,包括空格。

这是文件进入合并案例 (1) 的状态,如下所示。


(1) 从 'jon-dev-test-merge' 合并到 'test-merge-sales' 分支

注意:这个合并场景是我的主要问题。由于问题下方的 cmets,与其他合并场景(下面的#2)相关的问题已经得到解答。

此合并没有导致冲突。打开合并文件的差异查看器,以下是相关(合并)行的屏幕截图:

(点此link to full-size image

请注意,Git 通过包含两个相同的函数(并行添加)'print_customer_part_order_history()'来合并文件 - 没有合并冲突。 (这是开发人员 1 并行添加到两个分支的代码 sn-p。)因此,该函数在合并代码中出现了两次。

注意:'test-merge-sales' 分支在两个分支的突出显示的代码块中都有相同的空格 - 前导空格。

问题 1:为什么 Git 决定不存在合并冲突?在文件中的同一位置并行添加了两个代码块。即使代码块相同,我认为这应该是合并冲突。


(2) 从 'jon-dev-test-merge-2' 合并到 'test-merge-sales' 分支

注意:由于此问题下方的 cmets,与此合并场景相关的问题已得到解答。

(点此link to full-size image

要合并的代码的唯一区别是 Developer 1 将前导空格更改为制表符。 但是,在这种情况下,只有空格不同,Git 已声明存在合并冲突

问题 2:为什么 - 只有空格不同 - Git 会决定在一种情况下没有合并冲突,而在另一种情况下, 会发生合并冲突?


上面确定了我的两个问题,关于 Git 如何处理合并和合并冲突。

谢谢!


附录 我在名为“(0) Base File”的部分中添加了一个额外的屏幕截图 - BEFORE 两个分支分歧的文件的相关文本以及描述性文本。谢谢!

【问题讨论】:

  • 短版:合并有效地运行两个git diffs:base-vs-head1,base-vs-head2。如果差异匹配(可能的行偏移更改),则合并是非冲突的。除非使用-w 完成差异,否则空格更改不匹配。合并允许-X ignore-space-change 和类似选项(请参阅文档)控制git diff 结果。
  • 至于“为什么”:git 不知道你的文件中有什么——也许空格对文件的语义很重要。 (例如,python。)
  • @torek - 谢谢。关于 diffs 匹配:我不明白为什么在上面显示的 #1 合并中,在两个分支上并行添加相同的代码块(包括空格)的差异会成功与代码块合并在合并文件中出现两次,而不是出现冲突。
  • 这是“三向”合并的正常、理想行为。给定一些转换(添加 A、删除 D 或从旧到新更改),如果 same 转换发生 base->head1 和 base->head2,则复制一份。如果只发生 一个 转换,则复制一份。如果发生了两个不同的转换,则声明冲突。 (请注意,此公式有一些可用的调整,这只是默认行为。)
  • @torek - 场景(来自您的评论)if the same transformation occurred base->head1 and base->head2, take one copy of it 似乎正是问题中“Merge #1”的预合并文件中发生的情况 - 但 Git Merge 采用了 两份。我不确定我错过了什么。

标签: git merge


【解决方案1】:

这很简单:在执行merge 时,git 分析两个大小都发生变化的行:

  • 如果更改之间的距离小于 2 行(即将提供参考),这将产生冲突,因为更改很可能是同一件事;
  • 如果更改超过 2 行,则双方的内容被视为两个不同的东西,添加的内容不分析,只是添加到结果文件中。

由于 LHS 在 line 79 上添加了该功能,而 RHS 在 line 69 上添加了该功能,因此 git 认为这是不同的内容,因为它相距不止几行。


以后如何避免这种情况?

  • 进入两个分支之间的diff,如果您仔细阅读差异然后在合并中对其进行编辑,这将是可见的;
  • 在您的团队内部进行更多沟通(如果可能),两个开发人员在两个单独的分支中编写完全相同函数是否正常?

来自git merge 文档(重点是我的)

如何呈现冲突

在合并期间,工作树文件会更新以反映 合并的结果。在对共同祖先的所做的更改中 版本,不重叠的(也就是说,您更改了 文件,而另一侧保持该区域完整,反之亦然)是 逐字纳入最终结果。当双方做出 更改到同一区域,但是,Git 不能随机选择一侧 在另一个方面,并要求您通过留下双方的内容来解决它 对那个地区做过。

【讨论】:

猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2016-04-07
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-12-08
  • 2012-10-22
  • 1970-01-01
相关资源
最近更新 更多