Git 解决冲突

构造冲突

本文主要通过一个简单的 Demo 来演示如何在 Git 中解决冲突,以及相关名词的基本概念。

首先我们编辑一个名为 begin 的文件:

  • This is first line

然后在分支 a 上增加两行,用加号标记出来:

  • This is first line
  • +This is 2nd line
  • +This is 3rd line

再在分支 b 上增加两行,用加号标记出来:

  • This is first line
  • +This is second line
  • +This is third line

当我们想把分支 a 变基(rebase)到分支 b 上时,冲突必然会出现,因为两个分支修改了相同的行,git 不知道怎么处理了。此时有如下输出:

可以看到文件被标记为了 UU。U 的意思表示 updated but unmerged,两个 U 则是说明两个分支都做了修改,但还没有合并。出现 UU 基本上都意味着发生了冲突。

放弃合并

如果对解决方式没有信心,可以暂时先放弃合并,输入 git rebase --abort 即可。如果当初选择的是 merge 两个分支,那么将是 git merge --abort

这个命令能回退到合并分支前,但它无法在正确处理工作目录中的变动。也就是说,在开始合并之前,务必确保自己的工作目录是干净的。

不过在相当多的场合,Git 会自动做出提醒。比如当你的工作目录有改动时,直接就无法 rebase:

如果 merge 会影响到工作目录的改动,Git 也会禁止你 merge,比如我随便修改 begin 的最后一行,再执行 merge 操作会得到如下错误:

所以请牢记第一点: 在 rebase 或者 merge 之前,务必确保你的工作目录是干净的

冲突描述

我们来看一下冲突的文件长什么样,注意我们是在分支 a 上 rebase 到分支 b:

可以看到两个提交之间用 ===== 来分割,上面的部分有 <<<< 这个标记,后面跟着一串 SHA1 值,它其实就是分支 b 指向的那次提交。

下面的部分写得很明确,是分支 a 指向的那次提交内容。

如果我们在分支 b 上使用 git merga branch_a,得到的效果将会是:

可见,除了对分支 b 的描述不太一样以外,冲突的内容是一样的。都是上面是 b 分支的改动,下面是 a 分支的改动。

于是得出第二个结论:冲突被多个等号分割为两部分,上面是当前的改动,而下面是将要合入的改动

冲突文件的原理

运行命令 git ls-files -u,其中 -u 参数用来展示还没有合并的改动:

top Created with Sketch.