Git 分支策略模型

Git 分支策略模型

本系列,是自己学习Linux过程中的笔记。
希望读者在看完全文后,也能留下你们的经验或者问题。
如果能从这里学到点东西,记得请我喝杯☕☕☕~

—— MinRam

在整理自己项目Polaris Technology Radar的分支策略时,采照了当前商用级分支策略,写了些个人对这种分支模式的理解。
如果产品是处于持续交付策略,那么可能更适合GitHub flow的策略,不要试图将Git硬塞入你的产品团队
同时分支策略不是唯一固定的,我们需要适配产品需求。对于IT,没有万能钥匙存在。

一、前言 Overview

本文章仅描述我自己项目中的分支策略和发布管理。当我们选择分支策略时候,应考虑产品的迭代模式,团队的开发规模和开发方式等方面。

Polaris Technology Radar为例,该项目有如下几个信息:

  • 项目开发团队人数 2~10人
  • 项目代码规模小,满足单人开发条件
  • 项目发布流程涉及多种环境部署
  • 项目可能支持多个发布版本并存(正式版本/定制版本)
  • 团队开发模式为功能特性独立

二、为什么选择Git

Git作为一款版本控制系统VCS-Version Control System, 是开源项目不二的选择。让来自不同开发者的分支能够简单的对比/合并。

同样作为VCSSVN- Apache Subversion, 没法连接数据库就没法工作,同时SVN只能满足在少量开发者的场景下进行版本管控。

三、主分支 Main Branches

受开发模式影响,整个项目存在两个永存的分支: release & develop.

Main Branches

3.1 Release Branches

我们认为release为主分支,其中的代码始终满足发布状态,包含对下一版本要交付的功能特性代码。

该分支也是自动化构建的目标分支,只有该分支的代码,才会被发布到生产环境上。

3.2 Develop Branches

如名所示,develop分支是处于开发测试中的代码。

只有当代码变动趋于稳定后并准备发布的时候,所有代码变动会以某种方式合并到release分支中,并且标记版本号。

这一合并动作会在后面进一步详解。

所以,每次develop的代码变更,合并到master时,这就是一个针对生产环境的代码版本。

我们往往在这个合入动作(Pull Request)发生时,触发自动构建机制(DevOps, 如Git hook脚本)来构建我们的产品,并自动部署到生产环境上。

四、支持性分支 Supporting Branches

除了主分支(release & develop)的存在,依照我们开发模型,在整个分治策略中还有各种支持性分支,来协助团队成员进行并行开发,简化功能定位,以及为生产环境做准备。

有些分支也会协助开发者,快速修复实时生产环境上的问题。

与主分支的永久生命周期不一样,支持性分支的生命寿命是有限的,最终都会被删除。

对于这些支持性分支,大致包含以下几类:

  • 功能性分支
  • 发布性分支
  • 热补丁分支

这些分支都有明确的特定目标,并且遵循一定的原则。如只能从哪些分支上分叉出来,只能合入哪些分支。

Git的角度上看,这些分支没有任何区别,同样只是普通的代码分支,只是因为其目的特殊,所以有着特殊的含义。

4.1 特性分支 Feature Branches

feature branch

  • 根源分支: develop
  • 目标分支: develop
  • 分支命名规则: 一般以feature-*为命名规则,同时不包含release, develophotfix字样

功能分支,用于为即将发布的版本开发新功能。在开发该功能特性时,我们无法预估该功能最终会在哪个版本进行发布。但对于功能分支来说,只要功能还在开发,分支就一直存在。

对于该分支,它生命周期的终点,要么功能开发完成,合并入develop,准备发布。 要么因项目安排,功能被取消,最后直接删除分支。

功能分支,通常仅存在开发人员本地Git存储库中,不会存在远端代码仓库(origin)。

  • 创建功能分支

develop中创建。

1
2
$ git checkout -b feature/hello-world develop
Switched to new branch 'feature/hello-world'
  • 完成功能开发,合并代码变动:

在实际代码管理中,往往需要提交Pull Request,经过代码审查Review, 代码构建Build/Test来保证代码准确性。这里仅展示本地合并指令。

1
2
3
4
5
6
7
8
$ git checkout develop
Switched to branch 'develop'
$ git merge --no-ff feature/hello-world
Updating ea1b82a..05a893
(Summary of changes)
$ git branch -d feature/hello-world
Deleted branch feature/hello-world
$ git push origin develop

--no-ff 该参数, 用来避免丢失特性开发分支的整个提交链信息,同时创建新的代码提交信息。具体详见Git fast forward merge内容。

以下为两者简单对比:

fast forward

Pull Request中也有同样的选项。

