PRs期间的Git合并冲突
我在第一次设置存储库的地方做了一个不寻常的设置,没有用项目文件填充PRs期间的Git合并冲突,git,azure-devops,pull-request,Git,Azure Devops,Pull Request,我在第一次设置存储库的地方做了一个不寻常的设置,没有用项目文件填充master分支,而是创建并填充了transfer分支。然后,通过PR将文件拉入开发,然后通过另一个PR再次拉入主文件 接下来,主题分支将在developmentbranch下创建。完成后,将为主题创建PR-->开发,并为开发-->主控创建另一个PR。但是,在Azure DevOps上,我不断收到第二次PR开发的合并冲突-->主程序,例如在两个中添加的、在两个中编辑的等 现在,只使用挤压合并来完成development和maste
master
分支,而是创建并填充了transfer
分支。然后,通过PR将文件拉入开发
,然后通过另一个PR再次拉入主文件
接下来,主题分支将在development
branch下创建。完成后,将为主题创建PR
-->开发
,并为开发
-->主控
创建另一个PR。但是,在Azure DevOps上,我不断收到第二次PR开发的合并冲突-->主程序
,例如在两个中添加的、在两个中编辑的等
现在,只使用挤压合并来完成development
和master
中的PR
我想知道的是,我看到的这些合并冲突是由于存储库的原始设置还是挤压合并而发生的。用于development
和master
的PR的diff
也包含了很多我不期望的变化
我无法控制它。冲突的发生是因为您正在使用“挤压”合并并不断地重新整合一个分支。使用“挤压”时,您没有进行真正的合并(换句话说:历史没有连接)。而是在master
分支上创建一个新的提交
稍后,当您尝试将开发
合并到主控
时,所有先前的开发更改将再次合并(但它们已经存在于主控
中)。这就是为什么你会看到冲突
我看到两种选择:
- 对于重新集成分支,根本不要使用“挤压”,而是使用常规合并
- 每次合并后,从
master
重新创建development
在knittl现有的基础上,这里有一个场景,您可以在舒适的家中实施,以演示所谓的“挤压合并”是多么容易导致冲突
我们首先在master
上创建文件并提交:
$ git init
$ echo "a" >> a.txt
$ git add .
$ git commit -m'start'
现在,我们创建开发并修改该文件:
$ 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'
到目前为止还不错。现在我们犯了一个可怕的错误:我们又犯了一次。我们切换到开发
,并进一步修改该文件:
$ git checkout develop
$ echo "c" > a.txt
$ git add .
$ git commit -m'changed b to c'
然后我们返回到master
并再次执行“挤压合并”:
aaaaaaaaa我们会有冲突。比赛结束了
发生了什么事?问题是“挤压合并”不是合并。这是一种自我造成的补丁。它构造索引(暂存区域)的配置,然后您提交它。在我上面的法令中,我们将其作为一个单独的步骤;有了GitHub,它将为您服务。但关键是,尽管该提交包含了实际合并所产生的更改,但它并不是一个合并提交:它只是一个正常的提交,就像您自己直接在master
上完成了这些更改一样
那么,对真正的合并进行更改意味着什么呢?要回答这个问题,您必须知道合并是如何工作的:
合并首先计算合并分支发散的公共点:合并基
然后计算两个差异:从合并基础到第一个分支的末端,以及从合并基础到第二个分支的末端
最后,它在合并基础上执行这两个差异
好吧,你自己试试,用一个思维实验
对于上面场景中的第一个“挤压合并”,合并基数是“开始”,其中a.txt是“a”。因此:
- 在
master
上,它仍然是“a”,因此没有需要执行的差异
- 在
develope
上,它是“b”,因此差异是从“a”更改为“b”
因此,为了形成“挤压合并”提交,我们只需将“a”更改为“b”
很好,让我们继续我的场景中的第二个“挤压合并”。事情是这样的:合并基仍然是“start”,其中a.txt仍然是“a”。因此:
- 在
master
上,差异从“a”更改为“b”
(请注意,master
不“知道”这是由于任何类型的合并而发生的;它认为此更改是由直接在master
上工作的人独立执行的)
- 在
develope
上,差异是从“a”更改为“c”
但你不能两者兼而有之;这是一场冲突
因此,您可以看到,重用以前挤压合并的分支很麻烦的原因是合并基不移动(历史中没有任何合并);因此,每次连续的挤压合并都可能与同一分支的早期“挤压合并”发生冲突。现有的答案非常有助于解释为什么会发生这种情况。我想简单地量化一个简单的经验法则,以确定哪些合并类型可以用于哪些分支。Azure DevOps在完成PR时具有以下选项:
合并(无快进)
挤压提交
重基和快进
半线性合并
根据您的喜好,在完成从主题
到开发
的PR时,可以使用这些选项中的任何一个。但是development
和master
中的所有承诺都是神圣的,不应该改变。注意,选项2-4在源分支上所有可能的重写提交。因此,你应该:
仅在以下情况下完成PR时使用第一个选项合并
源代码分支是开发
或主代码
(以及Git Flow中的发布
或修补程序
)
Azure DevOps允许您将合并类型锁定到作为目标的分支中,但不幸的是我不这么认为
$ git checkout master
$ git merge --squash develop