详解Git合并冲突——问题重现、原因及解决 “Automatic merge failed; fix conflicts and then commit the result.“

详解Git合并冲突——问题重现、原因及解决 “Automatic merge failed; fix conflicts and then commit the result.“

码农世界 2024-05-17 后端 64 次浏览 0个评论

最后更新日期:2022/10/6


在Git中使用git merge命令合并两个分支的时候,有可能产生这种情况:

$ git merge A
Auto-merging merge.txt
CONFLICT (content): Merge conflict in merge.txt
Automatic merge failed; fix conflicts and then commit the result.

这就是发生了冲突(conflict)。

为什么会有冲突?要如何解决呢?请看下文介绍。

目录

  • 为什么会发生冲突?
  • 制造一个冲突
    • 第一步:初始化仓库及文件
    • 第二步:在新分支上更改并提交文件
    • 第三步:在主分支上更改并提交文件
    • 第四步:执行合并,触发冲突
    • 如何查看冲突?
    • 如何解决冲突?
    • 总结
    • 其他问题

      为什么会发生冲突?

      简单来说,就是两个分支都对同一个文件做了更改,当这两个分支合并的时候,Git不知道要采用哪一个更改,便发生了冲突。

      详解Git合并冲突——问题重现、原因及解决 “Automatic merge failed; fix conflicts and then commit the result.“
      图1 一个冲突的例子

      举个栗子,假设刚开始master分支版本为C0,然后依次发生了以下情况:

      1. 小A基于C0创建新分支new_branch,并在该分支上改动了文件merge.txt,提交得到版本C2
      2. 小B在主分支master上进行开发,同样改动了merge.txt,提交得到版本C1

      此时,如果用git merge将master与new_branch合并,就会发生冲突。完整的过程如图1所示。

      Git提示冲突,也是一件好事,它其实是在告诉你:

      “你让我合并new_branch和master两个分支,但是它们两个都改动了merge.txt,一个说要这样改,一个说要那样改,我应该听谁的呀?你来帮我看下吧!”。(形象解释)

      在讲解如何解决冲突之前,我们得先有一个冲突。下面将根据图1制造出一个冲突。

      制造一个冲突

      制造图1的冲突分为4个步骤:

      • 第一步:初始化仓库及文件
      • 第二步:在新分支上更改并提交文件
      • 第三步:在主分支上更改并提交文件
      • 第四步:执行合并,触发冲突

        第一步:初始化仓库及文件

        首先创建一个新仓库。打开Git Bash,顺序执行以下命令:

        $ mkdir git-merge-test
        $ cd git-merge-test
        $ git init
        Initialized empty Git repository in path/to/your/work/dictionary/git-merge-test/.git/
        

        以上命令在当前位置创建了一个名为git-merge-test的文件夹,并将其初始化为Git仓库。

        然后创建仓库文件。在仓库根目录下新建merge.txt,写入以下内容:

        这是第一行,这行不会被修改
        这是第二行
        

        详解Git合并冲突——问题重现、原因及解决 “Automatic merge failed; fix conflicts and then commit the result.“

        添加merge.txt到暂存区并提交更改:

        $ git add .
        $ git commit -m"初始化仓库内容"
        [master 8bc6262] 初始化仓库
         Date: Wed Oct 5 16:30:35 2022 +0800
         1 file changed, 2 insertions(+)
         create mode 100644 merge.txt
        

        此时,master处于图1中的C0。

        第二步:在新分支上更改并提交文件

        然后,创建一个新分支new_branch::

        $ git checkout -b new_branch
        Switched to a new branch 'new_branch'
        

        说明:git checkout -b 分支名表示创建一个新分支并切换到这个分支上。

        修改merge.txt:

        这是第一行,这行不会被修改
        我在new_branch分支上修改了第二行
        

        详解Git合并冲突——问题重现、原因及解决 “Automatic merge failed; fix conflicts and then commit the result.“

        添加merge.txt并提交更改:

        $ git commit -am"修改merge.txt"
        [new_branch 8eb88a9] 修改merge.txt
         1 file changed, 1 insertion(+), 1 deletion(-)
        

        说明:git commit -am"提交信息"中的选项a表示先git add所有发生改动的文件再提交。

        此时,new_branch位于图1中的C2。

        第三步:在主分支上更改并提交文件

        $ git checkout master
        Switched to branch 'master'
        $ echo "我在master分支上添加了第三行" >> merge.txt
        $ git commit -am"新增内容到merge.txt"
        [master 52c86fa] 新增内容到merge.txt
         1 file changed, 1 insertion(+)
        

        上述命令的意思是,先切换回master分支,然后往merge.txt中添加一行内容(">>"表示追加重定向文件),最后提交更改。

        此时,master位于图1中的C1。

        第四步:执行合并,触发冲突

        在合并之前,我们先捋一下现在的状况:

        • 最初的merge.txt的内容为:
          这是第一行,这行不会被修改
          这是第二行
          
        • 在new_branch分支上改动后的merge.txt内容为:
          这是第一行,这行不会被修改
          我在new_branch分支上修改了第二行
          
        • 在master主分支上改动后的merge.txt内容为:
          这是第一行,这行不会被修改
          这是第二行
          我在master分支上添加了第三行
          

          两个分支都改动了merge.txt,合并会发生什么呢?下面就来试一下。

          在master分支上执行git merge new_branch,尝试把new_branch分支合并过来:

          $ git merge new_branch
          Auto-merging merge.txt
          CONFLICT (content): Merge conflict in merge.txt
          Automatic merge failed; fix conflicts and then commit the result.
          

          可以看到,冲突发生了。

          在解决冲突之前,应该先要知道如何查看冲突。下面将进行介绍。

          如何查看冲突?

          文章刚开始已经提到,合并时发生冲突,是因为两个分支都对同一个文件做了更改。当合并master和new_branch的时候,Git发现对于merge.txt,一个分支这样改,另一个分支那样改,就陷入了两难。从报错信息可知,冲突需要我们手动解决后方可提交。

          很多人到这里就懵了,不知道该怎么弄。实际上,我们现在正处于合并的“中间状态”。合并的中间状态就是合并了,但还没完全合并。。好吧,是废话,意思就是你执行git merge了,但git merge并没有执行完成(因为发生冲突了),需要你解决冲突后继续进行。

          敲入git status,就可以看到这样的信息:

          $ git status
          On branch master
          You have unmerged paths.
            (fix conflicts and run "git commit")
            (use "git merge --abort" to abort the merge)
          Unmerged paths:
            (use "git add ..." to mark resolution)
                  both modified:   merge.txt
          no changes added to commit (use "git add" and/or "git commit -a")
          

          git status告诉我们以下信息:

          • “You have unmerged paths”:我们现在正处于合并的中间状态,有一些没有合并的文件;
          • “Unmerged paths”:下面列出了所有未合并的文件,都显示为红色(网页上看不到)。可以看到,merge.txt没有合并,因为两个分支都更改了它(“both modified”),发生了冲突。我们要先把冲突解决了。

            那我们现在就来查看冲突。用编辑器打开merge.txt,会发现内容变成了这样:

            这是第一行,这行不会被修改
            <<<<<<< HEAD
            这是第二行
            我在master分支上添加了第三行
            =======
            我在new_branch分支上修改了第二行
            >>>>>>> new_branch
            

            里面多了三行我们看不懂的记号:

            • <<<<<<< HEAD
            • =======
            • >>>>>>> new_branch

              这些记号是标记冲突内容的分隔线,解释如下:

              • <<<<<<< HEAD和=======之间的内容:是master分支修改的内容(准确来说是HEAD指针指向的分支修改的内容);
              • =======和>>>>>>> new_branch之间的内容:是new_branch分支修改的内容;
              • 分割线之外的内容:是两个分支都没有改动的内容(如merge.txt第一行)。

                看懂了吗?然后,解决冲突就变得很简单了。

                如何解决冲突?

                解决冲突只需3步:

                1. 编辑冲突文件。决定要保留的内容,然后删掉三行分割线
                2. git add将冲突文件添加到暂存区
                3. git commit提交

                对于第1步,要按照你的具体情况去改。通常情况下,我们有这两种做法:

                • 保留其中一个修改,删掉另一个
                • 同时保留两个修改

                  不管怎样,最终改好的文件会原封不动地提交到仓库中。另外需要注意,最后不要忘了删掉三行分隔线,即:<<<<<<< HEAD,=======,>>>>>>> new_branch

                  在我们的例子中,假如我们想同时保留两个分支的修改,那么可以编辑merge.txt,仅删掉三行分隔线,其他部分不用管,得到以下内容:

                  这是第一行,这行不会被修改
                  这是第二行
                  我在master分支上添加了第三行
                  我在new_branch分支上修改了第二行
                  

                  改好后,就可以提交了:

                  $ git add merge.txt
                  $ git commit -m "合并new_branch分支并解决冲突"
                  [master 0c88c4f] 合并new_branch分支并解决冲突
                  

                  查看合并后的提交记录:

                  $ git log
                  commit 0c88c4f9210af067125c9027f3e5885065f88dd0 (HEAD -> master)
                  Merge: 52c86fa 8eb88a9
                  Author: lanjianghao <528601933@qq.com>
                  Date:   Wed Oct 5 22:28:34 2022 +0800
                      合并new_branch分支并解决冲突
                  commit 52c86fa51bca34c7763ed7b56b7705b3ce31379c
                  Author: lanjianghao <528601933@qq.com>
                  Date:   Wed Oct 5 19:23:32 2022 +0800
                      新增内容到merge.txt
                  commit 8eb88a9d1dc88b30333492ec44c12685aaa8187c (new_branch)
                  Author: lanjianghao <528601933@qq.com>
                  Date:   Wed Oct 5 19:17:06 2022 +0800
                      修改merge.txt
                  commit 8bc626277eec39e413dcdd764642865b5291674e
                  Author: lanjianghao <528601933@qq.com>
                  Date:   Wed Oct 5 16:30:35 2022 +0800
                      初始化仓库
                  

                  可以看到,日志中新增了一条合并记录。

                  总结

                  • 为什么合并时发生了冲突?
                    • 要合并的两个分支改动了同一个文件,Git不知道要采用哪个,还是两个都采用,需要由你来决定。
                    • 怎样查看冲突?
                      • git status查看冲突的文件
                      • 编辑器打开冲突的文件,查看冲突的内容
                      • 冲突内容分隔线怎么看:
                        未冲突的内容(两个分支都未改动)在分隔线外面
                        <<<<<<< HEAD
                        Git当前所在分支修改的内容(准确来说是HEAD指针指向的分支修改的内容)
                        =======
                        要合并过来的分支修改的内容
                        >>>>>>> branch_to_merge
                        
                      • 怎样解决冲突?
                        1. git status查看冲突的文件
                        2. 编辑冲突文件,解决冲突(记得删除三行分隔线)
                        3. git add 冲突文件
                        4. git commit -m "提交信息"

                        其他问题

                        • 我不想继续合并了,如何退出合并的中间状态?
                          git merge --abort
                          
                          前文中提到,如果执行git merge合并时发生冲突,则会进入合并的中间状态。合并的中间状态下将无法执行其他一些操作(如切换分支)。

                          如果不想继续合并,要先用git merge --abort命令退出。该命令会使你回到执行git merge 分支之前的状态。

                          感谢大家能看到这里!本人也还是小白,如果有不对的地方,欢迎指正!

                          参考:

                          https://www.atlassian.com/git/tutorials/using-branches/merge-conflicts

转载请注明来自码农世界,本文标题:《详解Git合并冲突——问题重现、原因及解决 “Automatic merge failed; fix conflicts and then commit the result.“》

百度分享代码,如果开启HTTPS请参考李洋个人博客
每一天,每一秒,你所做的决定都会改变你的人生!

发表评论

快捷回复:

评论列表 (暂无评论,64人围观)参与讨论

还没有评论,来说两句吧...

Top