TBD不是分支策略选择题,而是CI/CD流水线、测试覆盖、代码审查与协作节奏的综合能力验证;需强制PR合入、每日主干集成、Feature Flag包裹未完成逻辑、release分支仅用于打补丁且单向同步回main。

Trunk-Based Development(TBD)不是“要不要用”的选择题,而是“能不能撑住”的工程能力验证。它表面是分支策略,实际是整套 CI/CD 流水线、测试覆盖、代码审查机制和团队协作节奏的总和。没配好 Feature Flag、没跑通 pre-commit + PR 自动化门禁、没做到每日至少一次主干集成,强行切 TBD 就是把 main 变成高危区。
为什么 main 分支必须只读且受保护
所谓“只读”,是指禁止直接 git push 到 main,所有合入必须走 Pull Request(或 Merge Request),由自动化流水线强制拦截。这不是为了形式主义,而是防止三类典型破坏:
- 本地未跑通
npm test或./gradlew check就推上去,导致 CI 红了 20 分钟没人敢提交 - 忘记同步
main最新变更,git merge后引入隐式冲突(比如 config 文件结构已变) - 误操作执行
git push --force-with-lease origin main,绕过保护机制,历史被重写
GitHub/GitLab 都支持 branch protection rules:勾选 “Require pull request reviews before merging”、“Require status checks to pass before merging”、“Include administrators”,再配上 require linear history 和 restrict pushes —— 这些不是可选项,是 TBD 的安全底线。
feature/xxx 分支存活时间不能超 24 小时的硬约束
超过一天的 feature/xxx 分支,本质已退化为 GitFlow 式长分支,只是名字叫得短而已。真正起作用的是“同步频率”而非“存在时长”:
- 每天至少一次从
mainrebase 或 merge,确保本地变更始终基于最新主干 - 每次同步后必须通过全部单元测试(
jest --ci/mvn test),不通过就暂停开发,先修复再继续 - 若功能确实无法 24 小时内完成,必须拆解,并用
FeatureToggle包裹未完成逻辑,保证合入后不影响现有行为
常见反模式:git checkout feature/login-v2 && git merge main 后不跑测试就直接 push —— 这等于把别人刚合入的 bug 一起打包进去了。
Feature Flag 不是锦上添花,而是主干开发的呼吸阀
没有 FeatureFlag 的 TBD,就像没刹车的车。它不是上线前才加的开关,而是在写第一行业务代码时就要决定是否包裹:
- 后端推荐用轻量方案:Spring Boot 的
@ConditionalOnProperty或自研FeatureManager.isEnabled("payment-v3") - 前端建议统一入口控制:在路由守卫或组件挂载前检查
flags.paymentV3,避免加载未完成模块引发运行时错误 - Flag 名称必须语义清晰、带版本或领域前缀,如
checkout.use-new-shipping-calculator,禁止用flag1、temp_switch这类命名 - 上线后 2 周内必须清理掉已全量的功能开关代码,否则技术债会指数级堆积
最常被忽略的一点:Flag 的状态读取必须是进程内缓存+定期刷新,不能每次请求都查数据库或远程配置中心,否则性能毛刺会直接暴露在用户侧。
发布分支 release/v1.2.x 的创建与维护原则
TBD 中的 release 分支不是用来开发的,而是用来“冻结快照+打补丁”的。它的生命周期极短,且与 main 单向同步:
- 仅在正式发布前从
main当前 HEAD 创建,例如git checkout -b release/v1.2.0 main - 该分支只允许 cherry-pick 来自
main的 hotfix commit(git cherry-pick abc123),禁止任何直接提交 - 补丁合入后,必须立即反向同步回
main(git cherry-pick回去),否则下次发布又得重复修一遍 - 版本号小数点后第三位(如
v1.2.1)只用于紧急修复,常规迭代一律走main→ 新 release 分支
容易踩的坑是:把 release 分支当成长期维护分支,在上面开子分支修 bug —— 这立刻让 TBD 退化成多主干模型,合并冲突风险回归。
真正难的从来不是“怎么建分支”,而是让每个人每天主动 rebase、每行新代码默认包裹 flag、每次 push 前本地跑完全部测试。这些动作没有魔法命令,只靠流程卡点和团队习惯。一旦松动,main 就不再是 trunk,而是一根随时可能断裂的细枝。


















