为什么merge冲突让开发者害怕(以及为什么不必害怕)
如果你使用Git有一段时间了,几乎可以肯定遇到过令人头疼的merge冲突。当Git告诉你它无法自动merge你的更改时,那种感觉就像撞上了一堵墙。许多开发者,尤其是职业生涯早期的开发者,会把merge冲突当作出了问题的信号。但事实更简单:merge冲突是协作开发的正常组成部分。只需要正确的方法就能高效地解决它们。
什么是merge冲突?
当Git无法自动合并来自两个不同branch的更改时,就会发生merge冲突。这通常发生在两个人(甚至同一个人在不同的branch上)编辑了同一个文件的同一行代码时。
当Git检测到冲突时,它会直接在受影响的文件中插入冲突标记:
<<<<<<< HEAD
const timeout = 5000;
=======
const timeout = 10000;
>>>>>>> feature/update-timeout
<<<<<<< HEAD和=======之间的所有内容是你的版本(通常称为"ours")。=======和>>>>>>>之间的所有内容是传入版本("theirs")。你的任务是决定最终结果应该是什么,删除标记,并告诉Git冲突已解决。
传统方式:手动编辑冲突标记
最基本的方法是在文本编辑器中打开有冲突的文件,找到每组冲突标记,然后手动编辑代码。对于小文件中的单个冲突,这种方法没问题。但在以下情况下会很快变得痛苦:
- 单个文件中散布的多个冲突
- 同一次merge中有多个冲突文件
- 需要合并两个版本部分内容的复杂更改
- 标记难以阅读的嵌套或相邻冲突
手动编辑标记容易出错。很容易不小心遗漏一个标记、删除错误的代码块,或者因为忘记了每个版本想要做什么而引入微妙的bug。一定有更好的方法。
可视化方式:使用3-way merge编辑器
什么是3-way merge?
3-way merge同时显示文件的三个版本:
- Base -- 共同祖先,即在任何一个branch做出更改之前的文件版本
- Ours -- 你的branch中的文件版本
- Theirs -- 传入branch中的文件版本
能够同时看到所有三个版本是一个巨大的改变。你不再需要盯着冲突标记试图重建发生了什么,而是可以准确地看到每一方相对于原始版本做了什么更改。这种上下文使得决定如何解决每个冲突变得容易得多。
在GitSquid中的工作方式
GitSquid内置了一个3-way merge编辑器,旨在让冲突解决变得简单直接,即使你从未解决过冲突也不用担心。工作流程如下:
1. 一目了然地查看所有冲突文件。 当merge产生冲突时,冲突面板会列出每个受影响的文件。你可以立即了解需要解决的范围。
2. 打开3-way编辑器。 点击任何冲突文件,在merge编辑器中打开它。你会看到三列并排显示:左侧是Base,中间是Ours,右侧是Theirs。每一列都显示带有语法高亮的完整文件内容,这样你可以在上下文中阅读代码。
3. 逐块解决冲突。 每个冲突都被高亮显示,并作为独立的块呈现。对于每个冲突,你都有清晰的操作按钮:
- Use Ours -- 保留冲突代码的你的版本
- Use Theirs -- 接受传入版本
- Use Both -- 依次包含两个更改
一次点击,冲突就解决了。不需要搜寻标记,也没有误删代码行的风险。
4. 微调结果。 在三列下方,结果面板在由CodeMirror 6驱动的带有语法高亮的完整代码编辑器中显示合并后的输出。如果一键选项都无法产生你需要的确切结果,你可以直接编辑结果。当你需要以自定义方式组合两个版本的部分内容时,这非常有用——例如保留一个branch的函数签名,但使用另一个branch的实现。
5. 标记为已解决。 对结果满意后,将文件标记为已解决,然后继续处理下一个冲突文件。当所有文件都解决后,你就可以完成merge了。
关键优势在于你永远不会失去上下文。你始终可以看到任何branch触碰之前代码的样子、每个branch改变了什么,以及最终结果将是什么。这种清晰度消除了merge冲突带来的大部分焦虑。
避免merge冲突的技巧
即使有好的工具,从一开始就预防冲突总是比解决冲突更好。以下是一些有帮助的实用习惯:
- 经常pull。 你越久不整合主branch的更改,你的代码就越偏离队友的工作。定期pull可以保持差距较小,减少编辑重叠的可能性。
- 保持branch短期存在。 存在两周的feature branch比只存在两天的积累了更多的潜在冲突。将大功能拆分为更小的、可merge的增量。
- 与团队沟通。 如果两个人需要在同一个文件或模块上工作,提前打个招呼可以节省之后的时间。协调不必正式,一条简短的消息通常就够了。
- 使用feature flags。 与其为尚未准备好发布的功能维护一个长期branch,不如在feature flag后面进行merge。代码持续集成,但功能保持隐藏直到完成。
merge冲突是正常的
merge冲突并不是出了问题的信号。它们是多人在同一代码库上工作的自然结果,而这正是版本控制系统被设计来支持的。令人沮丧的体验和顺畅的体验之间的区别,通常取决于你使用的工具。
可视化的3-way merge编辑器消除了猜测。你不再需要在文本编辑器中解读冲突标记,而是看到代码的每个版本,选择合理的解决方案,然后继续前进。使用GitSquid内置的merge编辑器,解决冲突变成了工作流程的一部分,而不是让人害怕的事情。