Sam*_*art 3 git git-merge merge-conflict-resolution git-merge-conflict
我试图了解在 git 合并后可能发生 git 冲突的情况以及如何避免它们。
我创建了一个 git 存储库并向其中添加了一个文本文件。
在此之后,我做了以下工作:
tor*_*rek 12
合并冲突发生在合并期间,而不是之后。
冲突部分真的很简单:在文件F 中发生冲突时:
HEAD提交的差异——对文件F 进行了更改,并且要理解这一点,您需要:
git diff;和的输出git diff是非常简单的,真的,但它需要记住的是,每一个提交持有快照的所有文件中。这意味着我们必须提供git diff 两个快照:旧的和新的。这是文件在两个时间点的样子的两张“图片”。然后 Git 玩了一个Spot the Difference游戏:它告诉你要从左侧快照转到右侧快照,你必须对一些文件集进行一些更改。这些更改可能涉及重命名某些文件;它们可能涉及添加新文件;它们可能涉及删除文件;它们可能涉及从某些文件中删除某些特定行,并在某些特定位置将某些行添加到某些文件中。
的输出git diff不一定是任何人所做的任何事情。这只是一组更改,如果应用于左侧快照,则会为您提供右侧快照。此处的“左侧”是左参数,此处git diff的“右侧”是右参数,当您使用时:
git diff <hash1> <hash2>
Run Code Online (Sandbox Code Playgroud)
其中两个哈希是提交的哈希 ID。(git merge实际上,这就是这样做的,尽管它在内部完成所有这些。)差异引擎旨在产生产生正确效果的最小更改集。事实证明,这通常是某人实际所做的……但并非总是如此;因此,它通常是正确的,但并非总是如此。
最后,但可能是最棘手的,理解的部分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
Run Code Online (Sandbox Code Playgroud)
在这里,当合并branch1和branch2- 这意味着提交J和L- 共同的起点显然是 commit 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
Run Code Online (Sandbox Code Playgroud)
Git 现在将结合这两个git diff命令产生的一组更改。它们重叠但不进行相同更改的地方就是您将遇到合并冲突的地方。
Git 会将合并的更改应用于H. 将您的更改应用于此快照会导致提交J;在 commit 中应用他们的更改L;应用组合的更改会导致组合。
如果没有冲突,Git 将能够自行组合更改。应用合并的更改后,Git 将自己提交结果,作为新的合并提交 M:
I--J
/ \
...--G--H M <-- branch1 (HEAD)
\ /
K--L <-- branch2
Run Code Online (Sandbox Code Playgroud)
这将是您的合并结果。
如果合并失败,Git 会在合并过程中停止。您现在的工作是完成合并(自己合并更改),然后告诉 Git 您已经完成合并提交。如果这太混乱了,你可以告诉 Git:完全中止合并,它会退出所有的合并尝试,让你回到 commit 状态J,就好像你根本不会运行一样git merge。
最后有点棘手的是:当你不通过Git的完成合并,自动或手动生成的合并提交记录两名家长。 也就是说,如果你看一下合并M上面,你会看到,它连接回都提交J 和 L。在许多合并中,我们会以不同的方式绘制它:
o--o <-- small-feature
/ \
...--o--B--o--D--o---o--o <-- mainline
\
o--o--o--o--o--o <-- big-feature
Run Code Online (Sandbox Code Playgroud)
在这里,小功能合并到主线中,大功能仍在进行中。小功能的合并基础是 commit D。大特性的合并基础将是 commit B。(其余的提交并不是很有趣。)不过,在某些情况下,我们会得到一个更复杂的图:
o--o---o <-- offshoot-feature
/ / \
o--o---o---o--o <-- medium-feature
/ \ /
...--o--o--o--o--o---o----o <-- mainline
Run Code Online (Sandbox Code Playgroud)
这个图并没有那么复杂,但是现在真的很难看到合并基础在哪里,因为所有从各种特征到主线和彼此的交叉合并。
Git会找到合并基础。您可以使用git merge-base --all. 你可以画图,也可以让 Git 用 来画git log --graph,然后试着用眼球来寻找合并基数。找到合并基础后,无论您如何操作,您都可以运行将运行的两个git diff命令git merge。这将告诉您冲突会在哪里。但通常,没有意义:只需运行git merge并找到冲突即可。
| 归档时间: |
|
| 查看次数: |
687 次 |
| 最近记录: |