Git合并冲突的不同方案 [英] Different scenarios for git merge conflicts

查看:11
本文介绍了Git合并冲突的不同方案的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试了解GIT合并后可能发生GIT冲突的情况以及如何避免它们。

我已创建一个Git存储库并向其中添加了一个文本文件。

  • 我已将"%1"添加到文本文件并将其提交给Master。
  • 我已从master(分支2)创建了一个新分支,并在文本文件中追加了一行内容为"2"的新行。
  • 我已从master(分支3)创建了一个新分支,并在文本文件中追加了一行内容为"3"的新行。

之后,我做了以下工作:

  • 我已将分支2合并到master中。没有冲突,这是正确的,也是我预期的。
  • 我已将Master合并到Branch3。我有冲突,因为文本文件的第二行有不同的内容。我通过保留"%3"而不是"%2"修复了冲突。
  • 我想将分支3合并到master中。现在我的问题是:1.当我进行合并时,是否有可能发生冲突?若有,原因为何?如果没有,为什么?2.如果不应该有冲突,但我仍然有冲突,可能的原因是什么?

推荐答案

合并冲突发生在合并期间,而不是合并后的

冲突部分实际上非常简单:冲突发生文件F时间:

  • 我们的";更改-从合并基本提交到我们的HEAD提交-对文件F
  • 的更改
  • 他们的更改(从相同的合并基准提交到他们的TIP提交的不同)也对文件F进行了更改(&Q),
  • 我们的更改与其更改重叠(编辑:或相邻-请参阅备注),但不完全相同。

要了解这一点,您需要:

  1. 了解git diff的输出;和
  2. 了解什么是合并库

git diff的输出非常简单,但它需要记住,每个提交都保存所有文件的快照。这意味着我们必须给git diff两个快照:一个旧的,一个新的。这是文件在两个时间点上的两张图片。然后,Git玩了一个Spot the Difference的游戏:它告诉您,要从左侧快照转到右侧快照,您必须对某些文件集进行一些更改。这些更改可能涉及重命名某些文件;可能涉及添加新文件;可能涉及删除文件;可能涉及删除某些文件中的某些特定行,以及在某些特定位置向某些文件添加某些行。

git diff的输出不一定是任何人员所做的事情。这只是一组更改,如果应用于左侧快照,则会得到右侧快照。这里是git diff的左侧参数和右侧参数,当您使用:

时,这里是右侧参数
git diff <hash1> <hash2>

其中两个散列是提交的散列ID。(这实际上就是git merge所做的,尽管它在内部完成了所有这些工作。)Diff引擎旨在生成能够产生正确效果的最小更改集。事实证明,这通常是某人实际所做的事情...但并非总是如此;因此,通常是正确的,但也不总是正确的。

理解git merge的最后但可能是最棘手的部分是合并基础的概念。从技术上讲,合并基础是从一个有向无环图(DAG)中找到节点的最低公共祖先(LCA)的算法产生的(单个)提交。并非所有DAG节点对(或集)都有LCA:有些没有,有些有多个。但是,您的Git的提交图在这里只有一个LCA是很常见的,并且git merge有一些处理多个LCA的方法。(当没有LCA时,现代git merge拒绝默认运行,告诉您这两个分支有不相关的历史。旧的Git无论如何都会运行合并,您也可以让现代的Git执行合并;在本例中,Git使用不带文件的合成提交作为合并基础。)

这里重要的部分是对合并基础有一个概念性的感觉。对于某些图表来说,这很容易。例如,考虑Git提交图的情况,其中您的两个分支只是从散列ID为H的公共祖先提交中分叉:

          I--J   <-- branch1 (HEAD)
         /
...--G--H
         
          K--L   <-- branch2
这里,当合并branch1branch2时--这意味着提交JL--共同的起点是明确提交H。因此git merge将运行两个git diff命令,每个中的合并基数将为H

git diff --find-renames <hash-of-H> <hash-of-J>    # what we changed on branch1
git diff --find-renames <hash-of-H> <hash-of-L>    # what they changed on branch2

Git现在将合并这两个git diff命令产生的更改集。它们重叠但不使相同更改的地方就是合并冲突的地方。

Git将对H中的快照应用组合更改。将您的更改应用于此快照将导致提交J;应用其更改将导致提交L;应用组合的更改将导致组合。

如果没有冲突,Git将能够自己组合更改。应用合并更改后,Git将自己提交结果,作为新的合并提交M

          I--J
         /    
...--G--H      M   <-- branch1 (HEAD)
             /
          K--L   <-- branch2

这将是您的合并结果。

如果合并失败,Git会在合并过程中停止。您现在的任务是完成合并(自己合并更改),然后告诉Git您已经完成并完成合并提交。如果这太混乱了,您可以告诉Git:完全中止合并,它将退出所有合并尝试,并让您返回提交J,就像您根本不会运行git merge一样。

最后一个棘手的地方是:当您通过Git自动或手动完成合并时,结果合并提交记录两个父级。也就是说,如果您查看上面的合并M,您将看到它连接回提交JL。在许多合并中,我们的描述略有不同:

                o--o   <-- small-feature
               /    
...--o--B--o--D--o---o--o   <-- mainline
         
          o--o--o--o--o--o   <-- big-feature

在这里,小功能合并到主线中,大功能仍在进行中。小功能的合并基础是提交D。大功能的合并基础将是提交B。(其余的提交并不是很有趣。)但在某些情况下,我们会得到一个更纠结的图形:

                  o--o---o   <-- offshoot-feature
                 /      / 
                o--o---o---o--o   <-- medium-feature
               /     /
...--o--o--o--o--o---o----o   <-- mainline

这张图并不那么复杂,但现在很难看到合并基础在哪里,因为从各种功能到主线和彼此的所有交叉合并。

Git查找合并基础。您可以使用git merge-base --all自己查找合并基础。你可以画这个图表,或者让Git用git log --graph来画,然后试着用眼球找到合并基点。找到合并基础之后,无论您如何操作,都可以运行git merge将运行的两个git diff命令。这将告诉您冲突将在哪里。但通常情况下,这是没有意义的:只需运行git merge并找到冲突。

这篇关于Git合并冲突的不同方案的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