2462 字
约 8 分钟
15
S06-A21 · 分支模型的代价:trunk-based 为什么不是"更先进"

一个团队从 Git Flow 迁到 trunk-based:所有人直接往主干提交、靠特性开关控制发布。三个月后他们说"更顺了"——而同期线上事故多了两起,都是"开关组合没测到"。

trunk-based 不是"更先进的模型",而是"把成本从"合并冲突"转移到"开关矩阵""。这个"更容易被看见"解释了"迁移的动机往往是"我被合并冲突烦透了",而"开关矩阵"是一项新增的、看不见的成本——它在第一次"开关组合事故"时才会被记起。
而这两项成本都很真实,只是其中一项更容易被看见。


1. 四种分支模型的成本位置

模型 主要成本
Git Flow(多长期分支) 合并冲突、集成延迟
GitHub Flow(短分支 + PR) 评审等待、集成频率
trunk-based(直提主干) 特性开关矩阵、纪律要求
发布分支模型 双向合入(主干↔发布)

第三项的"开关矩阵"是最容易被忽略的:N 个开关就有 2^N 种组合,而测试通常只覆盖"全开"与"全关"。这个"2^N"不是理论担忧:三个开关就是 8 种组合,而"开关之间的依赖"会让其中一部分非法——于是"组合空间"既大又有约束,靠人工枚举不可行。

第一项的"痛感"有个"放大机制":分支越久,改动越多,冲突越多,而"解冲突"需要"重新理解两边"——于是"合并那天"要花一整天。
第一项的"集成延迟"很直观:分支开得越久,合并越痛——而痛感在"合并那天"集中爆发。

2. trunk-based 的三个前提

前提 缺了会怎样
特性开关(可运行时关闭) 未完成代码进主干,影响发布
自动化测试与 CI 直提主干的风险没人兜
小步提交(< 1 天) 大改动直提,回滚困难

第一项是核心:**"未完成的代码"必须"对用户不可见"**第一项的"隐含要求"是"开关必须能"按环境/按用户"控制":如果只有"改配置重启"这一种方式,那"未完成代码"仍会影响发布。
,否则"主干永远可发布"这条假设不成立。

第二项是安全网:直提主干意味着"每次提交都可能进生产",于是"测试与构建"必须是自动的、快的。

第三项的"判据"可以换成"能否在一天内回滚":如果一次提交包含"三天的工作",那"回滚"就是"丢掉三天"——于是没人敢回滚。
第三项的"1 天"是经验值:超过一天的改动,回滚粒度就太粗。

3. 开关矩阵的三种风险

风险 表现
组合未测 只有全开/全关被覆盖
开关长期不清理 代码里 dozens of if (flag)
开关依赖顺序 打开 A 必须先打开 B

第一项就是开头那两起事故:两个开关的组合"A 开 B 关"从未被测试第一项的"修法"是"列出所有"会被同时使用的组合",只测这些"——而"会被同时使用"由"业务场景"决定,不是"穷举"。
,而它在某次灰度里恰好出现。

第二项的"识别"是"数代码里 if (flag) 的数量":超过 20 处,说明"开关没在清理"——而它同时意味着"组合空间"已经失控。
第二项的成本会累积:每个开关都是一条"永久分支",于是"代码里有两条路径",而只有一条常被走。

// 开关台账(每条必须有"到期")
flags:
  new-checkout:
    created: 2026-09-01
    expires: 2026-12-01        # 到期必须"转正或删除"
    states: [off, on]
    tested_combos: [[off], [on]]   # 明确"测了哪些组合"
  fast-search:
    depends_on: [new-checkout]      # 依赖关系必须写

"热修"是所有模型都要处理的一条路径,而它最能暴露模型缺陷:trunk-based 下热修就是"一个 commit + 立即发",而分支模型下热修要"合回主干 + 合到发布"两处。

// 两种模型的热修路径(同一场景:线上 bug 需 1 小时内修)
trunk-based:建 commit → CI → 直接发 → 完成(一条路径)
分支模型:  从 release 建 hotfix → 修 → 合 release → 再合 main → 完成(两条路径,易漏)
// 常见事故:只合了 release,忘了合 main → 下次发布"旧 bug 复活"

4. GitHub Flow 的隐性成本

成本 说明
评审等待 PR 平均等 1–2 天
分支寿命 "等评审"期间主干已前进
集成频率 每天合并不是"持续集成"

