写点什么

Git 进阶系列 | 4. 合并冲突

作者:俞凡
  • 2022 年 5 月 03 日
  • 本文字数:2619 字

    阅读完需:约 9 分钟

Git 是最流行的代码版本控制系统,这一系列文章介绍了一些 Git 的高阶使用方式,从而帮助我们可以更好的利用 Git 的能力。本系列一共 8 篇文章,这是第 4 篇。原文:Merge Conflicts: What They Are and How to Deal with Them[1]


合并冲突……没有人会喜欢,有些人甚至害怕冲突。但是使用 Git 时,特别是需要与其他开发人员合作时,冲突是不可避免的。大多数情况下,合并冲突并不像想象的那么可怕。在“Git 进阶”系列的第四部分中,我们将讨论冲突何时会发生,实际是什么,以及如何解决。


Git 进阶系列:

  1. 创建完美的提交

  2. Git中的分支策略

  3. 基于Pull Request实现更好的协作

  4. 合并冲突(本文)

  5. Rebase vs Merge

  6. 交互式 Rebase

  7. Git 中的 Cherry-pick 提交

  8. 用 Reflog 恢复丢失的提交

何时以及为什么会发生合并冲突


从名称就可以看出来: 将来自不同来源的更改集成(或“合并”)到当前工作分支时,就可能会发生合并冲突。请记住,集成并不局限于合并分支。冲突也可能发生在 rebase 或交互式 rebase 过程中、在 cherry-pick(从一个分支选择某个提交应用到另一个分支)过程中、在执行git pull时,甚至在重新加载暂存区的内容时。


所有这些操作都执行某种类型的集成,这就是合并冲突可能发生的时候。当然,并不意味着这些操作每次都会导致合并冲突,那么到底什么时候会发生冲突呢?

实际上,Git 的合并功能是其最大的优势之一: 分支合并在大多数时候都能完美工作,Git 通常能自己解决问题,知道如何集成变更。



但也有发生了相互矛盾的变化的情况,那时候技术根本无法决定什么是对的,什么是错的,这时就需要人类做出决定。例如,当同一行代码在两个不同分支的两次提交中被更改时,Git 无法知道哪一次更改才是对的。另一种不太常见的情况是,一个文件在一个分支中被修改,而在另一个分支中被删除了。Git 会问你该做什么,而不是猜测该怎么做。


怎样才能知道何时发生了合并冲突


那么,如何才能知道发生了合并冲突?不用担心,如果合并或 rebase 失败,Git 会立即告诉我们,也会对如何解决这个问题提出建议。例如,如果提交的更改与其他人的更改发生了冲突,Git 会在终端通知我们,并告诉我们自动合并失败了:

$ git merge developCONFLICT (content): Merge conflict in index.htmlAutomatic merge failed; fix conflicts and then commit the result.
复制代码


可以看到,这里发生了一次冲突,Git 立即报告了问题。即使错过这条消息,也会在下次输入git status时提示有冲突。



如果使用的是 Tower 这样的 Git 桌面 GUI,会确保不会忽略任何冲突:


在任何情况下都不用担心没有注意到合并冲突!

如何撤销合并冲突并重新开始


不能忽略合并冲突,相反,必须在继续工作之前处理,基本上有以下两种选择:

  • 解决冲突

  • 中止或撤销导致冲突的操作


在开始解决冲突之前,我们简要谈谈如何撤消和重新开始(知道有可能恢复,就让人非常放心)。在很多情况下,只需要简单添加--abort参数,比方说git merge --abortgit rebase --abort,这个命令可以撤消合并/rebase 并恢复到冲突发生之前的状态。


当我们解决冲突时,即使发现自己进入了死胡同,仍然可以撤消合并。这可以给我们信心,真的不会搞砸,我们总是可以中止,返回到干净的状态,然后重新开始。

Git 中的合并冲突到底是什么样的


让我们看看真正的冲突是什么样的。是时候揭开这些小东西的神秘面纱,更好的了解它们了。一旦理解了合并冲突,就没什么可担心的了。


