yuff100

V1

2022/05/03阅读:55主题:极简黑

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

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 develop
CONFLICT (content): Merge conflict in index.html
Automatic 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

- END -

分类:

后端

标签:

Git

作者介绍

yuff100
V1

俞凡,公众号DeepNoMind