第二项会让"短分支"变长:分支开了三天,主干合了 20 个 PR第二项的"量化"是"分支寿命中位数":超过 2 天,"短分支"已经在退化成"小 Git Flow"——而"冲突"会按期到来。
——于是"合并时冲突"照旧发生。

所以"GitHub Flow 的成败取决于评审速度":评审慢,短分支就退化成"小 Git Flow"。

"开关矩阵"可以只测"业务上会出现的组合",而这需要一张"组合清单":

// 组合清单(三条规则,控制规模)
1 每个开关与"默认关"组合必测(基线)
2 有依赖关系的开关:只测"合法组合"(A 开必须先 B 开)
3 线上会同时打开的组合:全测(通常 ≤ 5 组)
// 结果:从 2^N 收敛到 5–8 组,可人工维护

5. 怎么选:三个判据

判据 指向
发布频率(每天多次 vs 每周) 高频 → trunk-based
团队规模与信任 小团队/高信任 → trunk-based
测试自动化程度 弱 → 需要分支隔离

第三项的"门槛"可以量化:CI 从提交到结果 < 10 分钟、主干构建成功率 > 95%。达不到这两条,直提主干的"每天多次发布"就只是口号。
第三项最硬:如果没有"提交即验证"的能力,直提主干就是"把风险交给运气"。

第一项是"收益"侧:一天发多次的团队,分支模型必须支持"随时可发";而"每周发一次"的团队,分支的隔离价值更大。

"分支寿命"与"评审等待"是一对因果,需要一起看:

// 两个数(按周统计)
分支寿命中位数:        首次提交 → 合并   (目标 < 2 天)
PR 等待评审中位数:     提交 → 第一次评审 (目标 < 4 小时)
// 若"等待评审"占"分支寿命"的 70% → 问题是评审产能,不是模型

6. 排错:五种"分支模型带来的问题"

现象 成因 处理方向
合并永远很痛 分支太长 缩短分支寿命
主干不可发布 未完成代码直提 加开关
开关越积越多 无到期机制 台账 + 定期清理
发布分支双向合入混乱 无"主干优先"规则 定义合入方向
评审积压 评审能力不足 加人/拆小 PR

第四项在"发布分支"模型里最典型:热修要合回主干、主干又要合到发布——两条方向,任一条漏了就"下次发布回退 bug"。

最后一个"回滚"视角:trunk-based 的回滚单元是"一个提交",而分支模型的回滚单元是"一次合并"。

// 两种回滚粒度
trunk-based:revert 一个 commit → 影响"一次小改动"(精确但次数多)
分支模型:回滚整个 release → 影响"一批改动"(粗糙但一次搞定)
// 判据:你的团队更常"回滚一处"还是"回滚一批"

7. 边界:什么情况不必换模型

场景 为什么 做法
单人项目 无合并冲突 随意
发布频率低(每月) 分支隔离更省 Git Flow
强合规(每次发布需审计) 发布分支是证据 保留发布分支
大型单体(测试慢) 直提主干风险高 短分支 + 严格 CI

判断口径一句话:"合并成本"与"隔离收益"哪个更大。最后一条与"迁移"有关的边界:不要一次切换。可以先"缩短分支寿命(3 天 → 1 天)"与"建开关台账",等 CI 达到门槛再"直提主干"——中途任何一步都可能暴露"前置不足"。
合并成本高(长期分支、多人改动重叠),用 trunk-based;隔离收益大(发布需审计、测试慢),用分支。


8. 自测

  1. 四种分支模型的成本分别落在哪里?为什么"开关矩阵"最容易被忽略?
  2. trunk-based 的三个前提是什么?缺"小步提交"会造成什么?
  3. 为什么"两个开关的组合"会出事?2^N 的组合该怎么测?
  4. GitHub Flow 的成本为什么取决于"评审速度"?
  5. 三个判据里哪一个最硬?为什么"测试自动化弱"不该直提主干?
  6. 判断"该不该换模型"的那个问题是什么?
S06-A21 · 分支模型的代价:trunk-based 为什么不是"更先进"
https://www.clxhxhhr.top/posts/6595/
作者
clxstart
发布于
2024-12-31
许可协议
CC BY-NC-SA 4.0
评论
0 条
还没有评论,先写一条吧。