4.2 发布分支 Release-* Branches

  • 根源分支: develop
  • 目标分支:develop/release
  • 分支命名规则: release-*

release-* branches是为下一版本的发布做准备。他是正式发布前的预先检查环节。不同于develop分支对应的测试环境,release-对应的环境,更符合生产环境的标准,且在release-分支上只允许补丁相关的变动。

  • 创建发布分支

release-*是从develop创建出来的。假设当前的生产版本为1.2, 而develop已经完成新版本1.3所有的功能特性,我们就可以从develop中分支出release-1.3

1
2
3
4
5
6
7
$ git checkout release-1.3 develop
Switched to branch 'release-1.3'
$ ./bump-version.sh 1.3
Files modified successfully, version bumped to 1.3.
$ git commit -a -m "Bumped version to 1.3"
[release-1.3 74d9424] Bumped version number to 1.3
1 files changed, 1 insertions(+), 1 deletions(-)

接下来就是修改release-1.3上的版本信息,比如配置上的版本号。这里用bump-version.sh来自动更新这类信息。

release-*分支会一直存活,直到合并到release发布, 或者被删除.在此分支上,不得合入较大的功能变动。

  • 完成发布分支

release-1.3已经满足发布条件后,我们需要将该分支合入release中。同时我们需要在这次合入中打入特定标签,来保证我们能在后续众多的提交中,找到指定版本的发布提交点。

首先,需要更新release的标签到新的版本号。

1
2
3
4
5
6
$ git checkout release
Switched to branch 'release'
$ git merge -no-ff release-1.3
Merge made of recursive.
(Summary of changes)
$ git tag -a 1.3

另外,为了保留release-*的变动,我们还需要将release-*合并到develop,以保证所有的变动能在下一个版本中被包含。

1
2
3
4
5
$ git checkout develop
Switched branch to 'develop'
$ git merge -no-ff release-1.3
Merge made of recursive.
(Summary of changes)

最后,就是永久性的删除该分支

1
2
$ git branch -d release-1.3
Delete branch release-1.3 (was fsae5d6)

4.2 热补丁分支 Hotfix Branches

Hotfix Branches

  • 根源分支: release
  • 目标分支:develop/release
  • 分支命名规则: hotfix-*

热补丁分支同发布分支非常相似,同样为新生产版本做变动。不同的是,热补丁是计划外的。

在生产版本中总会出现一些关键Bug,需要立即采取措施来修复。我们就从生产版本的主分支分支出补丁分支来修复这类问题。

采取这样的策略,可以保证develop分支上的开发团队可以继续专注于下一版本的特性开发。而由单独的团队来快速修复这一紧急问题。

  • 补丁分支创建
    热补丁分支是由release分支出来的。例如生产环境出现了一个严重的Bug,但当前的develop的功能并不稳定,这是我们就会从release分支出hotfix branches,然后在这条分支中开始修复致命问题。
1
2
3
4
5
6
7
$ git check -b hotfix-1.0.1 release
Switched to a new branch "hotfix-1.0.0"
$ ./bump-version.sh 1.0.1
Files modified successfully, version bumped to 1.0.1
$ git commit -a -m "Bumped version number to 1.0.1"
[hotfix-1.0.1 41e61bb] Bumped version number to 1.2.1
1 files changed, 1 insertions(+), 1 deletions(-)

在创建出补丁分支后,不要忘了更新版本号,此处用bump-version.sh代表这一动作。来描述该分支版本变化(1.0.0 --> 1.0.1)。

接下来就是在这个分支上,修复所需要的Bug

  • 补丁分支完成

补丁分支的创建,需要合并到主分支release。同时也需要合并入develop分支,以确保该补丁能在下一个开发版本被修复。

此处为release,而不是release-*

首先,需要更新release的标签到新的版本号。

1
2
3
4
5
6
$ git checkout release
Switched to branch 'release'
$ git merge -no-ff hotfix-1.0.1
Merge made of recursive.
(Summary of changes)
$ git tag -a 1.2.1

下一步,就是将补丁合入develop

1
2
3
4
5
$ git checkout develop
Switched to branch 'develop'
$ git merge -no-ff hotfix-1.0.1
Merge made of recursive.
(Summary of changes)

如果当前存在release-*分支,我们可以直接合入release-*,而不用合并入develop

最后就是删除这一临时分支,及时清理无用分支,来保证整个仓库的简洁。

1
2
$ git branch -d hotfix-1.0.1
Delete branch hotfix-1.0.1 (was abbe5d6)

五、总结 Summary

整个分支策略模型并没有什么新颖的技能点,但从分支管理角度,它反映整个产品的开发模型。为团队建立一个对开发和发布流程的共识。

作者

MinRam

发布于

2022-09-28

更新于

2022-10-05

Licensed under

评论