成功的 Git 分支模型

成功的 Git 分支模型

技术之外 3年前 2315 0

最近项目开始做大起来了,需要团队协作。由于之前一直是在 master 分支上开发,现在项目新增人手,就需要换个方案了。找了挺多资料的,发现有篇讲的比较全。就转发翻译了一下。

原文:A successful Git branching model

反思笔记(2020年3月5日)

这个模型是在 2010 年构思出来的,而现在距今已有 10 多年的历史,而 Git 本身才诞生不久。在那 10 年中,git-flow「本文介绍的分支模型」在许多软件团队中非常流行,以至于人们开始将其视为某种标准,但不幸的是,它也被当作教条或灵丹妙药。

在那 10 年中,Git 本身就席卷了整个世界,并且与 Git 一起开发的最流行的软件类型正在越来越多地转向 Web 应用程序-至少在我的过滤泡中。 Web 应用程序通常是连续交付的,不会回滚,并且您不必支持在野外运行的软件的多个版本。

这不是我十年前写博客时想到的那种软件。如果您的团队正在持续交付软件,我建议您采用更简单的工作流程「例如 GitHub Flow」,而不是尝试将 git-flow 引入您的团队。

但是,如果您正在构建显式版本的软件,或者如果您需要狂野地支持软件的多个版本,那么git-flow 仍然可能像适合您团队的人一样适合您的团队最近 10 年。在这种情况下,请继续阅读。

总而言之,请始终记住万灵药不存在。考虑您自己的情况。别讨厌自己决定。

在这篇文章中,我介绍了大约一年前我为我的一些项目「在工作中和在私人项目中」引入的开发模型,事实证明该模型非常成功。我一直想写一阵子,但是直到现在为止我还没有真正找到时间这样做。我不会谈论任何项目的详细信息,而只会谈论分支策略和发布管理。

大图

为什么是 git?

有关 Git 与集中式源代码控制系统相比的优缺点的详尽讨论,请参见 Web。那里发生了许多火焰大战。作为开发人员,我比今天所有其他工具都更喜欢Git。 Git 确实改变了开发人员对合并和分支的看法。在我来自经典的CVS / Subversion 的世界中,合并/分支一直被认为有点吓人「当心合并冲突,它们会伤害你!」,而您却偶尔会做一次。

但是,使用Git,这些操作非常容易且简单,实际上,它们被视为日常工作流程的核心部分之一。例如,在CVS / Subversion 书籍中,分支和合并首先在后面的章节中(针对高级用户)进行讨论,而在每本 Git 书籍中,第3章(基础知识)都已经进行了介绍。

由于其简单性和重复性,分支和合并不再是令人害怕的事情。版本控制工具应该比其他任何工具都更有助于分支/合并。

有关这些工具的足够多的知识,让我们进入开发模型。我将在此处介绍的模型本质上不过是每个团队成员必须遵循的一组程序才能进入托管软件开发过程。

分散但集中

我们使用的存储库设置与该分支模型一起很好地使用,它是一个中央「真实」存储库。请注意,此存储库仅被视为中央存储库「由于 Git 是 DVCS,因此在技术层面上没有中央存储库之类的东西」。我们将此仓库称为起源,因为所有 Git 用户都熟悉该名称。

git

每个开发人员都拉起并推到原点。但是,除了集中的推拉关系之外,每个开发人员还可以从其他同伴那里拉出变更以组成子团队。例如,在将进行中的工作过早地推向市场之前,与两个或多个开发人员一起使用一项重大的新功能可能会很有用。在上图中,有 Alice 和 Bob,Alice 和David 以及 Clair 和 David 的子团队。

从技术上讲,这仅意味着 Alice 定义了一个名为 bob 的 Git 遥控器,该遥控器指向 Bob 的存储库,反之亦然。

主要分支

main-branches@2x.png

从根本上说,开发模型受到了现有模型的极大启发。中央存储库包含两个无限生命的主要分支:

  • master
  • develop

每个 Git 用户都应该熟悉原始的 master 分支。与 master 分支平行,存在另一个分支称为develop。

我们认为 origin/develop 是 HEAD 源代码始终反映状态的主要分支,该状态具有下一发行版的最新交付开发更改。有人将其称为「整合分支」。这是构建任何夜间自动构建的地方。

当 develop 分支中的源代码达到稳定点并准备发布时,所有更改应以某种方式合并回 master,然后用发布号标记。如何进行详细的讨论将在后面进行讨论。

