手把手教学,如何解决 git 冲突?

Git 是现在使用最广泛的源代码管理程序。一个合格的程序员必须要熟练掌握 Git。在使用 Git 的时候,最让人头疼的问题是什么?肯定是解冲突了。如果两个人修改了同一个文件的相同位置,那么当一个人提交代码并合并到主分支以后,第二个人尝试合并时就会触发冲突。大多数情况下,Git 自己知道如何把两份代码合并起来。但有时候当 Git 不知道应该怎么合并,就会提示你需要手动解决冲突。

我以前学习 Git 的时候,由于没有人跟我一起提交代码,所以我为了模拟两人提交的情况,会把代码 clone 到两个文件夹里面,然后把相同的位置分别做不同的修改,再分别提交。过程非常繁琐。

最近因为评上了微软 MVP 的关系,会主动关注一下微软的在线课程,结果发现微软悄无声息地出了一整套的 Github 课程。而这其中,有一套交互式的课程手把手指导如何解决 Git 的冲突:在 GitHub 上使用合并冲突解决来解决竞争提交,由于 Github 是基于 Git 的,所以只要稍作设置,这个课程就能变成通用的 Git 操作指导教程。

一开始我以为这个课程只有 MVP 能看,后来发现,课程不仅完全免费,而且不需要注册,所有人都能随时学习。只要你有一个 Github 账号就能参加。大家点击公众号下方的阅读原文就可以打开这个课程页面。

打开课程以后,页面如下图所示:

点击其中的“开始”按钮,就可以开始学习。课程一共有5个单元,如下图所示。

其中,第1,2单元是知识性介绍,大家可以看一下。今天我们重点说一下第3单元《练习-管理合并冲突》。这一单元,会基于 Github Lab(Github 学习实验室)来一步一步手把手指导。我们点击在 Github 上启动学习实验室按钮。

此时,浏览器会新开一个选项卡,如下图所示。点击Start free course,如下图所示。

此时,会让你登录 Github,并授权 Github Lab 创建一个练习源,如下图所示:

大家可以创建公共源,也可以创建私有源。如果是创建私有源的话,之后每次从远程推拉代码时,会让你输入 Github 账号密码。需要注意的是Additional Options这一项一定要选择Use the command line,这样我们才能学习通用的 Git 操作。另外两项都是 Github 专用的操作。对我们帮助不大。

授权完成以后,你的 Github 上会自动创建一个源,并且有很多的冲突,如下图所示:

回到刚才的课程页面,可以看到下面出现了几个课程阶段,如下图所示。

我们点击第一课的Start按钮,开始第一课。浏览器弹出了新的页面(实际上就是 Github 的 PR 页面),在这里,我们可以根据它的提示和说明进行操作。如下图所示:

大家不要担心全是英文看不懂,真正需要你进行的操作,都是灰色背景的代码片段,这些代码是很容易看懂的。

根据提示,首先 clone 代码:

1
2
git clone https://github.com/kingname/merge-conflicts.git
cd merge-conflicts

接下来,切换到update-config分支,然后拉取远程最新代码。

1
2
git checkout update-config
git pull

然后,我们把远程的master分支代码合并到update-config分支中:

1
git merge origin/master

发现了冲突,如下图所示:

它已经提示了_config.yml文件有冲突。所以我们可以直接打开_config.yml文件。你可以使用自己喜欢的编辑器打开。我这里使用 Vim。打开以后的代码如下图所示:

注意,这里的实际代码可能跟教程不一样。教程里面说冲突内容是被<<<<<<< update-config>>>>>>> master包起来的,但实际上代码里面的冲突内容是被<<<<<<< HEAD>>>>>>> origin/master包起来的。

大家可以看到,在<<<<<<< HEAD=======中间的内容,与=======>>>>>>> origin/master中间的内容,他们的字段名是一样的,但是值不一样,所以 Git 不知道应该以哪个为准,需要我们人工决断。

假设我想以上面这一段为准(在实际开发过程中,可能上下要各取一部分合并),如下图所示:

保存修改,根据它的提示,执行以下代码进行提交:

1
2
3
git add .
git commit -m "merge master into update-config"
git push

提交成功以后,网页上会立刻给出反馈:

我们继续往下看,根据它的提示,首先切换回master分支,然后拉取最新代码,然后把update-config分支的内容合并进入master:

1
2
3
git checkout master
git pull
git merge update-config

合并成功,如下图所示。

最后把本地已经合并的代码使用git push推到远程即可。

第二个问题更复杂一些,这次有两个冲突文件,如下图所示:

并且冲突的内容有好几个,如下图所示:

但解决方法还是一样的,人来决定要保留哪些内容,把不要的地方删掉:

保存修改,然后检查第二个文件。第二个文件也解决以后,根据页面上的提示输入代码,合并提交就可以了。

前两个问题,是别人创建了冲突,需要我们来改。第三个问题,是我们自己导致了冲突,我们自己来解决。方法跟之前是一样的,就不多说了。

最后这一步,让你完善这个源里面的内容。因为这个模拟冲突的源本质上是一个在线简历页面,你可以把里面的内容改成你自己的。当然,这是选做题,可做可不做。

所有任务都做完了,是不是很有成就感:

最后还能解锁成就:

总结

根据上面的学习过程,我总结了一个解决冲突的常规流程:

  1. 前提条件:不能在 master 分支上修改任何文件。master 分支的变更只能通过 git pull 和 git merge 获得。在 master 分支下面,不能手动修改任何文件。
  2. 我们自己有一个分支用来修改代码,例如我的分支叫做dev分支。我把代码修改完成了,现在不知道有没有冲突。
  3. 在 dev 分支里面,执行命令git merge origin/master,把远程的master分支合并到当前dev分支中。如果没有任何报错,那么直接转到第5步。
  4. 如果有冲突,根据提示,把冲突解决,保存文件。然后执行命令git add xxx把你修改的文件添加到缓存区。然后执行命令git commit -m "xxx"添加 commit 信息。
  5. 执行如下命令,切换到 master 分支:git checkout master
  6. 执行命令git pull确保当前 master 分支是最新代码。
  7. dev分支的代码合并回 master 分支:git merge dev
  8. 提交代码:git push

只要所有开发者都遵守这个规则,那么解决冲突是一件非常容易的事情。