解决代码提交的冲突
什么是代码提交冲突?
在多人团队使用代码托管服务时,不可避免的会出现两个人同时修改了一个文件的情况,这时在推送(push)代码到代码托管仓库时就会出现代码提交冲突并推送失败,如下图就是因为本地仓库与远程仓库文件修改的冲突所产生的推送失败。
如何解决代码提交冲突?
当代码提交冲突产生时,可以将远程代码仓库拉取(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分支后,再提交到远程仓库。
如何在代码托管服务的控制台上解决分支合并冲突?
代码托管服务支持云端的分支管理,当在进行分支合并时,有时也会产生冲突,下面来模拟一次产生了冲突的分支合并请求,并将其解决。
- 新建一个仓库。
- 在仓库中新建一个文件,在本案例中,在master分支上新建一个名为file03的文件,其内容初始编写如下。
- 基于master分支新建一个分支,在本案例中,将其命名为branch007。
新建成功后,在master分支、branch007分支中的内容是一模一样的,下面需要让它们产生差异。
- 在master分支中,将file03的内容修改为如下图所示,将提交信息填写为“modify in master”。
- 切换到branch007分支,并将file03文件修改为如下图所示,将提交信息填写为“modify in branch007”。此时切换分支即可直观的看到两个分支上已经产生了差异,也就是冲突。
- 新建一个合并请求,选择将branch007分支合入到master分支,如下图单击“确定”按钮即可提交一条分支合并请求。
此时将自动跳转到“合并请求详情”页面,也可以在“合并请求列表”中单击请求的名称进入此页面,如下图所示,代码托管服务提示您当前的合并状态为“冲突”,并建议您“在线解决冲突”或“本地解决冲突”
- 根据提示,解决冲突:
- 在线解决冲突(推荐在代码量较小或涉及冲突的代码量较小的情况下使用)
- 单击提示内容“在线解决冲突”,弹出如下图页面非常直观的展示了代码冲突。
在此页面中可以直接选择“应用我的”或“应用他的”来选择一方的修改作为最终修复后的内容。
- 当情况较复杂,简单的直接覆盖无法解决问题时,可单击进入“手动编辑”模式,如下图所示,可以看到跟示例:冲突的产生与解决中的冲突展现格式很像。
- 在上述页面中手动修改代码以解决冲突,并进行提交即可。
提交时注意需要填写提交信息。
上图中“<<<<” 、“>>>>”、“====”等所在行是冲突展现与分割符,在修改代码解决冲突时,要注意将其删除。
- 单击提示内容“在线解决冲突”,弹出如下图页面非常直观的展示了代码冲突。
- 本地解决冲突(推荐在大型项目中使用)
单击提示内容“本地解决冲突”,即弹出指导内容如下图所示,按照步骤操作即可。
代码托管服务会根据您的分支名自动生成适合您的Git命令,您只需要复制并在本地仓库执行即可。
- 在线解决冲突(推荐在代码量较小或涉及冲突的代码量较小的情况下使用)
- 使用上述两种方法之一,解决了冲突之后,分支合并状态变为“开启”,此时可以单击“合入”按钮,进行分支合并的操作了,系统会提示您合并成功。
(可选)也可以使用分支合并评审流程。
此时master、branch007两个分支的内容是一样的了,您可以切换分支进行查看验证。