看看当前存在冲突的index.html文件的内容:


Git 很好的标记了文件中有问题的区域,通过<<<<<<<和>>>>>>>包围。第一个标记之后的内容来自我们当前的工作分支(HEAD),七个等号(=======)的行分隔了两个冲突的更改,后面的内容显示来自另一个分支的更改(在例子里是develop)。


我们的工作是清理这些行并解决冲突,无论是通过文本编辑器、IDE、Git 桌面 GUI,或者通过 Diff & Merge 工具。

如何解决 Git 冲突


使用哪种工具或应用程序来解决合并冲突并不重要,当完成合并后,文件看起来必须与期望的完全一样。如果只有你一个人,可以很容易决定放弃哪些更改。但是,如果有冲突的更改来自其他人,可能必须在决定保留哪些代码之前与他们进行交谈。也许保留你的,也许保留别人的,也许是这两者的结合。


清理文件并确保包含真正想要的内容的过程并不需要任何魔法,可以简单的通过打开文本编辑器或 IDE 并进行更改来做到这一点。


然而,有时这并不是最有效的方法,专用工具也许可以节省更多时间和精力。例如,在解决合并冲突时,可以利用各种各样的 Git 桌面 GUI。


以 Tower 为例,它提供了一个专用的“冲突向导”,从而使本来抽象的情况更加直观,有助于更好的理解变化来自哪里,发生了什么类型的修改,并最终解决问题:


特别是对于更复杂的冲突,手头有一个专用的 Diff & Merge 工具是很好的,通过高级功能,如特殊格式和不同的表示模式(例如并排,合并在一个列中,等等),可以帮助我们更好的理解差异。


市面上有一些 Diff & Merge 工具[2][3],可以通过git config命令配置所选择的工具(详细说明请参考工具),在冲突发生时,可以通过简单的输入git mergetool来调用。举个例子,我在自己的 Mac 上使用 Kaleidoscope:


在清理完文件后(无论是通过文本编辑器、Git 桌面 GUI,还是使用 Merge Tool),可以像提交其他更改一样提交文件。输入git add <filename>,通知 git 冲突已经解决。


当解决了所有合并冲突并添加到暂存区(Staging Area)后,只需创建一个常规提交,这就完事儿了。

Don’t panic!


如你所见,合并冲突这件事没有什么需要担心的,当然也没有理由恐慌。一旦了解了为什么发生冲突,就可以决定是撤消更改还是解决冲突。记住,并不会产生什么破坏性后果,即使在解决冲突时意识到自己犯了错,仍然可以撤销,只需要回滚到犯错之前的提交,然后重新开始。


如果想更深入了解高级 Git 工具,可以免费查看“Advanced Git Kit[3]”: 这是关于分支策略、交互式 Rebase、Reflog、子模块等主题的短视频集合。


References:

[1] Merge Conflicts: What They Are and How to Deal with Them: https://css-tricks.com/merge-conflicts-what-they-are-and-how-to-deal-with-them/

[2] Diff tools for Mac: https://www.git-tower.com/blog/diff-tools-mac/

[3] Diff tools for Windows: https://www.git-tower.com/blog/diff-tools-windows/


你好,我是俞凡,在 Motorola 做过研发,现在在 Mavenir 做技术工作,对通信、网络、后端架构、云原生、DevOps、CICD、区块链、AI 等技术始终保持着浓厚的兴趣,平时喜欢阅读、思考,相信持续学习、终身成长,欢迎一起交流学习。

微信公众号:DeepNoMind

发布于: 刚刚阅读数: 3
用户头像

俞凡

关注

公众号:DeepNoMind 2017.10.18 加入

俞凡,Mavenir Systems研发总监,关注高可用架构、高性能服务、5G、人工智能、区块链、DevOps、Agile等。公众号:DeepNoMind

评论

发布
暂无评论
Git进阶系列 | 4. 合并冲突_git_俞凡_InfoQ写作社区