本文是我们 “高级 Git” 系列的一部分。请务必 关注 Tower 的 Twitter 或 注册他们的时事通讯 以了解下一篇文章的信息。
合并冲突……没有人喜欢它们。我们中有些人甚至害怕它们。但当您使用 Git 时,它们是生活中不可避免的一部分,尤其是在与其他开发人员合作时。在大多数情况下,合并冲突并不像您想象的那么可怕。在本系列的第四部分 “高级 Git” 中,我们将讨论何时会发生合并冲突、它们究竟是什么以及如何解决它们。
高级 Git 系列
- 第 1 部分: 在 Git 中创建完美的提交
- 第 2 部分: Git 中的分支策略
- 第 3 部分: 使用拉取请求进行更好的协作
- 第 4 部分: 合并冲突 (您在这里!)
- 第 5 部分: 变基与合并
- 第 6 部分: 交互式变基
- 第 7 部分: 在 Git 中挑选提交
- 第 8 部分: 使用 Reflog 恢复丢失的提交
合并冲突如何以及何时发生
顾名思义:当您将来自不同来源的更改集成(或“合并”)到当前工作分支中时,可能会发生合并冲突。请记住,集成不仅限于合并分支。冲突也可能发生在变基或交互式变基期间,当您在 Git 中挑选提交时(例如,当您从一个分支中选择一个提交并将其应用到另一个分支时),当您运行 git pull
时,甚至当您重新应用一个 stash 时。
所有这些操作都执行某种形式的集成,这就是合并冲突可能发生的时候。当然,这并不意味着这些操作中的每一个都会每次都导致合并冲突——谢天谢地!但冲突究竟何时发生呢?
实际上,Git 的合并功能是其最主要的优势之一:合并分支在大多数情况下都能完美运行,因为 Git 通常能够自行解决问题,并知道如何集成更改。

但有一些情况是存在矛盾的更改——而这就是技术无法决定什么是对或错的时候。这些情况需要人类做出决定。例如,当在两个不同分支的两个提交中更改了完全相同的代码行时,Git 无法知道您更喜欢哪种更改。另一种不太常见的情况:在一个分支中修改了一个文件,而在另一个分支中删除了该文件。Git 会询问您该怎么做,而不是猜测最有效的方法。

如何知道合并冲突何时发生
那么,您如何知道合并冲突发生了呢?不用担心——Git 会告诉您,它还会提供有关如何解决问题的建议。如果合并或变基失败,它会立即让您知道。例如,如果您提交了与其他人更改冲突的更改,Git 会在终端中通知您有关问题的信息,并告诉您自动合并失败
$ git merge develop
CONFLICT (content): Merge conflict in index.html
Automatic merge failed; fix conflicts and then commit the result.
您可以看到我在这里遇到了冲突,Git 马上就告诉我了这个问题。即使我错过了那条消息,下次我键入 git status
时也会被提醒有关冲突的信息。

如果您使用的是 像 Tower 这样的 Git 桌面 GUI,该应用程序会确保您不会错过任何冲突

无论如何:不用担心没有注意到合并冲突!
如何撤销合并冲突并重新开始
您无法忽略合并冲突——相反,您必须在继续工作之前处理它。您基本上有两个选择
- 解决冲突
- 中止或撤销导致冲突的操作
在讨论如何解决冲突之前,让我们简要讨论一下如何撤销并重新开始(知道这有可能非常令人放心)。在许多情况下,这就像使用 --abort
参数一样简单,例如在 git merge --abort
和 git rebase --abort
等命令中。这将撤销合并/变基,并将状态恢复到冲突发生之前的状态。
即使您已经开始解决冲突文件,并且即使在您发现自己陷入死胡同的情况下,这仍然有效,您仍然可以撤销合并。这应该让您相信自己真的不会弄错。您始终可以中止、返回到干净的状态并重新开始。
合并冲突在 Git 中究竟是什么样子
让我们看看冲突在幕后究竟是什么样子。是时候揭开这些小家伙的神秘面纱,更好地了解它们了。一旦您理解了合并冲突,您就可以不再担心了。
例如,让我们看一下当前有冲突的 index.html
文件的内容

Git 足够友好,会在文件中标记有问题的区域。它们被 <<<<<<<
和 >>>>>>>
包围。第一个标记后的内容来自我们当前的工作分支(HEAD
)。具有七个等号(=======
)的行将两个冲突的更改分隔开。最后,显示了来自另一个分支的更改(在本例中为 develop
)。
您的工作是清理这些行并解决冲突:在文本编辑器中、在您喜欢的 IDE 中、在 Git 桌面 GUI 中或在 Diff & Merge 工具中。
如何在 Git 中解决冲突
您使用什么工具或应用程序来解决合并冲突并不重要——完成后,该文件必须完全按照您想要的方式显示。如果只有您一个人,您可以很容易地决定删除代码更改。但是,如果冲突的更改来自其他人,您可能需要在决定保留哪些代码之前与他们进行讨论。也许是您的,也许是别人的,也许是这两者的结合。
清理文件并确保它包含您实际想要的内容的过程并不需要任何魔法。您只需打开文本编辑器或 IDE 并进行更改即可。
但是,有时您会发现这不是最有效的方法。这时,专用工具可以节省时间和精力。例如,有一些 Git 桌面 GUI 可以帮助您解决合并冲突。
让我们以 Tower 为例。它提供了一个专门的“冲突向导”,使这些原本抽象的情况更加直观。这有助于更好地理解更改来自何处、发生了哪种类型的修改,以及最终解决问题

对于更复杂的冲突,手头有一个专门的 Diff & Merge 工具非常有用。它可以通过提供高级功能(如特殊格式和不同的演示模式(例如,并排、合并到单列等))来帮助您更好地理解差异。
市场上有几种 Diff & Merge 工具(这里有一些 适用于 Mac 的工具 和 适用于 Windows 的工具)。您可以使用 git config
命令配置您选择的工具。(有关详细说明,请参阅该工具的文档。)如果发生冲突,您可以通过键入 git mergetool
来调用它。例如,我在 Mac 上使用 Kaleidoscope 应用程序

清理文件后——无论是在文本编辑器中手动清理、在 Git 桌面 GUI 中清理还是使用 Merge 工具清理——您可以像对任何其他更改一样提交该文件。通过键入 git add <filename>
,您通知 Git 冲突已解决。
当所有合并冲突都已解决并添加到暂存区后,您只需 创建一个常规提交。这便完成了冲突解决过程。
别慌!
如你所见,合并冲突没什么好担心的,绝对没有理由惊慌。一旦你了解了导致冲突的真正原因,就可以决定撤销更改或解决冲突。记住,你无法破坏任何东西——即使你在解决冲突时意识到自己犯了错误,你仍然可以撤销它:只需回滚到重大灾难之前的提交,然后重新开始。
如果你想深入了解高级 Git 工具,请随时查看我的(免费!)“高级 Git 工具包”:它包含关于分支策略、交互式变基、Reflog、子模块等等主题的简短视频集。
高级 Git 系列
- 第 1 部分: 在 Git 中创建完美的提交
- 第 2 部分: Git 中的分支策略
- 第 3 部分: 使用拉取请求进行更好的协作
- 第 4 部分: 合并冲突 (您在这里!)
- 第 5 部分: 变基与合并
- 第 6 部分: 交互式变基
- 第 7 部分: 在 Git 中挑选提交
- 第 8 部分: 使用 Reflog 恢复丢失的提交