共计 3025 个字符,预计需要花费 8 分钟才能阅读完成。
Git 是最风行的代码版本控制系统,这一系列文章介绍了一些 Git 的高阶应用形式,从而帮忙咱们能够更好的利用 Git 的能力。本系列一共 8 篇文章,这是第 5 篇。原文:Rebase vs. Merge: Integrating Changes in Git[1]
大多数开发人员都了解在 Git 中应用分支的重要性,事实上,本系列曾经有一篇对于 Git 分支策略的文章,解释了 Git 弱小的分支模型、不同类型的分支以及两种最常见的分支工作流。总而言之,在独立的容器中工作(即分支),是十分有用的,也是应用版本控制系统的次要起因之一。
本文咱们将钻研如何集成分支,如何将新代码增加回现有的开发线路中?有不同的办法能够实现这一点。在这篇“Git 进阶”系列的第五局部咱们要探讨 Git 中的集成更改,即合并和 rebase。
在咱们深刻细节之前,重要的是要了解这两个命令,git merge
和 git rebase
。它们解决了雷同的问题,行将一个 Git 分支的更改集成到另一个分支,只是做法稍有不同。上面咱们从git merge
开始。
Git 进阶系列:
- 创立完满的提交
- Git 中的分支策略
- 基于 Pull Request 实现更好的合作
- 合并抵触
- Rebase vs Merge(本文)
- 交互式 Rebase
- Git 中的 Cherry-pick 提交
- 用 Reflog 复原失落的提交
了解合并
要将一个分支合并到另一个分支,能够应用 git merge
命令。假如在 ranch-B
上有一些新提交,当初咱们想把这个分支合并到另一个分支 branch-A
中。为此,能够这样输出:
$ git checkout branch-A
$ git merge branch-B
如此,Git 会在当前工作分支 (本例中为branch-A
) 中创立一个新的合并提交,连贯两个分支的历史记录。为了实现这个工作,Git 须要查找三个提交:
- 第一个是“公共先人提交(common ancestor commit)”。如果跟踪一个我的项目中两个分支的历史,总是至多有一个公共提交。此时,两个分支具备雷同的内容。在那之后,就向不同方向进化。
- 另外两个乏味的提交是每个分支的端点,即它们的以后状态。请记住,集成的目标是组合两个分支的以后状态。因而,他们的最新订正当然很重要。
联合这三个提交能够执行咱们想要的集成。
无可否认,这是一个简化场景,两个分支中的一个 (branch-A
) 自创立以来没有任何新的提交,这在大多数软件我的项目中是不太可能的。因而,它在本例中的最初一次提交也是 公共先人(common ancestor)。
在这种状况下,集成非常简单,Git 能够将所有来自 branch-B
的新提交增加到公共先人提交之上。在 Git 中,这种最简略的集成模式称为“快进(fast-forward)”合并,而后两个分支共享完全相同的历史(并且不须要额定的“合并提交”)。
然而大多数状况下,两个分支将以不同的提交向前推动。咱们举一个更事实的例子:
为了集成,Git 必须创立一个蕴含所有更改的新提交,并留神分支之间的差别,这就是咱们所说的 合并提交(merge commit)。
人工提交和合并提交
通常状况下,提交是由人精心创立的,是一个有意义的单元,只蕴含相干的变更,以及包含了上下文和正文的有意义的提交信息。
当初,合并提交有点不一样,它不是由开发人员创立的,而是由 Git 主动创立的。而且,合并提交不肯定蕴含“相干更改的语义汇合”。相同,它的目标只是连贯两个 (或更多) 分支。
如果想理解这样的主动合并操作,必须查看所有分支的历史以及各自的提交历史。
Rebase 集成
在探讨 rebase 之前,先说分明一点: rebase 并不比合并更好或更差,只是不同而已。兴许你只须要通过合并集成分支,就能够实现工作,甚至不须要思考 rebase。不过,了解 rebase 是做什么的,并理解它的优缺点,的确很有帮忙。兴许你会在某个我的项目中遇到某个问题,而 rebase 恰好很有帮忙…
好吧,咱们开始!还记得刚刚讲的主动合并提交吗?有些人不太喜爱这些,宁愿不必。另外一些开发人员喜爱我的项目历史看起来像一条直线,没有任何迹象表明它在某个点上被分成了多个分支,即便这些分支曾经被集成了。这基本上就是 Git rebase 过程中产生的事件。
一步一步 rebase
让咱们逐渐介绍 rebase 操作。和后面的例子一样,一开始是这样的:
咱们想要将 branch-B
的更改集成到 branch-A
中,但这次是用 rebase,而不是合并。理论的 Git 命令非常简单:
$ git checkout branch-A
$ git rebase branch-B
相似于 git merge
命令,只须要通知 git 想要集成哪个分支。咱们来看看幕后故事……
第一步,Git 将“删除”产生在公共先人提交之后的所有对 branch-A
分支的提交。别放心,它们不会被抛弃,能够将这些提交视为被临时保留在一个平安的中央。
第二步,Git 利用来自 branch-B
的新提交。此时,两个分支临时看起来完全相同。
最初,集成那些“暂存”的提交 (来自branch-A
的新提交)。因为它们位于 branch-B
分支的顶部,所以是 rebase 的。
因而,我的项目历史看起来就像是在一条直线上进行开发,不存在蕴含所有合并更改的合并提交,并且保留了原始提交构造。
rebase 的潜在隐患
还有一件事对于了解 Git rebase 很重要,它重写了提交历史 。再看一下最初一张图表,提交C3*
带有星号,尽管 C3*
与C3
具备雷同的内容,但实际上是不同的提交。为什么?因为它在 rebase 之后有一个新的父提交。在 rebase 之前,C1
是父提交。在 rebase 之后,父提交是C4
,它被 rebase 到了C4
。
一个提交只有大量重要属性,比方作者、日期、变更集和父提交,更改任何这些信息都会创立一个全新的提交,有一个新的 SHA- 1 哈希 ID。
对于尚未公布的提交,这样重写历史记录不是问题。然而,如果正在重写的是曾经推送到远端代码库的提交,可能会遇到麻烦。兴许其他人的工作是基于最后的 C3 提交的,当初它忽然不存在了……
为了远离麻烦,这里有一个应用 rebase 的简略规定: 永远不要在公共分支上应用 rebase,比方说曾经被推送到远端代码库的提交!相同,只在将它集成到共享的团队分支之前,才应用 git rebase
来清理本地提交历史。
集成就是所有!
归根到底,merge 和 rebase 都是有用的 Git 策略,用哪个取决于想要实现的指标。合并是非破坏性的,因为合并不会扭转现有的历史。另一方面,rebase 能够通过防止不必要的合并提交来帮忙清理我的项目历史记录。只有记住不要在公共分支中这样做,从而防止烦扰其余开发人员。
如果想更深刻理解高级 Git 工具,能够收费查看“Advanced Git Kit[3]”: 这是对于分支策略、交互式 Rebase、Reflog、子模块等主题的短视频汇合。
References: \
[1] Rebase vs. Merge: Integrating Changes in Git: https://css-tricks.com/rebase-vs-merge-integrating-changes-in…你好,我是俞凡,在 Motorola 做过研发,当初在 Mavenir 做技术工作,对通信、网络、后端架构、云原生、DevOps、CICD、区块链、AI 等技术始终保持着浓重的趣味,平时喜爱浏览、思考,置信继续学习、一生成长,欢送一起交流学习。\
微信公众号:DeepNoMind
本文由 mdnice 多平台公布