【CI/CD】Git Flow 分支模型
Git Flow 分支模型
1.前言
Git Flow 模型(本文所阐述的分支模型)构思于 2010 年,也就是 Git 诞生后不久,距今已有 10 多年。在这 10 多年中,Git Flow 在许多软件团队中大受欢迎。
在这 10 多年里,Git 本身已经风靡全球,而使用 Git 开发的最流行的软件类型也更多地转向了网络应用。网络应用通常是持续交付的,不会回滚,也不需要支持多个版本的软件同时运行。这与原作者在 10 年前写这篇博文时所考虑的软件类型不同。
如果你的团队正在进行软件的持续交付,建议采用更简单的工作流程(比如 GitHub Flow),而不是试图把 Git Flow 强塞进你的团队。不过,如果您正在构建明确版本化的软件,或者您需要支持软件的多个版本,那么 Git Flow 可能仍然适合您的团队。
最后,请记住,一劳永逸式的通用解决方案是不存在的。考虑一下你自己的项目背景,再做决定。

2.Main branches 主要分支
在核心部分,开发模型受到了现有模型的极大启发。中心仓库拥有两个无限生命周期的主分支:
masterdevelop

每个 Git 用户对位于 origin 的 master 分支都不会陌生。与 master 分支平行的另一个分支叫 develop 分支。
我们把 origin/master 视为主分支,在这里,HEAD 的源代码总是反映生产就绪的状态。
我们认为 origin/develop 是主分支,HEAD 的源代码总是反映下一个版本最新交付的开发变更状态。有人称其为 “集成分支”。每晚的自动构建都是从这里开始的。
当 develop 分支中的源代码达到稳定点并准备发布时,所有变更都应以某种方式合并回 master 分支,然后标记上发布编号。具体做法将在后面讨论。
因此,每次将变更合并回 master 版本时,这就是一个新的生产版本。我们倾向于严格遵守这一点,因此理论上我们可以使用 Git 钩子脚本,在每次 master 版本有提交时自动构建软件并将其发布到生产服务器上。
3.Supporting branches 辅助分支
除了主分支 master 和开发分支 develop,我们的开发模式还使用各种辅助分支来帮助团队成员之间的 并行开发、简化功能跟踪、为生产发布做准备,以及 协助快速修复实时生产问题。与主分支不同,这些分支的生命周期总是有限的,因为它们最终会被移除。
我们可能使用的不同类型的分支包括
Feature branches(特性分支)Release branches(发布分支)Hotfix branches(热修复分支)
每种分支都有其特定的目的,并受严格的规则约束,哪些分支可以作为其原始分支,哪些分支必须作为其合并目标。我们稍后将详细介绍它们。
从技术角度看,这些分支并不 “特殊”。分支类型是根据我们的使用方式来分类的。当然,它们都是普通的 Git 分支。
3.1 Feature branches 特性分支
来自于 develop,必须合并回 develop。

分支命名约定:只要不用 master,develop,release-*,hotfix-* ,其他都可以。
feature 分支(有时也称作主题分支 Topic branches)用于 为即将发布或未来发布的版本开发新特性。在开始开发某个功能时,可能还不知道该功能将被集成到哪个目标版本中。feature 分支的本质是,只要该特性还在开发阶段,它就一直存在,但最终会被合并回 develop(将新特性添加到即将发布的版本中)。
特性分支通常只存在于开发者版本库中,而不存在于原始版本库(origin)中。
(1)创建 feature 分支
开始开发新功能时,从 develop 分支创建分支。
$ git checkout -b myfeature develop
Switched to a new branch "myfeature"
(2)将已完成的功能并入 develop 分支
已完成的功能可以合并到 develop 分支,以便在即将发布的版本中加入这些功能:
$ 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 标志后,即使合并可以通过快进执行,也会始终创建一个新的提交对象。这样可以避免丢失 feature 分支历史存在的信息,并将共同添加该特性的所有提交组合在一起。

