前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >猫头鹰的深夜翻译:开发者必须了解的分支发布模型

猫头鹰的深夜翻译:开发者必须了解的分支发布模型

作者头像
眯眯眼的猫头鹰
发布2019-11-08 17:44:59
5470
发布2019-11-08 17:44:59
举报
文章被收录于专栏:眯眯眼猫头鹰的小树杈

前沿

本文只会聚焦于分支发布策略,不会涉及任何的项目细节。

为什么选择Git

想要深入了解Git和中心化代码版本管理系统的优缺点比较,可以在网上自行查询,这个话题一直争论不休。作为一个开发者,我更倾向于使用Git。Git确实改变了开发者对代码合并和分支管理的认识。作为一个使用过传统的CVS工具的人,合并/开分支是一个比较恐怖的行为,迫不得已才执行一次。

但是,Git的分支合并和创建操作就非常简单,这些操作已经被是为每日工作流的一部分。比如,在介绍CVS的书本中,分支和合并只会在末尾的章节面向高端开发者介绍一下,而在每一本说Git的书中,基本上在第三章就会说明。

因为Git在这个操作上的简洁性和重复性特性,分支开发和合并不再是一件可怕的事情。版本控制工具本就应当更好的帮助分支的创建和合并。

不谈工具,接着要介绍开发模型。今天我要介绍的这个模型本质上是一组流程,每个团队成员通过遵循这一组流程来管理软件开发过程。

去中心化又中心化

在分支发布模型中,我们会设置一个中心化的“真理”仓库。这个仓库只是名义上的中心仓库(因为Git是一个去中心化的仓库,因此从技术角度上来说这个仓库不是中心化的)。我们将该仓库标记为origin,因为origin这个命名对于所有的Git用户来说都是很熟悉的。

每个开发者从origin拉取和上传代码。每个开发者之间也可以从彼此的代码仓库拉取或构件子代码团队。这种方式适用于大型团队,即子团队可以先在一个团队分支上进行特性开发,在特性稳定后再提交到origin仓库。

主分支

中央仓库持有两个拥有永久生命周期的分支:master和develop origin仓库中的master主分支对每个Git用户都是再熟悉不过的了。和master分支平齐的分支称为develop开发分支。

origin/master分支是项目的主分支,源代码的HEAD标签永远指向了该分支上的一个可发布版本。

我们将origin/develop分支是为另一种类型的主分支,该分支上的代码始终处于一个稳定的可发布的状态。该分支上的所有变更都应当被合并到master分支上,并搭上一个发布标签。具体的操作将在后文详细描述。

因此,每当变更被合并到master分支上时,都意味着释放了一个新的发布版本。我们严格的遵循这一定义,因此理论上来说,每当有一个代码提交至master分支上,我们应当使用Git钩子来自动构建和发布代码到生产环境服务器。

辅助分支

在主分支master和develop之外,开发过程模型还使用了各种辅助分支来实现团队成员间的并行开发,简化功能开发,做生产发布的准备工作和快速修复生产环境的故障。和主分支不同,这些分支都有着一定的生命周期,因为他们最终都会被删除。

辅助分支的类型包括:

  • 特性分支 Feature Branch
  • 发布分支 Release Branch
  • 修复分支 Hotfix Branch

每一类分支都有着特定的目标,并且受限于不同的约束,比如该类分支应当从哪类分支中生成,最终合并到哪类分支中去。

但是这些分支从Git的角度上来说并无区别,它们就是通常意义的Git Branch,只是我们赋予了他们不同的使用语义。

特性分支 Feature Branch

来源分支:develop开发分支 合并分支:develop开发分支 分支命名规范:master, develop, release-, 和 hotfix

特性分支是为了支持未来上线的新功能来进行开发分支。在开始特性分支开发时,对应的未来的发布分支可能是未知的。特性分支的精髓在于只要该特性还在开发中,该分支就会一直存在,并会最终合并回develop开发分支(确定该特性会被发布)或是被抛弃(特性的开发结果没有达到预期)。

特性分支一般只存在于开发者的仓库中。

创建特性分支
代码语言:javascript
复制
$ git checkout -b myfeature develop
Switched to a new branch "myfeature"
合并开发完成的特性分支到develop分支中
代码语言:javascript
复制
$ git checkout develop
Switched to branch 'develop'
$ git merge --no-ff myfeature
Updating ea1b82a..05e9557
(Summary of changes)
$ git branch -d myfeature
Deleted branch myfeature (was 05e9557).
$ git push origin develop

--no-ff标签使得合并操作创建一个新的提交记录,即使该合并可以被fast-forward快速合并到目标分支中。这种方式避免了所有在feature分支上的历史提交记录的丢失。对比如下:

右图中无法从Git提交历史中看出来哪些提交记录构成了feature分支,你需要手动阅读所有的日志消息。回滚特性代码在右图中是一件非常麻烦的事情,但是通过--no-ff合并的左图中就比较容易。虽然它会创建更多的提交记录,但是总的来说优点大于缺点。

发布分支 Release Feature

来源分支:develop开发分支 合并分支:develop开发分支和master主分支 分支命名规范:release-*

发布分支支持为一个新的生产环境发布做准备。它允许在上线之前进行最后的操作。除此以外,它允许小的bug修复和发布前的元数据准备操作(版本号,构建日期等)。通过在发布分支上做这些事情,开发分支变得更加简洁,只需要接收未来会发布的新特性。

当开发分支基本达到了发布一个新版本的状态时,需要从开发分支创建一个新的发布分支。所有满足发布条件的特性分支此时必须已经被合并到开发分支中。而尚未达到发布条件的特性分支无需合并到master分支,它们必须等到发布分支生命周期结束后才能合并到开发分支上。

