Git分支与版本管理实践
软件交付里常把两件事绑在一起:版本号怎么标 (含 Alpha / Beta / RC),以及 Git 分支怎么组织(主线、功能、发布、修复如何流动)。多人协作、阶段提测、发布后还要维护某一版时,更需要一套可执行的规则,而不是只背「Git Flow」四个字。
速览
- 版本:优先 SemVer ;RC = 功能冻结后只修 Bug,用 Tag 标记(
v1.2.0-rc.1→v1.2.0)。- 分支:Web/SaaS 常 GitHub Flow ;客户端/多版本维护用 主线 + 长期 release (无
develop)或经典 Git Flow。- 混合模型:feature → main ;bugfix → release → 再回 main ;release 在测时 main 继续合 feature,禁止把 main 新功能并进 release。
- 回主线:日常 逐条 PR / cherry-pick ;停维后可选 一次性收尾 merge(方式 B 为默认推荐)。
目录
一、版本号
- [1. 语义化版本 SemVer](#1. 语义化版本 SemVer)
- [2. 先行版本与 RC](#2. 先行版本与 RC)
- [2.1 CalVer 与其它约定](#2.1 CalVer 与其它约定)
二、主流分支模型
- [3. 四种常见工作流](#3. 四种常见工作流)
- [3.5 Forking Workflow(开源)](#3.5 Forking Workflow(开源))
- [4. 模型横向对比](#4. 模型横向对比)
三、可落地的混合模型
- [5. 主线 + 维护型 release](#5. 主线 + 维护型 release)
- [6. 阶段流程](#6. 阶段流程)
- [6.1 并行期:release 在测、main 仍前进](#6.1 并行期:release 在测、main 仍前进)
- [6.2 发布瞬间:release 与 main 如何同步](#6.2 发布瞬间:release 与 main 如何同步)
- [7. 多版本 release 并行维护](#7. 多版本 release 并行维护)
- [8. bugfix 如何回主线](#8. bugfix 如何回主线)
- [9. cherry-pick、双向 PR 与合并策略](#9. cherry-pick、双向 PR 与合并策略)
四、规范与选型
- [10. 分支命名、Tag 与保护](#10. 分支命名、Tag 与保护)
- [11. 怎么选模型](#11. 怎么选模型)
- [12. 落地检查清单](#12. 落地检查清单)
- [13. 速查卡](#13. 速查卡)
1. 语义化版本 SemVer
业界广泛采用 Semantic Versioning:
text
主版本(Major).次版本(Minor).修订号(Patch)[-先行版本][+构建元数据]
例:1.2.3
1.2.3-rc.1
1.2.3+20260525.abc123f
| 段 | 何时递增 | 示例 |
|---|---|---|
| Major | 不兼容的 API/协议变更 | 1.x → 2.0.0 |
| Minor | 向下兼容的新功能 | 1.1.0 → 1.2.0 |
| Patch | 向下兼容的 Bug 修复 | 1.2.0 → 1.2.1 |
| 约定 | 说明 |
|---|---|
| 0.y.z | 1.0.0 前可用 0.x 表示 API 未稳定;规则同 SemVer,Major 仍为 0 |
| +build | 构建元数据(日期、commit SHA),不参与版本大小比较 |
| 内外版本 | 应用商店/固件对外版本可与仓库 Tag 一致或映射(如 2.1.0 (build 1024)) |
正式版与候选版都应用 Git Tag 打在对应 commit 上,不要只靠分支名表示版本。
2. 先行版本与 RC
| 标识 | 含义 | 典型用途 |
|---|---|---|
| alpha | 内测,功能未齐、Bug 多 | 仅内部/小范围 |
| beta | 公测,功能基本冻结 | 对外开放测试 |
| rc(Release Candidate) | 候选发布:不再加新功能,只修 Bug | QA 最后一轮 |
| release / stable | 正式版 | 上线生产 |
RC 与 release 分支 :从主线(或 develop)拉出 release/1.2.0,打 v1.2.0-rc.1、v1.2.0-rc.2;通过后打 v1.2.0。RC 阶段 禁止合入新 feature,只接受 bugfix。
2.1 CalVer 与其它约定
| 方案 | 格式示例 | 适用 |
|---|---|---|
| SemVer | 1.2.3 |
库、API、需表达兼容性时(默认推荐) |
| CalVer | 2025.05.1、25.05 |
按日历发版的 App、内网工具、不强依赖 API 兼容语义时 |
CalVer 与分支策略 无关 :仍可用 release/vX.Y.x + Tag;只是 Tag 数字含义从「兼容级别」变为「发布日期」。团队选一种为主,CHANGELOG 写清规则即可。
3. 四种常见工作流
3.1 主干开发(Trunk-Based)
核心 :尽量往单一 main 提交;feature 分支 极短 (理想 <1 天),未完成功能用 Feature Flag 隐藏。
text
main: ●─●─●─●─●─●─●─●
↑ 短命 feature 快速合回
| 优点 | 缺点 |
|---|---|
| 结构简单、冲突少 | 强依赖 CI/自动化测试 |
| 适合高频发布 | 不适合长周期大功能、弱测试团队 |
3.2 Git Flow
核心 :区分 开发集成 与 发布 ;长期分支 main + develop。
| 分支 | 用途 |
|---|---|
main |
生产可用代码 + Tag |
develop |
下一版日常集成 |
feature/* |
从 develop 拉,合回 develop |
release/* |
从 develop 拉,RC 测试,合回 main + develop |
hotfix/* |
从 main 拉紧急修,合回 main + develop |
text
main: ●──────────────────────────── v1.2.0(tag)
\ ↗
develop: ──●──●──●──────── release/1.2.0 ──●──→
\ / ↓ rc.1 → rc.2
feature/A feature/B
适合:客户端 / App / SDK、多版本并行、有固定 QA 周期。不适合:强 CD、小团队嫌流程重。
3.3 GitHub Flow
核心 :只有 main(永远可部署) + 短命 feature/*;PR + CI + Review 后合入 main 即可部署。
text
main: ●────────●────────●(deploy)────●
\ / PR merge
feature: ●──●──●
RC/正式版在 main 上打 Tag ,由 CI 发布到预发/生产。适合 Web / SaaS、持续交付。
3.4 GitLab Flow(环境驱动)
核心 :分支对应 环境 ,例如 feature → main → staging → production。
适合:多环境、发布需审批的中大型团队;需书面规范避免分支泛滥。
3.5 Forking Workflow(开源)
核心 :贡献者 Fork 上游仓库 → 在自己仓库的 branch 开发 → 向上游提 PR ;维护者 Review 后合入上游 main。
| 特点 | 说明 |
|---|---|
| 权限 | 外部无 push 权限,安全 |
| 同步 | 定期 upstream/main 合并到 fork |
| 与 §5 关系 | 上游仓库内部仍可用主线+release;Fork 只解决「谁有权提交」 |
适合:开源项目、外部贡献多 ;公司内部单仓库通常用 PR 到 main 即可,不必每人 Fork。
4. 模型横向对比
| 维度 | Trunk-Based | Git Flow | GitHub Flow | GitLab Flow |
|---|---|---|---|---|
| 长期分支 | 仅 main | main + develop | 仅 main | main + 环境分支 |
| 临时分支 | feature 极短 | feature/release/hotfix | feature 短命 | feature 等 |
| RC 位置 | main 上 Tag | release 分支 Tag | main 上 Tag | 常对应预发分支 |
| 发布节奏 | 日/周多次 | 计划性(周/月) | 持续部署 | 按环境推进 |
| 合并冲突 | 低 | 高 | 中 | 中 |
| CI/CD 要求 | 极高 | 中 | 中高 | 中高 |
| 典型场景 | 大厂高频服务 | 客户端/多版本 | Web/SaaS | 多环境团队 |
5. 主线 + 维护型 release
当 main 上功能最全 、阶段提测后发布 、且 已发布版要在 release/vX.Y.x 上修 Bug 并维护一段时间 时,用下面 混合模型(常被称为「无 develop 的 Git Flow」)。
与标准 Git Flow 的差异
| 项 | 标准 Git Flow | 本篇混合模型 |
|---|---|---|
| 日常集成线 | develop |
main |
| feature 合入 | develop |
main |
| release 从哪拉 | develop |
main 上某 commit(提测点) |
| release 期间新功能 | 不应进 release | 只进 main,禁止进 release |
| 已发版 Bug | release + hotfix 从 main | bugfix 从 release 拉,再回 main |
| 停维后 | 删 release,已合 develop | bugfix 已逐条回 main;可选收尾 merge |
口头说「我们 Git Flow」时,建议明确是否保留 develop,避免和本节模型混淆。
分支全景与命名分工
text
main
release/v1.2.x
feature/*
bugfix/* ← 从 release 拉,对应当前维护中的版本
hotfix/* ← 见下表,慎用前缀
| 分支 | 职责 |
|---|---|
| main | 下一版全集;feature 只进 main |
| release/vX.Y.x | 某次发布的维护线;只收 bugfix,不收 feature |
| feature/* | 从 main 拉 → PR → main |
| bugfix/* | 测试/线上 Bug:从 release 拉 → PR → release → 再回 main |
| hotfix/* | 约定二选一 (团队写进规范):① 从 已停维旧版 的 Tag 拉(仅修老版本);② 从 main 拉、随下一版发布的紧急修(不进当前 release) |
不要 用 hotfix 和 bugfix 混指同一件事;默认:维护已发布线 = bugfix/。
维护期
提测发布
开发期
PR
tag
PR
PR 或 cherry-pick
main
feature/*
release/v1.2.0
v1.2.0
release/v1.2.x
bugfix/*
main
6. 阶段流程
阶段 1:功能开发
bash
git checkout main && git pull
git checkout -b feature/login-oauth
# 开发...
# PR → main,CI + Review 通过后合并
阶段 2:提测 --- 拉 release
bash
git checkout main && git pull
git checkout -b release/v1.2.0
# 版本号 bump、CHANGELOG;此后禁止合入 feature
git tag v1.2.0-rc.1
进入测试;可继续打 v1.2.0-rc.2 等 Tag。
阶段 3:测试 / 线上 bugfix
| Bug 来源 | 修复分支 | 合并去向 |
|---|---|---|
| 测试阶段 | release/vX.Y.x |
release → 再回 main |
| 已发布用户 | release/vX.Y.x |
release → 再回 main |
| 仅在 main 重现 | main 或 feature/* |
仅 main |
bash
git checkout release/v1.2.0
git checkout -b bugfix/release-1.2-login-error
# PR → release/v1.2.0
# 再 PR → main 或 cherry-pick(§9)
6.1 并行期:release 在测、main 仍前进
拉出 release/v1.2.0 之后,main 不会冻结 ------下一版 feature 继续 PR → main。这是最常见、也最容易出事的阶段。
text
时间 →
main: ●──●──●──●──●──●──● (持续合入 feature)
release: ●────●──●──● (仅 bugfix + RC tag)
↑ 禁止把 main 上新 feature merge/cherry-pick 进 release
| 规则 | 说明 |
|---|---|
| 允许 | main 合 feature;release 合 bugfix |
| 禁止 | 把 main 上未纳入本版 scope 的提交并进 release |
| 禁止 | feature 分支直接 PR 到 release(除非该 feature 已明确纳入本版且从 release 点 cherry-pick,极少用) |
| 冲突 | release 上 bugfix 回 main 时若冲突,在 回 main 的 PR 里解决,不要反过来把 main 整包 merge 进 release |
feature/* release/v1.2.0 main feature/* release/v1.2.0 main RC 测试只收 bugfix PR 新功能 每个 bugfix 单独回流
6.2 发布瞬间:release 与 main 如何同步
GA(General Availability)时在 release 上打正式 Tag v1.2.0。main 如何对齐 二选一(团队默认推荐 方式 B):
| 方式 | 做法 | 优点 | 缺点 |
|---|---|---|---|
| A 收尾 merge | merge release/v1.2.0 → main 一次,打齐 Tag 节点 |
main 历史含完整 release 线 | 易带进 release 脏提交;巨型 merge |
| B 逐条回流(推荐) | GA 前 bugfix 已全部 PR/cherry-pick 到 main;不日常 merge release | main 干净,与 §8 铁律一致 | 需纪律;漏回流则下版 Bug 复活 |
方式 B 的 GA 检查:
- 本版所有 bugfix 已在 main 有对应提交
-
release上 Tagv1.2.0指向发布构建 commit - main 可继续包含下一版 feature(无需与 release 树一致)
补丁版 v1.2.1、v1.2.2:在 release/v1.2.x 上打 Tag,bugfix 仍 release → main 逐条回。
何时结束 release 分支:停维、补丁已回 main、无未发布提交 → 删远程分支,保留 Tag。
7. 多版本 release 并行维护
同时维护 v1.2.x 与 v1.3.x 时:
text
main (下一版 v1.4 开发)
release/v1.2.x
release/v1.3.x
| 规则 | 说明 |
|---|---|
| 一条已发布线一条 branch | release/v1.2.x、release/v1.3.x 独立 |
| 同一 Bug 多版本受影响 | 每个 release 各修、各 PR;再分别回 main(逻辑相同可 cherry-pick 同一 patch 多次) |
| main 代表 | 下一完整版,不是「所有版本的超集」 |
| 先修哪条 | 通常 先修仍在维的最新 release,再向后移植到更老 release(若仍维护) |
8. bugfix 如何回主线
错误做法:日常「整条 release merge 进 main」
- release 上可能有调试代码、测试开关、版本专用 hack。
- 隔几周再 merge,main 已前进,巨型 merge 难 review。
铁律
| 规则 | 说明 |
|---|---|
| release 不主动 merge main | main 新功能不污染已发版线 |
| 每个 bugfix 显式回 main | 最小单位回流 |
| 收尾 merge 仅停维时 | 且团队选 方式 A 时才做 |
text
feature/* ──PR──► main
bugfix/* ──PR──► release/v1.2.x ──PR / cherry-pick──► main
不必回 main:仅当前版的临时 hack、与主线架构冲突的修复、纯测试代码。
常见反例
| 反例 | 后果 |
|---|---|
| feature 直接 PR 到 release | RC 范围漂移,测试无效 |
| 为「省事」每周 merge release→main | 脏提交、漏 review |
| 只在 release 修、从不回 main | 下一版 Bug 复活 |
9. cherry-pick、双向 PR 与合并策略
cherry-pick 何时用
| 场景 | 推荐 |
|---|---|
| bugfix 小、commit 干净 | 双向 PR |
| release 有脏提交、只要修复点 | cherry-pick 单 commit → main |
| feature | 只走 main,不 pick |
| release 已停维 | 收尾 merge 或批量 cherry-pick |
安全三原则 :只 pick 单一职责 bugfix;pick 后在 main 上视为只读;message 注明来源,如 fix: null (#123, cherry-pick from release/v1.2.0)。
bash
git checkout main && git pull
git cherry-pick <bugfix-commit-sha>
Squash merge 注意 :feature 用 Squash 合入 main 后,回 main 的 bugfix 应 cherry-pick 合并后的那一个 commit(或 bugfix 在 release 上的 merge commit),不要 pick 已 squash 掉的中间提交。
PR 合并策略(建议默认)
| 目标分支 | 建议策略 | 说明 |
|---|---|---|
| main ← feature | Squash merge | 主干历史一条线一条功能 |
| main ← bugfix 回流 | Merge commit 或 cherry-pick PR | 保留与 release 的追溯 |
| release ← bugfix | Merge commit 或 squash(看审计) | 便于 Tag 指向明确节点 |
平台 Merge queue(GitHub 等)可用于 main:CI 通过后排队合并,减少「刚绿就冲突」。
10. 分支命名、Tag 与保护
命名
| 类型 | 命名示例 |
|---|---|
| 功能 | feature/login-oauth |
| 发布维护 | release/v1.2.0、release/v1.2.x |
| 维护线修复 | bugfix/release-1.2-login-error |
| 旧版/特殊 | hotfix/v1.1.5-security(从 Tag 拉) |
Monorepo :可在前缀加包名,如 feature/billing-invoice、release/billing-v1.2.0;策略仍按 可发布单元 或目录 OWNER 划分。
Tag 与 CHANGELOG
| 实践 | 说明 |
|---|---|
| Tag = 版本 | v1.2.0-rc.1、v1.2.0、v1.2.1 |
| CHANGELOG | 每次发版记录变更;RC 可只记 Fixes |
| Signed tag | 合规/供应链场景用 git tag -s + 密钥管理(可选) |
分支保护与 CI 最小集
| 规则 | main |
release/* |
|---|---|---|
| 禁止 force push | ✅ | ✅ |
| 必须 PR | ✅ | ✅ |
| 必须 CI 绿 | ✅ 全量/主干测试 | ✅ 该版本测试集 |
| 必须 Review | ✅ ≥1 | ✅ ≥1(建议 release OWNER) |
| 谁可打 Tag | 维护/发布角色 | 同左 |
| RC Tag | --- | 触发 预发 流水线 |
v*.*.* Tag |
触发生产或制品库 | 补丁 Tag 同 |
CODEOWNERS :release/ 路径仅 release 负责人可 approve,降低 feature 误入概率。
11. 怎么选模型
| 场景 | 建议 |
|---|---|
| 小团队、微服务、强 CI、日/周发布 | Trunk-Based + Feature Flag |
| Web / SaaS、持续部署 | GitHub Flow;RC 用 Tag + 预发 |
| 客户端 / App、多版本、阶段 QA | Git Flow,或 §5~§9 混合模型 |
| 多环境(dev/staging/prod) | GitLab Flow |
| 开源、外部贡献 | Forking + 上游用 GitHub Flow 或混合模型 |
| 主线最全 + 提测 + release 长期修 Bug | §5~§9 |
12. 落地检查清单
分支与版本
- 版本号 SemVer(或书面约定 CalVer)
- Tag 打在 release 维护线;RC 只合 bugfix
-
main仅 PR;feature 禁止 直进 release
并行期
- release 在测时 main 可合 feature,但 禁止 main 新功能进 release
- bugfix:release → main 逐条回流
发布与停维
- 默认 方式 B:GA 不依赖整条 release→main merge
- 停维后再决定是否收尾 merge;多版本各维护各
release/vX.Y.x
合并与工具
- feature→main 默认 Squash;bugfix 回流策略写清
-
main/release/*保护分支 + CI 已配置 - 多版本 Bug:每个受影响 release 各修各回 main
13. 速查卡
text
┌─────────────────────────────────────────────────────────┐
│ 流向:feature → main │
│ bugfix → release/vX.Y.x → main(逐条) │
├─────────────────────────────────────────────────────────┤
│ 禁止:feature → release │
│ 日常 merge release → main │
│ release 在测时把 main 新功能并进 release │
├─────────────────────────────────────────────────────────┤
│ 版本:SemVer + Tag(rc.1 → 正式 → patch) │
│ 并行:main 继续开发,release 只收 bugfix │
│ 回流:双向 PR 或 cherry-pick 单 commit │
│ 多版本:每条 release/vX.Y.x 独立维护 │
└─────────────────────────────────────────────────────────┘
| 问题 | 答案 |
|---|---|
| RC 能加功能吗? | 不能,只修 Bug |
| release 在测 main 能合 feature 吗? | 能,但不能进 release |
| 怎么回 main? | 每个 bugfix 单独 PR/pick,别整支 merge |
| hotfix 和 bugfix? | 维护已发版用 bugfix/ |
| GA 怎么同步 main? | 推荐方式 B:修已全在 main |
落地注意
- 命令与保护分支以 GitHub / GitLab / Gitee 文档为准;MR/PR 选项名略有差异。
- 若有 develop :把文中
main换成「develop 集成 + main 发布」,release 维护逻辑不变。 - worktree 、图形化分支面板:并行检出
main+release/*时便于本地多分支,不改变流向。 - SBOM / 制品签名:与 Tag、CI 制品库联动,属供应链加固,分支策略不替代安全流程。
- 命令细节(checkout、merge、revert 等)见仓库内 Git常用命令操作指南。
一句话 :SemVer + Tag 标版本,feature→main、bugfix→release→main 管协作;release 在测时 main 仍可前进但互不进犯 ;用 逐条回流 代替日常整条 merge,多版本就多条 release/vX.Y.x 并行维护。