因此,每次将更改合并回主版本时,根据定义,这是一个新的生产版本。我们通常对此非常严格,因此从理论上讲,每当主服务器上有提交时,我们就可以使用 Git 钩子脚本自动将软件构建和推出到生产服务器。

分支行

除了主要分支机构的掌握和开发之外,我们的开发模型还使用各种支持分支机构,以帮助团队成员之间进行并行开发,简化功能跟踪,为生产发布做准备并协助快速解决生产中的实际问题。与主要分支不同,这些分支的生命周期总是有限的,因为它们最终将被删除。

我们可以使用的不同类型的分支机构是:

  • 功能分支
  • 发布分支
  • 修补程序分支

这些分支中的每一个都有特定的用途,并受严格的规则约束,即哪些分支可能是其原始分支,哪些分支必须是其合并目标。我们将在一分钟内逐步解决它们。

从技术的角度来看,这些分支绝不是「特殊的」。分支类型是根据我们的使用方式进行分类的。它们当然是普通的旧 Git 分支。

功能分支

fb@2x.png

可能从以下分支:   develop 必须合并回:   develop 分支命名约定:   除了master,develop,release- 或 hotfix- 以外的任何东西

功能分支「或有时称为主题分支」用于为即将发布或遥远的将来版本开发新功能。当开始开发功能时,此时可能不知道将合并该功能的目标版本。功能分支的本质是只要功能在开发中就存在,但是最终会合并回到开发中「以确保将新功能添加到即将发布的版本中」或丢弃「以防实验令人失望」。 功能分支通常仅存在于开发人员存储库中,而不存在于源中。

创建功能分支

当开始使用新功能时,请从 develop 分支中分支出来。

$ git checkout -b myfeature develop
切换到新的分支 「myfeature」

在开发中加入完成的功能

可以将完成的功能合并到 developer 分支中,以确保将它们添加到即将发布的版本中:

$ git checkout develop
切换到分支 「develop」
$ git merge --no-ff myfeature
更新 ea1b82a..05e9557 「变更摘要」
$ git branch -d myfeature
已删除分支 myfeature「之前是05e9557」
$ git push origin develop

--no-ff 标志使合并始终创建一个新的提交对象,即使合并可以通过快进来执行。这样可以避免丢失有关要素分支历史存在的信息,并将所有添加了要素的提交分组在一起。比较: 比较图片 在后一种情况下,无法从 Git 历史记录中看到哪些提交对象一起实现了功能—您将不得不手动读取所有日志消息。在后一种情况下,还原整个功能「即一组提交」确实很头疼,而如果使用 --no-ff 标志则很容易做到。

是的,它将创建更多「空」提交对象,但收益远大于成本。

发布分支

可能从以下分支:   develop 必须合并回:   develop 和 master 分支命名约定:   release-*

发布分支支持新产品版本的准备。他们允许最后一刻对细节一丝不苟。此外,它们允许进行较小的错误修复并为发布准备元数据「版本号,构建日期等」。通过在发行分支上完成所有这些工作,将清除 develop 分支以接收下一个大型发行版的功能。

从 develop 分支出新版本分支的关键时刻是 develop「几乎」何时反映新版本的所需状态。此时至少必须合并要构建的发行版的所有功能。面向将来发行版的所有功能可能都不会—它们必须等到发行分支分支出来之后。

正是在发行分支的开头,为即将发布的版本分配了版本号-较早的版本。直到那一刻,develop 分支都反映了「下一个发行版」的更改,但是尚不清楚该「下一个发行版」最终将变为 0.3 还是1.0,直到发行分支开始。该决定是在发布分支的开始时做出的,并且由项目的版本号增加规则来执行。

创建一个发布分支

发布分支是从开发分支创建的。例如,说版本 1.1.5 是当前的生产版本,我们即将发布一个大版本。开发状态已准备就绪,可用于「下一个发行版」,我们已经决定将其变成 1.2 版「而不是1.1.6或2.0版」。因此,我们分支并给发行分支起一个反映新版本号的名称:

$ git checkout -b release-1.2 develop
选择一个新分支 「release-1.2」
$ ./bump-version.sh 1.2
文件修改成功,版本升至1.2。
$ git commit -a -m "将版本提高至 1.2"
[release-1.2 74d9424] 将版本号推送到 1.2
1 files changed, 1 insertions(+), 1 deletions(-)

创建新分支并切换到该分支后,我们更改版本号。在这里,bump-version.sh 是一个虚构的shell 脚本,它会更改工作副本中的某些文件以反映新版本。 「当然,这可以是手动更改-关键是某些文件会更改。」然后,提交被修改的版本号。

