Git 进阶系列 | 4. 合并冲突
Git 是最流行的代码版本控制系统,这一系列文章介绍了一些 Git 的高阶使用方式,从而帮助我们可以更好的利用 Git 的能力。本系列一共 8 篇文章,这是第 4 篇。原文:Merge Conflicts: What They Are and How to Deal with Them[1]
合并冲突……没有人会喜欢,有些人甚至害怕冲突。但是使用 Git 时,特别是需要与其他开发人员合作时,冲突是不可避免的。大多数情况下,合并冲突并不像想象的那么可怕。在“Git 进阶”系列的第四部分中,我们将讨论冲突何时会发生,实际是什么,以及如何解决。
Git 进阶系列:
合并冲突(本文)
Rebase vs Merge
交互式 Rebase
Git 中的 Cherry-pick 提交
用 Reflog 恢复丢失的提交
何时以及为什么会发生合并冲突
从名称就可以看出来: 将来自不同来源的更改集成(或“合并”)到当前工作分支时,就可能会发生合并冲突。请记住,集成并不局限于合并分支。冲突也可能发生在 rebase 或交互式 rebase 过程中、在 cherry-pick(从一个分支选择某个提交应用到另一个分支)过程中、在执行git pull
时,甚至在重新加载暂存区的内容时。
所有这些操作都执行某种类型的集成,这就是合并冲突可能发生的时候。当然,并不意味着这些操作每次都会导致合并冲突,那么到底什么时候会发生冲突呢?
实际上,Git 的合并功能是其最大的优势之一: 分支合并在大多数时候都能完美工作,Git 通常能自己解决问题,知道如何集成变更。
但也有发生了相互矛盾的变化的情况,那时候技术根本无法决定什么是对的,什么是错的,这时就需要人类做出决定。例如,当同一行代码在两个不同分支的两次提交中被更改时,Git 无法知道哪一次更改才是对的。另一种不太常见的情况是,一个文件在一个分支中被修改,而在另一个分支中被删除了。Git 会问你该做什么,而不是猜测该怎么做。
怎样才能知道何时发生了合并冲突
那么,如何才能知道发生了合并冲突?不用担心,如果合并或 rebase 失败,Git 会立即告诉我们,也会对如何解决这个问题提出建议。例如,如果提交的更改与其他人的更改发生了冲突,Git 会在终端通知我们,并告诉我们自动合并失败了:
可以看到,这里发生了一次冲突,Git 立即报告了问题。即使错过这条消息,也会在下次输入git status
时提示有冲突。
如果使用的是 Tower 这样的 Git 桌面 GUI,会确保不会忽略任何冲突:
在任何情况下都不用担心没有注意到合并冲突!
如何撤销合并冲突并重新开始
不能忽略合并冲突,相反,必须在继续工作之前处理,基本上有以下两种选择:
解决冲突
中止或撤销导致冲突的操作
在开始解决冲突之前,我们简要谈谈如何撤消和重新开始(知道有可能恢复,就让人非常放心)。在很多情况下,只需要简单添加--abort
参数,比方说git merge --abort
和git 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
版权声明: 本文为 InfoQ 作者【俞凡】的原创文章。
原文链接:【http://xie.infoq.cn/article/a7f74bc4417a0da94e8c33a91】。
本文遵守【CC-BY 4.0】协议,转载请保留原文出处及本版权声明。
评论