相信许多程序员都遇到过 git 冲突,我就一次性把 git 冲突讲透,让你知道冲突是如何产生的,怎样避免代码冲突,即使有冲突了,也能找到方法很快解决。
1、git 冲突的由来
git 冲突出现的场景很多,git rebase
,git pull
,git merge
,git cherry-pick
, 等命令都有可能出现冲突,其实他们的本质是相同的。
两个分支各自都有新的提交,且都对代码同一行进行了修改,现在想将两个分支进行合并,就发生冲突了。
文字有点绕,看看下图:
我和同事都拿到一份提交历史为 a,b 的代码,我们两个都对同一部分代码进行修改并提交,分别为 c 和 d。
现在要将两个提交进行合并,git 不知道应该采用哪个修改,于是就提示冲突,让我们人为进行修改。
2、解决 git merge 冲突
知道冲突怎么来的,解决冲突就很简单了,这里以 git merge
举例。
原始代码只有一个 README.md 文件,内容为:
This is first commit.
我在 master 分支上将该文件进行如下修改并提交:
This is second commit.
然后通过命令 git checkout -b dev
,新建一个 dev 分支,并切换到该分支。
修改 README.md 文件为如下内容,并进行提交:
This is third commit.
我这里在两个分支上,对同一个文件同一行进行了修改并提交。
然后切换到 master 分支上,通过命令 git merge dev
,将两个分支进行合并。
这时会提示 README.md 文件发生了冲突:
$ git merge dev
Auto-merging README.md
CONFLICT (content): Merge conflict in README.md
Automatic merge failed; fix conflicts and then commit the result.
README.md 文件中的内容自动变成:
<<<<<<< HEAD
This is second commit.
=======
This is third commit.
>>>>>>> dev
通过 ======= 将发生冲突的两部分进行隔开,表示这两部分不同内容会在文件中的相同位置。
HEAD 表示当前本地所在分支的别名,dev 表示将要将要合并过来的分支。
手动修改 READ.md 文件去掉冲突,比如修改为:
This is second/third commit.
然后使用 git add
将该文件添加到暂存区。
刚才遇到冲突后,merge 过程就被中断了,现在使用git merge --continue
继续合并过程。这时会弹出文本编辑界面,需要编辑内容作为 commit 信息。
编辑结束,保存 commit 信息后,冲突就被解决了,且合并过程也完成了。
3、git pull 冲突
git pull
是将远程分支的修改同步到本地,并和本地分支进行合并,所以 git pull 实际上是两个命令:
git pull = git fetch + git merge FETCH_HEAD
因为有 git merge,如果我本地有一个新提交,且没上传到服务器,那么新提交和远程分支的修改有可能发生冲突,解决办法同上。
有些人使用 git pull 时喜欢加上参数--rebase
,表示
git pull --rebase = git fetch + git rebase FETCH_HEAD
git merge 和 git rebase 功能比较类似,是将两个分支的提交进行合并,它们的区别有:合并时是否创建新提交,提交树是否呈线性等。
git rebase 发生冲突后,解决办法也是很类似的,区别仅仅是最后的命令更改为 git rebase --continue
。
4、避免 git 冲突
我们知道怎么解决冲突,但是在工作中还是要尽量避免,养成以下好习惯,让你尽可能不产生代码冲突。
尽可能频繁地使用 git pull 同步代码,每次修改都基于最新的源码,大大减少发生冲突的概率。
还要减少每次提交代码的行数,每次做完一个小修改就提交并上传代码。这样即使发生冲突了,你也能很好地解决。
你肯定不希望有几十处,几百行代码发生冲突吧,那场面想想都可怕。