Git之旅(12):解决冲突

  • A+
所属分类:Git  运维技术

  

博主会将与Git有关的知识点总结到"通俗易懂Git入门系列"文章中,如果你对Git不是特别了解,请按照顺序阅读"Git系列",以便站在前文的基础上理解新的知识点。

 

前文中介绍了合并分支的方法以及常见场景,但是并没有模拟合并分支时遇到冲突的场景,这篇文章就站在前文的基础上,来总结一下怎样解决冲突。

 

如果两个分支中的同一个文件中的同一行的内容不一样,当我们合并这两个分支时,就会出现冲突,因为git无法判断我们想要以哪个内容为准,所以需要我们人为介入去确认,人为介入确认内容的过程,就是解决冲突的过程。

 

为了方便演示,我们先来创建一个测试仓库,并且创建两个分支出来,然后分别修改这两个分支中的同一个文件中的同一行,以便之后合并时能够出现冲突,过程如下:

通过上述步骤,我们创建了一个测试文件testfile,在testfile里面写了两行内容,并且创建了两个初始提交,然后,我们基于master分支创建了new分支,现在,new分支和master分支是完全相同的,我准备在两个分支中分别修改testfile的第二行,让new分支和master分支中的testfile的第二行的内容变的不同。

先来操作new分支,操作如下:

如上所示,我将new分支中的testfile文件中的第二行从"2"改成了"2new",并且基于这个修改,在new分支中创建了新提交。

new分支操作完了,现在来操作master分支。

如上所示,我将master分支中的testfile文件中的第二行从"2"改成了"2master",并且基于这个修改,在master分支中创建了新提交。

现在,在master分支和new分中,都有了属于了自己的提交,如下图所示,而且,这些提交都是针对testfile文件的第二行所做的修改。

Git之旅(12):解决冲突

假设,此时我们想要合并两个分支,就会出现所谓的冲突,我们来试试。

当前我们处于master分支中,现在尝试直接把new分支合并到当前分支,命令如下:

git merge new

当我们执行上述命令后,会看到如下返回信息

那么上述返回信息是什么意思呢?大概意思就是,合并时出现冲突啦,冲突在testfile中,自动合并失败啦,快来人解决冲突啊。

而且,我们能够发现,在git bash中,如果合并时遇到冲突,在git bash所显示的路径中就会添加上如下字样

"(分支名|MERGING)"

就像上例中的 "/d/workspace/git/testgit (master|MERGING)" 一样, "(分支名|MERGING)"表示当前分支还处于"合并中"的状态,也就是说,合并操作并没有完成,还在进行中。

此时,如果我们执行git status命令,能够看到如下信息

从上述信息可以看出,我们当前处于master分支,存在没有合并完成的路径(存在没有合并完成的文件)。

而且git提示我们,现在我们有两种选择,这两种选择分别如下:

(fix conflicts and run "git commit")

(use "git merge --abort" to abort the merge)

第一种选择是:修复冲突,然后将确定后的内容创建提交。

第二种选择是:使用"git merge --abort"命令放弃合并。

看来git还是很人性化的,在合并时如果遇到冲突,我们可以选择放弃合并,就像从来都没有发生过任何事情一样,也可以选择解决冲突,完成合并,后文会演示这两种操作,此处不用纠结。

从返回信息的"Unmerged paths"中,我们能够找到所有未完成合并的文件(存在冲突的文件),而上例中,合并时出现冲突的文件就是testfile文件,那么,我们来看看,在产生冲突以后,testfile文件变成了什么样子。

如上所示,当冲突发生以后,git会自动将冲突的部分标注出来。

git会使用如下结构,将冲突的内容标注起来

<<<<<<< HEAD

=======

>>>>>>> BranchName

git会将当前分支中的内容放在 "<<<<<<< HEAD" 与 "=======" 之间。

git会将new分支中的内容放在 "======="  与 "<<<<<<< new" 之间。

也就是说,git并不能确定,是使用"2master"作为最终的内容,还是使用"2new"作为最终的内容,所以,需要我们人为的进行裁决,决定最终的内容。

 

到目前为止,我们已经在合并时遇到了冲突,并且查看了冲突所在的testfile文件,我们可以选择放弃合并,也可以选择解决冲突,我们先来演示一下,怎样放弃合并,正如提示信息中所示,我们只要执行"git merge --abort"命令即可放弃合并,我们来试试,操作如下:

如上例所示,当我们执行git merge --abort命令以后,git就取消了本次合并操作,此时,再次执行"git status"命令,可以看到master分支中没有任何需要修改和提交的内容,查看testfile的内容,会发现testfile中的内容与执行合并操作之前相同,就好像没有执行过任何合并操作一样。这就是在冲突时放弃合并的方法,很容易吧。

 