在后一种情况下,我们无法从 Git 历史记录中看到哪些提交对象一起实现了某个特性,而必须手动阅读所有日志信息。在后一种情况下,还原整个特性(即一组提交)确实是个令人头疼的问题,而如果使用 - - no - ff 标志,就很容易做到。
是的,这会多创建几个(空)提交对象,但收益远大于代价。
3.2 Release branches 发布分支
来自于 develop,必须合并回 develop 和 master。
分支命名约定:release-*。
release 分支支持新生产版本的准备工作。release 分支允许在最后一刻进行校验。此外,它们还可以进行小的错误修复,并为发布版本准备元数据(版本号、构建日期等)。在 release 分支上完成所有这些工作后,develop 分支就可以接收下一个大版本的功能了。
从 develop 分支分离出新版本分支的关键时刻是 develop 分支(几乎)反映了新版本的理想状态。至少所有针对即将发布的版本的功能都必须在此时合并到 develop 分支。而针对未来版本的所有功能则不一定,它们必须等到 release 分支分支化之后。
正是在 release 分支开始时,即将发布的版本才会被分配一个版本号,而不是更早。在此之前,develop 分支反映的是 “下一个版本” 的变更,但在 release 分支启动之前,“下一个版本” 最终是 0.3 0.3 0.3 还是 1.0 1.0 1.0 并不清楚。这个决定是在 release 分支启动时做出的,并由项目的版本号递增规则来执行。
(1)创建 release 分支
release 分支是从 develop 分支创建的。例如, 1.1.5 1.1.5 1.1.5 版是当前的生产版本,而我们即将发布一个大版本。develop 分支已经为 “下一个版本” 做好了准备,我们决定将其命名为 1.2 1.2 1.2 版(而不是 1.1.6 1.1.6 1.1.6 版或 2.0 2.0 2.0 版)。因此,我们建立了分支,并给 release 分支起了一个反映新版本号的名字:
$ 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 脚本,它会更改工作副本中的某些文件,以反映新版本。(当然,这也可以是手动更改,关键是某些文件会发生变化)。然后,提交被修改的版本号。
这个新分支可能会存在一段时间,直到正式发布。在此期间,错误修复可能会应用到该分支(而不是 develop 分支)。严禁在此添加大型新功能。它们必须合并到 develop 分支,因此要等到下一个大版本发布。
(2)完成 release 分支
当 release 分支的状态准备好成为真正的发布版本时,需要执行一些操作。首先,将 release 分支合并到 master 分支(因为 master 分支上的每次提交都是一次新的发布,切记)。其次,必须对 master 分支上的提交进行标记,以方便将来引用这个历史版本。最后,需要将 release 分支上的修改合并回 develop 分支,以便未来的版本也包含这些错误修复。
Git 的前两个步骤:
$ 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
现在,发布工作已经完成,并打上了标签,以备将来参考。(你也可以使用 -s 或 -u <key> 标记对标签进行加密签名。)
为了保留 release 分支中的改动,我们需要把它们合并回 develop 分支。在 Git 中:
$ git checkout develop
Switched to branch 'develop'
$ git merge --no-ff release-1.2
Merge made by recursive.
(Summary of changes)
这一步很可能导致合并冲突(甚至可能,因为我们已经更改了版本号)。如果是这样,请修复并提交。
现在我们真的完成了,release 分支也可以删除了,因为我们不再需要它了:
$ git branch -d release-1.2
Deleted branch release-1.2 (was ff452fe).
3.3 Hotfix branches 热修复分支
来自于 master,必须合并回 develop 和 master。
分支命名约定:hotfix-*。

