每个人都有一份他们不喜欢的事情清单:去看牙医、堵车或航班取消。当我准备 我的书 时,我并不惊讶地发现许多设计师和开发者毫不犹豫地将合并冲突添加到这份清单中。
当使用 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的原因之一就是因为它在处理合并冲突方面非常出色。
当出现冲突时,非常清晰明了。

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

所以我的流程通常是:
- 我的更改与其他分支对该文件的更改,哪一个应该“胜出”是否非常明显?如果是,则选择相关的“使用我的版本解决<file>”或“使用他们的版本解决<file>”。
- 如果需要仔细查看,可以在代码编辑器中打开并检查。然后我可能仍然可以使用其中一个选项。
- 如果更复杂,则手动修复,然后从Tower中选择“将<file>标记为手动解决”。
- 如果存在许多复杂的修复,有时会使用合并工具,Tower也支持通过“在合并工具中打开<file>”选项打开冲突。
我爱Tower!每天都在我的工作流程中使用它。强烈推荐!
多么具有讽刺意味和及时性:我最近刚创建了一个GitHub账户。感谢这篇文章!
具有讽刺意味的是,合适的合并工具后面列出的工具明显缺少Linux选项。众所周知,Git的创建者Linus Torvalds因另一个项目而闻名,我此刻想不起来了。
对于Linux用户,请查看Meld和Gitg
谢谢,我正要问Linux用户有什么工具。
大家好!作者正在这里打字。如果您有任何问题,请告诉我——如果我能回答,我将很乐意回答!
如何在Git中报告错误?
我可以通过git://或ssh://而不是https://访问我的仓库吗?
是的:Git支持所有这些协议。请记住,“git://”非常高效,但没有身份验证机制(因此适用于只读访问)。“ssh://”主要通过SSH公钥认证进行支持。
一个很棒的总结。
我过去几个月才开始认真使用Git,冲突曾经是我的噩梦。但我已经通过艰苦的方式学会了解决它们。可惜这篇文章没有早点写出来。
我选择的合并/差异工具是Beyond Compare。
或者你仍然可以使用SourceTree,它有一个可用的GUI。
有趣的阅读。但是,我不同意其中一点:你绝对可以破坏东西。
重要的是要意识到,虽然git会阻止你在远程仓库中创建冲突,但这并不意味着你不能破坏你的应用程序。当然,有可能以一种git不会抱怨但会破坏你的应用程序的方式来解决冲突。
当然,任何版本控制方法都是如此,但我认为这里“你无法破坏任何东西”的口号有点误导人。
当然,Git不会阻止你编写“错误”的代码——这是绝对正确的。但是,它在这种情况下提供了一个安全网:你可以轻松地撤消错误的更改。
无论你犯了什么错误,在Git中都相当容易撤消和恢复。
对于Windows用户,我个人喜欢WinMerge。转到文件>打开冲突文件…它将使用与比较两个单独文件相同的界面打开合并冲突。
你忘记了解释如何解决整个文件的冲突……而不仅仅是文件内部的冲突。
例如,我在63个文件中存在冲突->我知道我想保留其中23个文件的远程分支版本,其余文件的本地版本。
示例 – 你想通过保留本地文件来解决冲突
git checkout --ours conflict.file
或者
你想通过保留他们的文件版本来解决冲突
git checkout --theirs conflict.file
是的,你说得对。
我刚刚发布了一篇文章,解释了如何将Git与P4Merge无缝集成。我喜欢P4Merge,因为它无论在Windows、Linux还是Mac上都能提供统一的性能。
试试看?http://goo.gl/YKGvnX
我刚刚开始在Linux上使用Meld。对于Linux用户来说,它真的很好用,并且有非常直观的文档。
感谢更正,它运行良好。