在创建发布分支时,会为本次发布定义一个版本号(不会早于此)。直到这一刻,用于下一次发布的开发分支才知道自己下一次的发布版本号为0.3还是1.0。在发布分支创建时会按照版本号的演进规则决定本次发布的版本号。

创建发布分支

发布分支创建于开发分支。比如,假设当前生产环境的版本号为1.1.5,并且接着会有一个重大的发布。此时开发分支已经达到了下一次发布的要求,并且我们决定该版本为1.2(不是1.1.6或是2.0)。因粗我们创建分支并且在发布分支的命名中带上了新的版本号:

代码语言:javascript
复制
$ git checkout -b release-1.2 develop
Switched to a new branch "release-1.2"
$ ./bump-version.sh 1.2
Files modified successfully, version bumped to 1.2.
$ git commit -a -m "Bumped version number to 1.2"
[release-1.2 74d9424] Bumped version number to 1.2
1 files changed, 1 insertions(+), 1 deletions(-)

在创建了新的分支并切换到该分支上后,我们开始切换版本号。在此处,bump-version.sh是一个虚拟的shell脚本,它会在发布版本文件上执行一些版本操作(当然了这些操作可以通过手动完成)。接着,版本操作被提交。

这个新分支会存在一段时间,直到发布被完全执行。在此期间,可以在分支上修复bug(而非develop分支上),但是禁止添加大的新特性。它们必须先被合并到开发分支,然后等待下一个发布节点。

结束发布分支

当发布分支确实可以发布时,在此之前需要执行一些操作。首先,发布分支被合并到master分支上。接着,提交到master分支上的代码必须打上标签,从而在未来可以引用该历史版本。最后,发布分支上的代码必须被合并会开发分支,使得开发分支上的代码也包含了发布版本的内容以及修复的bug。

代码语言:javascript
复制
$ git checkout master
Switched to branch 'master'
$ git merge --no-ff release-1.2
Merge made by recursive.
(Summary of changes)
$ git tag -a 1.2

此时发布已经完成,并且打上了标签以便引用。 接着将变更合并会develop分支:

代码语言:javascript
复制
$ git checkout develop
Switched to branch 'develop'
$ git merge --no-ff release-1.2
Merge made by recursive.
(Summary of changes)

这一步合并操作可能会存在冲突,需要解决冲突并提交。 在这些都完成后,我们可以删除掉发布分支,因为我们不再需要该分支了:

代码语言:javascript
复制
$ git branch -d release-1.2
Deleted branch release-1.2 (was ff452fe).

修复分支 Hotfix Branch

来源分支:master主分支 合并分支:develop开发分支和master主分支 分支命名规范:hotfix-*

修复分支和发布分支很接近,因为它们都是为了生产环境发布做准备的一个分支。修复分支产生的缘由在于需要立刻对生产环境中的代码进行快速变更。当生产环境版本代码出现重大bug需要立刻处理时,可以从对应版本的生产环境代码拉一个修复分支进行处理。

该分支的核心点在于团队的其他成员可以继续基于开发分支进行开发,而负责修复的成员可以独立的快速修复生产环境问题。

创建修复分支

修复分支创建于master分支。比如版本1.2是当前正在运行的生产环境版本,并且因为一个缺陷出现了故障。但是开发分支上的代码尚不稳定。我们需要创建修复分支并开始修复问题:

代码语言:javascript
复制
$ git checkout -b hotfix-1.2.1 master
Switched to a new branch "hotfix-1.2.1"
$ ./bump-version.sh 1.2.1
Files modified successfully, version bumped to 1.2.1.
$ git commit -a -m "Bumped version number to 1.2.1"
[hotfix-1.2.1 41e61bb] Bumped version number to 1.2.1
1 files changed, 1 insertions(+), 1 deletions(-)

切换新的发布版本后不要忘了切换代码中的版本号 接着在一次或多次提交的代码中修复问题。

代码语言:javascript
复制
$ git commit -m "Fixed severe production problem"
[hotfix-1.2.1 abbe5d6] Fixed severe production problem
5 files changed, 32 insertions(+), 17 deletions(-)
关闭修复分支

修复完毕后,修复分支需要合并会主分支,也需要合并回开发分支,从而确保该修复包含在下次发布代码中。这与发布分支的关闭过程完全相同。 首先,更新master代码的标签并发布:

代码语言:javascript
复制
$ git checkout master
Switched to branch 'master'
$ git merge --no-ff hotfix-1.2.1
Merge made by recursive.
(Summary of changes)
$ git tag -a 1.2.1

接着将代码合并回开发分支:

代码语言:javascript
复制
$ git checkout develop
Switched to branch 'develop'
$ git merge --no-ff hotfix-1.2.1
Merge made by recursive.
(Summary of changes)

这里一个特殊点在于,如果此时存在一个发布分支,修复分支的变更需要合并到发布分支中,而非开发分支。合并到发布分支中,可以最终将该修复通过发布分支带回到开发分支中。(如果开发分支也需要立刻修复该问题,无法等到发布分支合并回来,也可以先将该变更安全的合并会发布分支)

代码语言:javascript
复制
$ git branch -d hotfix-1.2.1
Deleted branch hotfix-1.2.1 (was abbe5d6).
本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 前沿
  • 为什么选择Git
  • 去中心化又中心化
  • 主分支
  • 辅助分支
    • 特性分支 Feature Branch
      • 创建特性分支
      • 合并开发完成的特性分支到develop分支中
    • 发布分支 Release Feature
      • 创建发布分支
      • 结束发布分支
    • 修复分支 Hotfix Branch
      • 创建修复分支
      • 关闭修复分支
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档