Trunk-Based Development(主干开发)是一种开发实践,所有更改都合并到单一主干分支(trunk)中,无需长期存在的 feature 分支。根据 trunkbaseddevelopment.com, 2024,Trunk-Based Development 涉及短期分支(1–2 天)或使用功能切换直接提交到主干。这种方法与持续集成和持续部署(CI/CD)相结合,并减少了合并冲突的数量。
要点
Trunk-Based Development(TBD) — 一种版本管理方法,所有开发人员每天多次将他们的更改集成到一个单一主分支(主干、main 或 master)中。与使用长期存在的 feature 分支的 Git Flow 不同,TBD 将分支的生命周期缩短到几小时,很少到 1–2 天。主要目标是避免「合并地狱」(merge hell),即当一个大功能经过数周开发后才与主干合并时发生的情况。
根据 Google Cloud DevOps, 2024,Trunk-Based Development 是高绩效 DevOps 团队的关键实践之一。State of DevOps Report(Puppet, 2023)的研究表明,使用 TBD 的团队从故障中恢复的速度快 30%,在生产中遇到严重缺陷的概率低 50%。TBD 对于持续部署是强制性的。
Trunk-Based Development 并不意味着开发人员不经验证就直接提交到主干。在 TBD 中,使用短期 feature 分支,在创建合并请求和快速代码审查(几小时内)后合并到主干。如果审查超过一天 — 意味着该功能需要分解为更小的部分。
年度 State of DevOps Report(Puppet/DORA)跟踪高绩效团队的做法。自 2015 年以来,TBD 一直位列与高部署频率和低恢复时间(MTTR)相关的前三大实践。实践 TBD 的团队部署代码的频率高 2–3 倍,从故障中恢复快 30%(DORA, 2023)。
功能切换(Feature Toggles)(功能标志,feature flags)— 无需更改代码即可启用和禁用功能的机制。在 TBD 中,功能切换取代了 feature 分支:开发人员将未完成的代码提交到主干,但将其隐藏在条件标志后面。当功能准备好展示时,标志在配置中切换而无需重新部署。
根据 Martin Fowler, 2024,功能切换 分为四种类型:发布切换(管理功能可见性)、实验切换(A/B 测试)、运维切换(管理操作参数)和权限切换(按角色访问)。在移动项目中,发布切换特别有用:新功能在发布日期之前隐藏,但代码已在主干中并通过 CI/CD。
// Android 上 Kotlin 中的功能切换
object FeatureManager {
private val remoteConfig = FirebaseRemoteConfig.getInstance()
fun isEnabled(key: String): Boolean {
return remoteConfig.getBoolean(key)
}
}
// 在代码中使用
if (FeatureManager.isEnabled("new_checkout_flow")) {
showNewCheckoutScreen()
} else {
showOldCheckoutScreen()
}
持续集成(CI) — TBD 最重要的组成部分。每次推送到主干(或合并请求前的临时分支)都会触发完整的流水线:构建、单元测试、集成测试、代码检查、静态分析、代码覆盖率检查。如果至少有一个阶段失败 — 更改的作者在下一次提交前修复代码。「主干被破坏 — 开发停止」是 TBD 的主要规则。
根据 Jez Humble, Continuous Delivery, 2024,Trunk-Based Development 需要 CI 流水线在 10–15 分钟内执行。如果构建时间更长 — 开发人员提交的频率降低,这就破坏了 TBD 的意义。在 Android 和 iOS 移动项目中,构建可能需要 20–30 分钟,这使得 TBD 不太方便。在这种情况下,团队使用带有即时 CI 的短期 feature 分支(1 天分支)。
# 用于 TBD(Android)的 GitHub Actions
name: CI - TBD Check
on:
push:
branches: [main, develop]
pull_request:
branches: [main, develop]
jobs:
build-and-test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Run tests
run: ./gradlew testDebugUnitTest
- name: Static analysis
run: ./gradlew ktlintCheck detekt
短期分支(short-lived branches)— 纯 TBD(直接提交到主干)和 Git Flow 之间的折衷。分支存活不超过 1–2 天,包含 1–3 次提交的更改,并在审查后(等待不超过 4 小时)合并到主干。如果功能需要更多时间 — 将其分解为子任务,每个子任务都有自己的短期分支。
根据 TBD Documentation, 2024,短期分支规则:分支从最新的主干创建(不超过 1 小时),不通过合并/变基与主干同步(如果超过 4 小时 — 创建新分支),合并请求在第一次提交后立即创建(即使工作未完成 — 作为草稿)。
对于 Trunk-Based Development,预测试提交技术很重要:开发人员在提交前在自己的分支中运行 CI 流水线,只有状态为绿色时提交才能进入主干。在 GitLab 中,这通过合并请求流水线和「流水线成功后合并」选项实现。在 GitHub 中 — 通过带有必需状态检查的分支保护规则。这确保主干永远不会包含损坏的代码。
通过抽象分支(Branch by Abstraction) — 一种允许替换或显著更改系统部分而无需创建长期 feature 分支的技术。不是在 Git 中分支,开发人员创建一个抽象层(接口),旧的和新的实现都在其下工作。所有消费者逐步迁移到新实现,之后删除旧实现。
根据 Branch by Abstraction, 2024,通过抽象分支的步骤:1)为要替换的组件创建抽象,2)在抽象下实现新版本,3)通过配置将消费者切换到新实现,4)删除旧实现。所有步骤以小批量提交到主干,每个步骤都不会破坏 CI/CD。
Trunk-Based Development 和 Git Flow — 两种对立的分支管理方法。Git Flow 使用长期分支和严格的层次结构,TBD — 使用一个分支和短集成周期。两者之间的选择取决于团队规模、发布频率和 CI/CD 自动化水平。
| 参数 | Trunk-Based Development | Git Flow |
|---|---|---|
| 分支 | 一个(主干)+ 短期分支 | 五种类型(main, develop, feature, release, hotfix) |
| 分支生命周期 | 几小时–1 天 | 数天–数周 |
| Feature 分支 | 不推荐 | 主要机制 |
| 功能切换 | 强制 | 可选 |
| CI 强制性 | 绝对 | 建议 |
| 持续部署 | 兼容 | 困难 |
| 复杂性 | 低 | 高 |
TBD 错误 通常与 CI/CD 不足或提交纪律薄弱有关。第一个错误 — 在没有 CI 的情况下实施 TBD,在第一次失败的提交时就崩溃。如果主干不能在 15 分钟内修复 — 团队失去对流程的信任并回到长分支。第二个 — 允许「仅限此功能」的长期分支,破坏整个概念。
根据 Paul Hammant, 2023,第三个错误 — 代码的模块化差。Trunk-Based Development 要求代码被划分为独立的模块。如果对一个类的更改破坏了三个其他模块 — 开发人员无法以小批量提交。第四个 — 忽略功能切换:尝试提交没有标志的未完成代码会导致整个团队的主干被破坏。
Trunk-Based Development 在移动项目中具有特殊性,因为构建时间长(Android 和 iOS 为 20–30 分钟)和质量要求严格。Google 和 Spotify 在移动开发中使用 TBD,采用短期分支并在合并前强制通过 CI。功能切换通过 Firebase Remote Config 或 LaunchDarkly 进行管理。
根据 LaunchDarkly Docs, 2024,在移动开发中,TBD 提供了优势:功能在 trunk 中与其余代码一起在发布日期之前进行测试,从而降低了集成问题的风险。如果 CI 流水线耗时超过 15 分钟 — 最佳选择是 1 天的短期分支,每次推送时自动运行 CI。对于 Apple App Store 和 Google Play,TBD 需要通过功能切换配置分阶段推出。
在 TBD 中管理 功能切换 使用的平台:LaunchDarkly(企业级,完整功能)、Firebase Remote Config(小型项目免费)、Split.io(开源)。它们提供:按用户百分比定向启用功能、A/B 测试、使用监控和错误时自动禁用。在移动项目中,Firebase Remote Config 是最受欢迎的选择,因为它与 Firebase 集成且免费阈值高达 1000 用户。
常见问题
Trunk-Based Development(TBD) — 所有开发人员在一个主分支(主干)中工作,每天多次以小批量提交代码的方法。这减少了合并冲突并加速了持续集成。
在 TBD 中 没有长期存在的 feature 分支和单独的 develop 分支。所有更改快速合并到主干中,未完成的代码隐藏在功能切换后面。Git Flow 使用长分支和通过发布和热修复的严格合并过程。
是的,功能切换 — TBD 的关键机制。它们允许将未完成的代码提交到主干而不会破坏主分支。功能隐藏在一个标志后面,准备好时启用。这取代了 Git Flow 的 feature 分支。
从 CI/CD 开始:流水线应在 15–30 分钟内执行。实施功能切换(Firebase Remote Config, LaunchDarkly)。使用 1–2 天的短期分支和快速代码审查。将大功能分解为小的子任务。
主要风险 — 主干被破坏会阻塞整个团队。没有快速的 CI(10–15 分钟)和小提交的纪律,TBD 无法工作。还需要高质量的模块化架构和使用功能切换的经验。
总结
我们将开发一款交钥匙移动应用程序
IT Sectr自2017年以来为初创企业和企业打造iOS和Android应用程序。我们将为您提供咨询并提出最佳解决方案。