这个新分支可能在那里存在了一段时间,直到可以肯定地发布该版本为止。在此期间,错误修复程序可能会应用于此分支「而不是develop分支」。严格禁止在此处添加大型新功能。必须将它们合并到开发中,因此,请等待下一个重要版本。

完成发布分支

当发布分支的状态准备好成为真实发布时,需要执行一些操作。首先,将release分支合并到master中「记住,由于 master 上的每次提交都是新的发行,请记住」。接下来,必须标记对主提交的提交,以便将来轻松参考此历史版本。最后,需要将对发行分支所做的更改重新合并到开发中,以便将来的发行版也包含这些错误修复程序。

Git 的前两个步骤:

$ git checkout master
切换到 'master'
$ git merge --no-ff release-1.2
递归合并「更改摘要」
$ git tag -a 1.2

该版本现已完成,并已标记以供将来参考。

编辑:您也可能希望使用-s或-u 标志以加密方式对标签进行签名。

为了保留在 release 分支中所做的更改,我们需要将这些更改重新合并到 develop 中。在Git中:

$ git checkout develop
切换 'develop'
$ git merge --no-ff release-1.2
递归合并「更改摘要」

此步骤很可能导致合并冲突「因为我们已经更改了版本号」。如果是这样,请修复它并提交。 现在我们已经完成了,并且释放分支可能已删除,因为我们不再需要它了:

$ git branch -d release-1.2
删除了分支版本1.2「为 ff452fe」

修补程序分支

hotfix-branches@2x.png

可能从以下分支:   master 必须合并回:   develop 和 master 分支命名约定:   hotfix-*

修补程序分支与发布分支非常相似,尽管它们是计划外的,但它们也旨在为新的生产版本做准备。它们源于对不期望的实时生产版本立即采取行动的必要性。当必须立即解决生产版本中的严重错误时,可以从标记生产版本的 master 分支上的相应标记中分支出一个修补程序分支。

实质是团队成员的工作(在 develop 分支)可以继续,而另一个人正在准备快速的生产修复。

创建修补程序分支

修补程序分支是从 master 分支创建的。例如,说 1.2 版是当前的生产版本,正在运行,并且由于严重的错误而引起麻烦。但是发展的变化还不稳定。然后,我们可能会分支出一个修补程序分支并开始解决问题:

$ git checkout -b hotfix-1.2.1 master
切换到新的分支 「hotfix-1.2.1」
$ ./bump-version.sh 1.2.1
文件修改成功,版本升至1.2.1。
$ git commit -a -m "Bumped version number to 1.2.1"
[hotfix-1.2.1 41e61bb] 将版本号推送到1.2.1
1 files changed, 1 insertions(+), 1 deletions(-)

别忘了在分支后增加版本号!

然后,修复该错误,并在一个或多个单独的提交中提交此修复程序。

$ git commit -m "Fixed severe production problem"
[hotfix-1.2.1 abbe5d6] 解决了严重的生产问题
5 files changed, 32 insertions(+), 17 deletions(-)

完成修补程序分支

完成后,该错误修复程序需要重新合并到母版中,但也需要重新合并到开发中,以保护该错误修复程序也包含在下一个版本中。这与释放分支的完成方式完全相似。

首先,更新 master 并标记发行版。

$ git checkout master
切换到 'master'
$ git merge --no-ff hotfix-1.2.1
递归合并「更改摘要」
$ git tag -a 1.2.1

编辑:您也可能希望使用-s或-u 标志以加密方式对标签进行签名。

接下来,在 develop 分支中也包含错误修正:

$ git checkout develop
切换到 'develop'
$ git merge --no-ff hotfix-1.2.1
递归合并「更改摘要」

该规则的一个例外是,当当前存在发行分支时,需要将修补程序更改合并到该发行分支中,而不是进行开发。在发行分支完成后,将错误修正回合并到发行分支中,最终也会导致该修正修正也被合并到开发中。 「如果开发人员中的工作立即需要此错误修复,而不能等待发布分支完成,则现在也可以安全地将错误修复合并到开发中。」

最后,删除临时分支:

$ git branch -d hotfix-1.2.1
删除了分支修补程序 1.2.1「为 abbe5d6」

总结

尽管该分支模型没有什么真正令人震惊的新东西,但这篇文章开头的「大图」图在我们的项目中被证明是非常有用的。它形成了一个易于理解的优雅思维模型,并允许团队成员对分支和发布过程形成共识。

原文: http://yiqiao.me/articles/28/successful-git-branching-model

版权声明: 自由转载-非商用-非衍生-保持署名 (创意共享3.0许可证)