解决合并请求的代码冲突
在多人团队使用代码托管服务时,可能出现两个人同时修改一个文件的情况,这时在推送(push)代码到代码托管仓库时就会出现代码提交冲突并推送失败,如下图就是因为本地仓库与远程仓库文件修改的冲突所产生的推送失败。
- 不同版本的Git、不同编译工具的Git插件所返回提示的内容不完全一致,但所表达的意思基本一致。
- 只要在返回提示的内容中解读出,推送失败、另一个仓库成员,两个信息,一般即为产生了提交冲突。
- Git在文件合并时是比较智能的,对于同一个文件不同位置的修改内容会自动合并,只有在同一个文件同一个位置被同时修改时(本地仓与远程仓的当前版本有差异),才会产生冲突。
- 在分支合并时,有时也会产生冲突,这时的判定方式与解决办法与提交远程仓库时的冲突基本一样,如下图是本地分支branch1向master分支合并时产生了冲突(file01文件的修改冲突了)。
- 可解决合并请求的文件冲突数量不得超过50个,且单文件冲突内容的大小不得超过200KB。
如何解决代码提交冲突?
当代码提交冲突产生时,您可以将远程代码仓库拉取(pull)到本地仓库的工作区,这时Git会将可以合并的修改内容进行合并,并将不能合并的文件内容进行提示,开发者只需要对提示的冲突内容进行修改即可再次推送到远程仓库(add → commit → push),这时冲突就解决完毕了。
如下图所示,在做拉取(pull)操作时,Git提示您,一个文件合并时产生了冲突。
在修改冲突文件时应该考虑清楚,必要时要与冲突方联系协商解决,避免覆盖他人代码。
git pull可以理解为 git fetch 的操作 + git merge的操作,其详细说明如下:
git fetch origin master #从远程主机的master分支拉取最新内容 git merge FETCH_HEAD #将拉取下来的最新内容合并到当前所在的分支中
在merge的时候,会将有冲突不能合并的内容做出提示。
示例:冲突的产生与解决
下面模拟一个情景来帮助理解冲突的产生和解决的过程,情景如下。
某公司的一个项目使用代码托管服务和Git工具来管理,这个项目有一个功能(假设此功能涉及的修改文件是file01)由开发者1号(以下用01_dev表示)和开发者2号(以下用02_dev表示)共同开发,项目上线前一周,大家都在修改代码,产生了如下情况。
- file01存储在远程仓库,此时文件内容如下。
- 01_dev在本地仓库修改了文件file01的第二行等内容,并已经成功推送到了远程仓库,此时01_dev的本地仓库和远程仓库的文件内容如下。
- 此时02_dev也在本地仓库修改了文件file01的第二行等内容,在推送远程仓库时Git提示file01文件上产生了冲突,02_dev的本地仓库文件内容如下,此时与远程仓库的冲突很明显。
- 02_dev将远程仓库的代码拉取到本地,发现文件第二行开始的冲突并马上联系01_dev进行冲突的解决。
- 打开冲突的文件(如下图所示),发现都对第2行进行了修改,也都在最后一行添加了内容,Git将第二行开始的内容识别为冲突。
Git很智能的将两个人的修改同时显示出来,并用“=======”分割开来
- “<<<<<<<HEAD” 与 “=======” 中间的是冲突位置中对应的本地仓库的修改。
- “=======” 与 “>>>>>>>” 中间的是冲突位置中对应的远程仓库的修改(也就是刚拉取下来的内容)。
- “>>>>>>>” 后面是本次的提交ID。
- “<<<<<<<HEAD”、“=======”、“>>>>>>>”、提交ID并非实际编写的代码,解决冲突时注意删除。
- 两人商量的解决方案是保留两个人的修改内容,由02_dev负责修改,修改后02_dev的本地仓库文件内容如下图,同时保留了两个人的修改和新增内容。
- 这样02_dev就可以重新推送(add → commit → push)本次合并后的更新到远程仓库,推送成功后,远程仓库文件内容如下。此时冲突解决
在上面的示例中,使用txt文本方式进行的演示,在实际开发中不同的文本编辑器、编程工具的Git插件中,对冲突的展示会略有不同。
如何避免冲突的产生?
代码提交、合并冲突经常发生,但只要在代码开发前,做好仓库预处理工作,就能有效地避免冲突的产生。
在示例:冲突的产生与解决中,开发者02(02_dev)成功的解决了提交远程仓库时遇到的冲突问题,此时他的本地仓库与远程仓库的最新版本内容是一样的,但是开发者01(01_dev)本地仓库和远程仓库仍然是有版本差异的,此时如果直接推送本地仓库(push),仍然会产生冲突,那么如何避免呢?
方式一(推荐新手使用):
如果开发者本地的仓库不常更新使用,在做本地修改时,可以重新clone一份远程仓库的内容到本地,修改后再次提交,这样简单直接的解决了版本差异问题,但缺点是如果仓库较大、更新记录较多,clone过程将耗费一定的时间。
方式二:
如果开发者每天都要对本地仓库进行修改,则建议在本地新建一条开发分支进行代码修改,在要提交远程仓库时,切换到master分支并将远程仓库的最新master分支内容拉取到本地,在本地进行分支合并,对产生的冲突进行修复,成功将内容合并到master分支后,再提交到远程仓库。
在代码托管服务的控制台上解决分支合并冲突
代码托管服务支持分支管理,在进行分支合并时,可能会产生冲突,本案例将复现产生冲突的分支合并请求,并解决合并请求冲突。
- 新建一个仓库名为Demo_Test。
- 基于master分支,新建一个名为“FileTest”的文件,内容如下图所示。
图1 在master分支新建“FileTest”文件
- 基于“master”分支新建分支“branch_test”。此时“master”分支、“branch_test”分支中的内容是一致的,下面在两个分支间制造差异。
- 在“master”分支中,将“FileTest”的内容修改为如下图所示,将提交信息填写为“Update FileTest in master”。
图2 在“mster”分支修改FileTest
- 切换到“branch_test”分支,修改“FileTest”内容如下图所示。将提交信息填写为“Update FileTest in branch_test”。此时“mster”分支与“branch_test”分支的内容已产生差异,即代码冲突。
图3 在“branch_test”分支修改FileTest
- 切换到“branch_test”分支,单击右上角“新建合并请求”,新建一个合并请求,把“branch_test”分支合入“master”分支。
此时将自动跳转到新建的“合并请求详情”页面,如下图所示,代码托管提示您“代码合并冲突未解决”,并建议您“在线解决冲突”或“本地解决冲突”。
图4 新建合并请求
- 下面根据提示,解决冲突:
- 在线解决冲突(推荐在代码量较小或涉及冲突的代码量较小的情况下使用)
- 单击“在线解决冲突”,跳转到页面解决代码冲突,如下图所示。您可以单击“应用源分支”或“应用目标分支”解决合并冲突。如果选择“应用源分支”,将会把“branch_test”分支的内容应用到“master”分支;如果选择“应用目标分支”,将会把“master”分支的内容应用到“branch_test”分支。
- 如果当前的冲突内容较多,您可单击,进入下图所示的页面,在线编辑并解决冲突。其中,“<<<<” 、“>>>>”、“====”所在行是冲突展现与分割符,在修改代码解决冲突时,需要将其删除。
图5 在线手动解决冲突内容页面
- 本地解决冲突(推荐在大型项目中使用)
单击提示内容“本地解决冲突”,即弹出指导内容如下图所示,按照步骤操作即可解决冲突。
代码托管服务会根据您的分支名自动生成适合您的Git命令,您只需要复制并在本地仓库执行即可。
- 在线解决冲突(推荐在代码量较小或涉及冲突的代码量较小的情况下使用)
- 使用下面根据提示,解决冲突:的两种方法之一,即可解决代码冲突,单击“合入”执行分支合并的操作,系统会提示您合并成功,并且源分支“branch_test”与目标分支“master”的内容无差异。