hotfix 分支与 release 分支非常相似,都是为新的生产版本做准备,尽管是计划外的。它们产生的原因是,必须立即对实时生产版本中不希望出现的状态采取行动。当必须立即解决生产版本中的关键错误时,可以从标记生产版本的 master 分支上的相应标记中分出一个 hotfix 分支。
这样做的好处是,团队成员(在开发分支上)的工作可以继续进行,而另一个人则在准备快速的生产修复。
(1)创建 hotfix 分支
hotfix 分支是从 master 分支创建的。例如, 1.2 1.2 1.2 版是当前正在运行的生产版本,由于一个严重的错误而造成了很多麻烦。但开发中的更改还不稳定。这时,我们可以分离出一个 hotfix 分支,开始修复 1.2 1.2 1.2 版本的错误。
$ 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(-)
分支后不要忘记提升版本号!
然后,修复错误并在一个或多个单独的提交中提交修复。
$ git commit -m "Fixed severe production problem"
[hotfix-1.2.1 abbe5d6] Fixed severe production problem
5 files changed, 32 insertions(+), 17 deletions(-)
(2)完成 hotfix 分支
完成后,需要将漏洞修复合并回 master 分支,但同时也需要合并回 develop 分支,以确保下一个版本也包含该漏洞修复。这与 release 分支的完成方式完全类似。
首先,更新主版本并标记发布版本。
$ 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
可以使用 -s 或 -u <key> 标记对标签进行加密签名。
接下来,在 develop 中也包含错误修正:
$ git checkout develop
Switched to branch 'develop'
$ git merge --no-ff hotfix-1.2.1
Merge made by recursive.
(Summary of changes)
这里的规则有一个例外,那就是当当前存在 release 版分支时,热修复程序的更改需要合并到 release 分支,而不是 develop 分支。将错误修正反向合并到 release 分支,最终会导致在 release 分支完成后,错误修正也被合并到 develop 分支。(如果 develop 中的工作立即需要这个错误修正,而又不能等到 release 分支完成,那么现在也可以安全地将错误修正合并到 develop 中)。
最后,删除临时分支:
$ git branch -d hotfix-1.2.1
Deleted branch hotfix-1.2.1 (was abbe5d6).
4.总结
虽然这个分支模型并没有什么令人震惊的新内容,但这篇文章开头提到的 “全局” 图在我们的项目中却非常有用。它形成了一个优雅的心智模型,易于理解,并能让团队成员对分支和发布流程形成共识。
相关文章:
【CI/CD】Git Flow 分支模型
Git Flow 分支模型 1.前言 Git Flow 模型(本文所阐述的分支模型)构思于 2010 年,也就是 Git 诞生后不久,距今已有 10 多年。在这 10 多年中,Git Flow 在许多软件团队中大受欢迎。 在这 10 多年里,Git 本身…...
SpringBoot Thymeleaf模板引擎
Thymeleaf 模板引擎 前端交给我们的页面,是html页面。如果是我们以前开发,我们需要把他们转成jsp页面,jsp好处就是当我们查出一些数据转发到JSP页面以后,我们可以用jsp轻松实现数据的显示,及交互等。 jsp支持非常强大…...
prometheus部署
一、前言 Prometheus 是一个开源的系统监控和警报工具,用于收集、存储和查询时间序列数据。它旨在提供高效的多维数据收集和查询功能,帮助用户监控其应用程序和基础设施的性能,并在出现问题时触发警报,总来得说prometheus是用来收…...
Flink-Window详细讲解-countWindow
一.countWindow和countWindowall区别 1.countWindow: 如果您使用 countWindow(5),这意味着您将数据流划分成多个大小为 5 的窗口。划分后的窗口如下: 窗口 1: [1, 2, 3, 4, 5]窗口 2: [6, 7, 8, 9, 10] 当每个窗口中的元素数量达到 5 时&…...
React 18 state 如同一张快照
参考文章 state 如同一张快照 也许 state 变量看起来和一般的可读写的 JavaScript 变量类似。但 state 在其表现出的特性上更像是一张快照。设置它不会更改已有的 state 变量,但会触发重新渲染。 设置 state 会触发渲染 可能会认为用户界面会直接对点击之类的用…...
EasyPoi导出 导入(带校验)简单示例 EasyExcel
官方文档 : http://doc.wupaas.com/docs/easypoi pom的引入: <!-- easyPoi--><dependency><groupId>cn.afterturn</groupId><artifactId>easypoi-spring-boot-starter</artifactId><version>4.0.0</version></dep…...
八大排序
目录 选择排序-直接插入排序 插入排序-希尔排序 选择排序-简单选择排序 选择排序-堆排序 交换排序-冒泡排序 交换排序-快速排序 归并排序 基数排序 选择排序-直接插入排序 基本思想: 如果碰见一个和插入元素相等的,那么插入元素把想插入的元素放在相等元素…...
网络安全【黑客技术】自学
1.网络安全是什么 网络安全可以基于攻击和防御视角来分类,我们经常听到的 “红队”、“渗透测试” 等就是研究攻击技术,而“蓝队”、“安全运营”、“安全运维”则研究防御技术。 掌握技术的听说也需要心怀正义,不要利用技术行不轨之事&…...
【网络通信】socket编程——TCP套接字
TCP依旧使用代码来熟悉对应的套接字,很多接口都是在udp中使用过的 所以就不会单独把他们拿出来作为标题了,只会把第一次出现的接口作为标题 文章目录 服务端 tcp_servertcpserver.hpp(封装)初始化 initServer1. 创建socket2. 绑定 bindhtons —— 主机序…...
ROS2系统学习番外篇2---用VSCode开发ROS2程序
在ROS2系统学习3—第一个“Hello World”程序—即工作空间创建与包创建中已经介绍了如何创建ROS的工作空间以及包。在开发大型工程时,往往需要在IDE下面进行开发,因此本篇介绍使用VSCode来搭建ROS2开发环境的方法。 首先用VSCode打开ROS2的工作空间。 使用快捷键编译ROS2 …...
06 - Stream如何提高遍历集合效率?
前面我们讲过 List 集合类,那我想你一定也知道集合的顶端接口 Collection。 在 Java8 中,Collection 新增了两个流方法,分别是 Stream() 和 parallelStream()。 1、什么是 Stream? 现在很多大数据量系统中都存在分表分库的情况…...
【Spring】使用注解的方式获取Bean对象(对象装配)
目录 一、了解对象装配 1、属性注入 1.1、属性注入的优缺点分析 2、setter注入 2.1、setter注入的优缺点分析 3、构造方法注入 3.1、构造方法注入的优缺点 二、Resource注解 三、综合练习 上一个博客中,我们了解了使用注解快速的将对象存储到Spring中&#x…...
[webpack] 基本配置 (一)
文章目录 1.基本介绍2.功能介绍3.简单使用3.1 文件目录和内容3.2 下载依赖3.3 启动webpack 4.基本配置4.1 五大核心概念4.2 基本使用 1.基本介绍 Webpack 是一个静态资源打包工具。它会以一个或多个文件作为打包的入口, 将我们整个项目所有文件编译组合成一个或多个文件输出出去…...
模板学堂|SQL数据集动态参数使用场景及功能详解
DataEase开源数据可视化分析平台于2022年6月正式发布模板市场(https://dataease.io/templates/)。模板市场旨在为DataEase用户提供专业、美观、拿来即用的仪表板模板,方便用户根据自身的业务需求和使用场景选择对应的仪表板模板&a…...
Wlan——射频和天线基础知识
目录 射频的介绍 射频和Wifi 射频的相关基础概念 射频的传输 信号功率的单位 射频信号传输行为 天线的介绍 天线的分类 天线的基本原理 天线的参数 射频的介绍 射频和Wifi 什么是射频 从射频发射器产生一个变化的电流(交流电),通过…...
前端实习周记第三周周记
第二周总结 第二周主要是做了一些PC端细节内容。大的地方改的不多,但是小的细节蛮多。 值得一提的是,第二周做的微信小程序,改了很多逻辑。改逻辑需要与后端进行联调,收获很大,思路也愈发清楚。 记录做了什么是好习…...
Android 13 Launcher界面——移除Launcher的删除和卸载功能
目录 一.背景 二.将卸载功能进行屏蔽 三.将移除功能屏蔽 四.将Remove按钮与Uninstall按钮屏蔽...
深度学习:使用卷积神经网络CNN实现MNIST手写数字识别
引言 本项目基于pytorch构建了一个深度学习神经网络,网络包含卷积层、池化层、全连接层,通过此网络实现对MINST数据集手写数字的识别,通过本项目代码,从原理上理解手写数字识别的全过程,包括反向传播,梯度…...
docker search 镜像报错: connect: no route to host (桥接模式配置静态IP)
如下 原因 可能有多种: ① 没有开放防火墙端口 ② ip地址配置有误 解决 我是因为虚拟机采用了桥接模式,配置静态ip地址有问题。 先确认虚拟机采用的是 桥接模式,然后启动虚拟机。 1、打开命令行,输入下面指令,打开…...
【VUE】[Violation] Added non-passive event listener to a scroll-blocking...
环境 chrome: 115.0.5790.170vue: ^3.3.4element-plus: ^2.3.4vite: ^4.4.7 问题 [Violation] Added non-passive event listener to a scroll-blocking <某些> 事件. Consider marking event handler as passive to make the page more responsive. See <URL> …...
龙虎榜——20250610
上证指数放量收阴线,个股多数下跌,盘中受消息影响大幅波动。 深证指数放量收阴线形成顶分型,指数短线有调整的需求,大概需要一两天。 2025年6月10日龙虎榜行业方向分析 1. 金融科技 代表标的:御银股份、雄帝科技 驱动…...
挑战杯推荐项目
“人工智能”创意赛 - 智能艺术创作助手:借助大模型技术,开发能根据用户输入的主题、风格等要求,生成绘画、音乐、文学作品等多种形式艺术创作灵感或初稿的应用,帮助艺术家和创意爱好者激发创意、提高创作效率。 - 个性化梦境…...
Chapter03-Authentication vulnerabilities
文章目录 1. 身份验证简介1.1 What is authentication1.2 difference between authentication and authorization1.3 身份验证机制失效的原因1.4 身份验证机制失效的影响 2. 基于登录功能的漏洞2.1 密码爆破2.2 用户名枚举2.3 有缺陷的暴力破解防护2.3.1 如果用户登录尝试失败次…...
DIY|Mac 搭建 ESP-IDF 开发环境及编译小智 AI
前一阵子在百度 AI 开发者大会上,看到基于小智 AI DIY 玩具的演示,感觉有点意思,想着自己也来试试。 如果只是想烧录现成的固件,乐鑫官方除了提供了 Windows 版本的 Flash 下载工具 之外,还提供了基于网页版的 ESP LA…...
CMake 从 GitHub 下载第三方库并使用
有时我们希望直接使用 GitHub 上的开源库,而不想手动下载、编译和安装。 可以利用 CMake 提供的 FetchContent 模块来实现自动下载、构建和链接第三方库。 FetchContent 命令官方文档✅ 示例代码 我们将以 fmt 这个流行的格式化库为例,演示如何: 使用 FetchContent 从 GitH…...
如何在最短时间内提升打ctf(web)的水平?
刚刚刷完2遍 bugku 的 web 题,前来答题。 每个人对刷题理解是不同,有的人是看了writeup就等于刷了,有的人是收藏了writeup就等于刷了,有的人是跟着writeup做了一遍就等于刷了,还有的人是独立思考做了一遍就等于刷了。…...
视觉slam十四讲实践部分记录——ch2、ch3
ch2 一、使用g++编译.cpp为可执行文件并运行(P30) g++ helloSLAM.cpp ./a.out运行 二、使用cmake编译 mkdir build cd build cmake .. makeCMakeCache.txt 文件仍然指向旧的目录。这表明在源代码目录中可能还存在旧的 CMakeCache.txt 文件,或者在构建过程中仍然引用了旧的路…...
iOS性能调优实战:借助克魔(KeyMob)与常用工具深度洞察App瓶颈
在日常iOS开发过程中,性能问题往往是最令人头疼的一类Bug。尤其是在App上线前的压测阶段或是处理用户反馈的高发期,开发者往往需要面对卡顿、崩溃、能耗异常、日志混乱等一系列问题。这些问题表面上看似偶发,但背后往往隐藏着系统资源调度不当…...
【网络安全】开源系统getshell漏洞挖掘
审计过程: 在入口文件admin/index.php中: 用户可以通过m,c,a等参数控制加载的文件和方法,在app/system/entrance.php中存在重点代码: 当M_TYPE system并且M_MODULE include时,会设置常量PATH_OWN_FILE为PATH_APP.M_T…...
C# 表达式和运算符(求值顺序)
求值顺序 表达式可以由许多嵌套的子表达式构成。子表达式的求值顺序可以使表达式的最终值发生 变化。 例如,已知表达式3*52,依照子表达式的求值顺序,有两种可能的结果,如图9-3所示。 如果乘法先执行,结果是17。如果5…...