我们已经掌握了怎样在合并产生冲突时放弃合并,现在我们来看看怎样在发生冲突的情况下完成合并。

再次执行如下合并命令,以便合并时产生冲突。

如你所见,自动合并失败了,因为有冲突在testfile文件中,git提示我们,可以修复冲突,然后将修复后的结果提交。

查看testfile文件的内容,发现冲突的部分已经被git标注好了,如下:

我们可以按照自己的需求,修改冲突的部分,此处假设,我想要使用"2 master 2 new"作为最终的内容,我只需要通过编辑器,将冲突标注的部分改为"2 master 2 new"即可,操作如下(使用vim编辑器编辑文本):

好了,冲突的部分已经被人为干预解决了,不过,这并不代表整个合并操作完成了,在解决所有冲突文件以后,我们还需要将最终的状态创建为提交,才算完成了整个合并操作,整个流程操作如下:

如上述操作所示,我们先执行了git status命令,如果你在git bash中也执行了git status命令,会看到返回信息中testfile是红色的,也就是说,testfile目前的状态还未添加到暂存区,于是,为了方便提交,我们执行了git add命令,将testfile添加到了暂存区,再次执行git status命令,可以看到testfile已经变为绿色,最后,我们使用git commit命令创建了提交,将解决冲突后的合并状态永久的保存了在了新提交中。

此时,使用gitk --all命令查看图形化界面,如下:

Git之旅(12):解决冲突

可以看到,合并完成了,在合并过程中虽然遇到了冲突,但是我们人为介入,解决了冲突,并且在最后创建了提交,将合并后的状态保存在了新的合并提交中。

细心如你肯定已经发现了,上图所表达的状态其实与前文中正常合并后的状态一样(前一篇文章中我们演示了在没有冲突的情况下顺利完成合并的操作,其合并后的状态与上图一样),只不过,当遇到冲突时,合并提交不会自动创建,而是会给我们解决冲突的机会,当我们将所有冲突解决以后,再手动的创建合并提交,也就是刚才演示的解决冲突、创建提交的过程。总结成一句话就是,在合并时,如果没有冲突,就自动创建合并提交,如果存在冲突,需解决冲突后手动创建提交。

 

其实,在没有冲突能够正常合并的情况下,我们也可以明确指定不自动创建提交,而是手动的创建提交,我们只需要借助"--no-commit"参数即可,示例如下

上述命令表示,将new分支合并到当前分支,在没有冲突的情况下,也不自动创建提交,而是给我们一个修改的机会,我们可以将内容进行进一步修改后,以最后敲定的结果创建提交。快来自己创建一个测试场景,试试上面的"--no-commit"参数吧,此处就不进行演示了。

 

当分支合并完成后,我们就可以将不需要的分支删除了,比如上例中的new分支,我们已经将new分支的内容合并到了master分支中,所以,如果不再需要在new分支上进行操作,即可删除new分支,示例命令如下:

如上述操作所示,我们想要删除new分支,所以执行了"git branch -d new"命令,"-d"参数为删除之意,需要注意,你如果想要删除new分支,就不能处于new分支中,必须先切换到其他分支中,而上例中,我们删除new分支时,处于master分支中,所以可以正常删除new分支,删除分支后,使用"git branch -a"命令查看所有分支,已经看不到new分支了,可以确认,new分支已经被删除了。

此时,如果使用gitk --all命令查看图形化界面,会看到如下界面:

Git之旅(12):解决冲突

从上图中可以看出,new分支的分支标签已经被删除了,目前只有master分支。

 

在有些情况下,我们使用"-d"参数,是无法删除对应分支的,比如,当git检测到,你要删除的分支还没有合并到其他分支中,git会出现类似如下提示:

error: The branch 'new' is not fully merged.

If you are sure you want to delete it, run 'git branch -D new'.

在new分支没有完全合并到其他分支中时,如果执行"git branch -d new"命令,就会出现上述提示,这是git为了保险起见而进行的提示,如果你无论如何就是想要删除new分支,无论它是否被完全合并都想要删除它,可以使用"-D"选项(大写D),即可强制删除对应的分支,示例如下:

  

好啦,到目前为止,我们已经了解了怎样合并分支、解决冲突、删除分支,希望这篇文章能够帮助到你,加油~

  

weinxin
我的微信公众号
关注"实用运维笔记"微信公众号,当博客中有新文章时,可第一时间得知哦~
朱双印

发表评论

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

目前评论:1   其中:访客  1   博主  0

    • avatar 北美玩具 1

      厉害👍👍👍👍👍