git - PR 期间的 Git 合并冲突
问题描述
我做了一些不寻常的设置,首先设置存储库,而不是master
用项目文件填充分支,而是transfer
创建并填充了一个分支。然后,文件通过 PR 被拉入development
,然后再次master
通过另一个 PR 被拉入。
而且,未来,主题分支是在分支之外创建的development
。完成后,为 --> 创建了 PR,为-- topic
>创建了development
另一个 PR 。但是,我不断遇到第二个 PR 的合并冲突-->例如在 Azure DevOps 上的两个中添加、在两个中编辑等。development
master
development
master
目前,只有 squash 合并用于完成 PR 到development
和master
.
我想知道的是,我看到的这些合并冲突是否是由于存储库的原始设置或壁球合并而发生的。diff
PR for development
and也包含很多我没想到的master
变化。
我无法理解它。
解决方案
只是为了建立在 knittl 的现有答案的基础上,这里有一个场景,您可以在自己舒适的家中制定一个场景,以展示所谓的“壁球合并”是多么容易导致冲突。
我们首先创建文件master
并提交它:
$ git init
$ echo "a" >> a.txt
$ git add .
$ git commit -m'start'
现在我们创建develop
并修改该文件:
$ git branch develop
$ git checkout develop
$ echo "b" > a.txt
$ git add .
$ git commit -m'changed a to b'
我们返回master
并进行“壁球合并”,它似乎工作正常:
$ git checkout master
$ git merge --squash develop
$ git commit -m'a squash commit from develop'
到目前为止,一切都很好。现在我们犯了一个可怕的错误:我们再做一次。我们切换到develop
该文件并对其进行更多修改:
$ git checkout develop
$ echo "c" > a.txt
$ git add .
$ git commit -m'changed b to c'
然后我们再次返回master
并进行“壁球合并” :
$ git checkout master
$ git merge --squash develop
Aaaaaand 我们发生冲突。游戏结束。
发生了什么?好吧,问题在于“壁球合并”不是合并。这是一种自我造成的补丁。它构造索引(暂存区)的配置,然后您提交它。在我上面的法令中,我们将其作为一个单独的步骤提交;使用 GitHub,它会为您服务。但关键是那个提交,虽然它包含从真正的合并中产生的更改,但它不是一个合并提交:它只是一个正常的提交,就好像你自己完成了这些更改,直接在master
.
那么,从真正的合并中产生的变化意味着什么?要回答这个问题,您必须知道合并是如何工作的:
合并从计算合并分支分歧的共同点开始:合并基础。
然后它计算两个差异:从合并基础到第一个分支的末尾,以及从合并基础到第二个分支的末尾。
最后,它在合并基础上制定两个差异。
好的,所以自己尝试一下,使用思想实验。
对于我上面场景中的第一个“壁球合并”,合并基础是“start”,其中a.txt是“a”。所以:
在 上
master
,它仍然是“a”,因此没有要制定的差异。On
develop
,它是 "b",所以差异是change-"a"-to-"b"。
因此,要形成“squash merge”提交,我们只需将“a”更改为“b”。
很好,让我们继续我的场景中的第二个“壁球合并”。事情是这样的:合并基础仍然是 "start",其中a.txt仍然是"a"。所以:
在 上
master
,差异是change-"a"-to-"b"。(请注意,
master
它不“知道”这是由于任何类型的合并而发生的;它认为此更改是由直接在 . 上工作的人独立执行的master
。)在 上
develop
,差异是change-"a"-to-"c"。
但你不能两者都做;那是冲突!
所以你看,重用之前 squash-merged 的分支之所以麻烦,是因为合并基础没有移动(历史上没有任何内容涉及任何合并);因此,每个连续的壁球合并都是与同一分支的早期“壁球合并”的潜在冲突。