如何在 Git 中处理合并冲突

Avatar of Tobias Günther
Tobias Günther 发布

DigitalOcean 为您旅程的每个阶段提供云产品。立即开始使用 200 美元的免费额度!

每个人都有一份他们不喜欢的事情清单:去看牙医、堵车或航班取消。当我准备 我的书 时,我并不惊讶地发现许多设计师和开发者毫不犹豫地将合并冲突添加到这份清单中。

当使用 Git 进行版本控制时,无需害怕。一旦您理解合并冲突的工作原理以及如何处理它们,我相信您就可以将它们从这份清单中划掉。

您无法破坏任何东西

您应该牢记的第一件事是,您始终可以撤消合并并返回到冲突发生之前的状态。您始终可以撤消并重新开始

如果您来自另一个版本控制系统(例如 Subversion),您可能会受到创伤:Subversion 中的冲突具有(合理)声誉,即极其复杂且令人讨厌。造成这种情况的原因之一是,简单地说,Git 在这方面的工作方式与 Subversion 完全不同。因此,Git 能够在合并期间处理大多数事情——让您只需解决相对简单的场景。

此外,冲突只会影响您自己。它不会使您的整个团队停滞不前或损害您的中央存储库。这是因为,在 Git 中,冲突只能发生在您的本地机器上——而不是服务器上。

合并冲突是如何发生的

在 Git 中,“合并”是指将另一个分支集成到您当前工作分支的操作。您正在从另一个上下文中获取更改(分支实际上就是一个上下文),并将它们与您当前的工作文件组合起来。如果您不熟悉此概念,请查看此 分支介绍

将 Git 作为您的版本控制系统的一大优势在于,它使合并变得极其容易:在大多数情况下,Git 会弄清楚如何集成新的更改。

但是,在少数情况下,您可能需要介入并告诉 Git 该怎么做。最常见的情况是,当两个分支对同一个文件进行了更改时。即使在这种情况下,Git 也很可能能够自行解决。但是,如果两个人在同一个文件中更改了相同的行,或者一个人决定删除它而另一个人决定修改它,那么 Git 就无法知道哪个是正确的。然后,Git 会将该文件标记为存在冲突——您必须在继续工作之前解决此冲突。

如何解决合并冲突

遇到合并冲突时,第一步是了解发生了什么。您的同事是否与您在同一行编辑了同一个文件?他们是否删除了您修改的文件?你们是否都添加了同名的文件?

Git 会通过“git status”告诉您存在“未合并路径”(这只是告诉您存在一个或多个冲突的另一种方式)。

冲突标记

让我们深入了解如何解决最常见的情况:当两个更改影响同一个文件的同一行时。

现在是时候查看冲突文件的内容了。在您的代码编辑器中打开它。Git 足够友好,会在文件中使用“<<<<<<< HEAD”和“>>>>>>> [other/branch/name]”将有问题的区域括起来。

来自您当前分支的代码位于顶部,来自您正在合并的分支的代码位于底部。

第一个标记后的内容来自您当前的工作分支。在尖括号之后,Git 告诉我们更改来自哪里(来自哪个分支)。带有“=======”的行将两个冲突的更改分隔开。

清理

我们的工作现在是清理这些行:完成后,文件应该完全按照我们想要的方式显示。可能需要咨询编写冲突更改的团队成员以确定最终哪个代码是正确的。可能是您的,可能是他们的,或者可能是两者之间的混合。

在编辑器中打开原始文件并进行清理是完全有效的,但不是很方便。使用专用的合并工具可以使这项工作变得更加容易。您可以使用“git config”命令配置您选择的工具。请参阅您工具的文档以获取详细说明。请注意,仅仅因为您安装了 git 并不意味着您安装了专用的合并工具,这些是独立的可选软件工具。

然后,在发生冲突的情况下,您可以稍后通过简单地键入“git mergetool”来调用它。

对于此示例,我在 Mac 上使用了 Kaleidoscope

左右窗格代表冲突的更改;比“<<<<<<<”和“>>>>>>>”更优雅的可视化。

您现在可以简单地切换要应用哪个更改。中间窗格显示结果代码;在良好的工具中,您甚至可以进一步编辑它。

现在,在使用最终代码清理文件后,剩下的就是保存它。为了提示 Git 您已完成此文件,您应该退出合并工具以继续。在幕后,这告诉 Git 对(现在已成为)冲突文件执行“git add”命令。这将冲突标记为已解决。如果您决定使用合并工具,而是直接在编辑器中清理文件,则必须手动标记文件为已解决(通过执行“git add <filename>”)。

最后,在解决所有冲突后,需要通过常规提交来结束合并冲突情况。

如何撤消合并

如前所述,您可以随时返回到开始合并之前的状态。这应该让您有信心,您不会破坏任何东西。在命令行中,一个简单的“git merge –abort”就可以做到这一点。

如果您在解决冲突时犯了错误,并且仅在完成合并后才意识到这一点,您仍然可以轻松撤消它:只需使用“git reset –hard <commit-hash>”回滚到合并之前的提交,然后重新开始。

工具可以使事情变得更容易

我已经简要地提到过:配备好的工具可以使您的生活轻松很多。 合适的合并工具 将帮助您更好地理解冲突场景并做出正确的决定。

充满信心

有了 Git 提供的所有安全保障,您真的没有必要害怕合并冲突。一旦了解了它们的工作原理以及您的选择,您就应该准备好随时进行合并。始终牢记:您不会破坏任何东西!

编辑寄语

Tobias谦虚地没有将Tower列为解决合并冲突的优秀工具。事实上,我个人使用Tower的原因之一就是因为它在处理合并冲突方面非常出色。

当出现冲突时,非常清晰明了。


并且右键点击冲突文件会提供一些不错的选项。

所以我的流程通常是:

  1. 我的更改与其他分支对该文件的更改,哪一个应该“胜出”是否非常明显?如果是,则选择相关的“使用我的版本解决<file>”或“使用他们的版本解决<file>”。
  2. 如果需要仔细查看,可以在代码编辑器中打开并检查。然后我可能仍然可以使用其中一个选项。
  3. 如果更复杂,则手动修复,然后从Tower中选择“将<file>标记为手动解决”。
  4. 如果存在许多复杂的修复,有时会使用合并工具,Tower也支持通过“在合并工具中打开<file>”选项打开冲突。