Trunk-Based Development — 什么是主干开发、原则及在单一分支中工作

作者: IT Sectr 发布日期: 2026-05-11 阅读时间: 8 分钟

Trunk-Based Development(主干开发)是一种开发实践,所有更改都合并到单一主干分支(trunk)中,无需长期存在的 feature 分支。根据 trunkbaseddevelopment.com, 2024Trunk-Based Development 涉及短期分支(1–2 天)或使用功能切换直接提交到主干。这种方法与持续集成和持续部署(CI/CD)相结合,并减少了合并冲突的数量。

要点

  • Trunk-Based Development(TBD) — 所有开发人员在一个分支(主干)中工作,使用最长 1–2 天的短期分支。
  • 功能切换(Feature Toggles) 取代 feature 分支:未完成的代码隐藏在条件标志后面,并在准备好时启用。
  • 持续集成 是强制性的:每次提交到主干都要通过构建、测试和代码检查,这可以防止主分支被破坏。
  • 提交大小 — 小批量、频繁的提交(每一两个小时一次),而不是在功能结束时进行一次大型合并请求。
  • 通过抽象分支(Branch by Abstraction) — 大规模变更的技术:创建一个抽象层,在其下逐步替换实现而无需分支。

什么是 Trunk-Based Development?

Trunk-Based Development(TBD) — 一种版本管理方法,所有开发人员每天多次将他们的更改集成到一个单一主分支(主干、main 或 master)中。与使用长期存在的 feature 分支的 Git Flow 不同,TBD 将分支的生命周期缩短到几小时,很少到 1–2 天。主要目标是避免「合并地狱」(merge hell),即当一个大功能经过数周开发后才与主干合并时发生的情况。

根据 Google Cloud DevOps, 2024Trunk-Based Development 是高绩效 DevOps 团队的关键实践之一。State of DevOps Report(Puppet, 2023)的研究表明,使用 TBD 的团队从故障中恢复的速度快 30%,在生产中遇到严重缺陷的概率低 50%。TBD 对于持续部署是强制性的。

Trunk-Based Development 并不意味着开发人员不经验证就直接提交到主干。在 TBD 中,使用短期 feature 分支,在创建合并请求和快速代码审查(几小时内)后合并到主干。如果审查超过一天 — 意味着该功能需要分解为更小的部分。

State of DevOps Report:关于 TBD 的数据

年度 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。

kotlin
// 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()
}

Trunk-Based Development 中的 CI/CD:强制实践

持续集成(CI) — TBD 最重要的组成部分。每次推送到主干(或合并请求前的临时分支)都会触发完整的流水线:构建、单元测试、集成测试、代码检查、静态分析、代码覆盖率检查。如果至少有一个阶段失败 — 更改的作者在下一次提交前修复代码。「主干被破坏 — 开发停止」是 TBD 的主要规则。

根据 Jez Humble, Continuous Delivery, 2024Trunk-Based Development 需要 CI 流水线在 10–15 分钟内执行。如果构建时间更长 — 开发人员提交的频率降低,这就破坏了 TBD 的意义。在 Android 和 iOS 移动项目中,构建可能需要 20–30 分钟,这使得 TBD 不太方便。在这种情况下,团队使用带有即时 CI 的短期 feature 分支(1 天分支)。

yaml
# 用于 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

短期分支:TBD 中的工作规则

短期分支(short-lived branches)— 纯 TBD(直接提交到主干)和 Git Flow 之间的折衷。分支存活不超过 1–2 天,包含 1–3 次提交的更改,并在审查后(等待不超过 4 小时)合并到主干。如果功能需要更多时间 — 将其分解为子任务,每个子任务都有自己的短期分支。

根据 TBD Documentation, 2024短期分支规则:分支从最新的主干创建(不超过 1 小时),不通过合并/变基与主干同步(如果超过 4 小时 — 创建新分支),合并请求在第一次提交后立即创建(即使工作未完成 — 作为草稿)。

预测试提交:有保证的提交

对于 Trunk-Based Development,预测试提交技术很重要:开发人员在提交前在自己的分支中运行 CI 流水线,只有状态为绿色时提交才能进入主干。在 GitLab 中,这通过合并请求流水线和「流水线成功后合并」选项实现。在 GitHub 中 — 通过带有必需状态检查的分支保护规则。这确保主干永远不会包含损坏的代码。

  • 1–2 天 — 短期分支的最长生命周期
  • 1–3 次提交 — 最佳更改大小
  • 4 小时 — 代码审查的最长等待时间
  • 立即创建合并请求 在第一次提交后,即使是草稿状态

通过抽象分支:无需分支的代码替换

通过抽象分支(Branch by Abstraction) — 一种允许替换或显著更改系统部分而无需创建长期 feature 分支的技术。不是在 Git 中分支,开发人员创建一个抽象层(接口),旧的和新的实现都在其下工作。所有消费者逐步迁移到新实现,之后删除旧实现。

根据 Branch by Abstraction, 2024通过抽象分支的步骤:1)为要替换的组件创建抽象,2)在抽象下实现新版本,3)通过配置将消费者切换到新实现,4)删除旧实现。所有步骤以小批量提交到主干,每个步骤都不会破坏 CI/CD。

TBD 与 Git Flow:方法比较

Trunk-Based Development 和 Git Flow — 两种对立的分支管理方法。Git Flow 使用长期分支和严格的层次结构,TBD — 使用一个分支和短集成周期。两者之间的选择取决于团队规模、发布频率和 CI/CD 自动化水平。

参数Trunk-Based DevelopmentGit Flow
分支一个(主干)+ 短期分支五种类型(main, develop, feature, release, hotfix)
分支生命周期几小时–1 天数天–数周
Feature 分支不推荐主要机制
功能切换强制可选
CI 强制性绝对建议
持续部署兼容困难
复杂性

实施 Trunk-Based Development 时的常见错误

TBD 错误 通常与 CI/CD 不足或提交纪律薄弱有关。第一个错误 — 在没有 CI 的情况下实施 TBD,在第一次失败的提交时就崩溃。如果主干不能在 15 分钟内修复 — 团队失去对流程的信任并回到长分支。第二个 — 允许「仅限此功能」的长期分支,破坏整个概念。

根据 Paul Hammant, 2023,第三个错误 — 代码的模块化差。Trunk-Based Development 要求代码被划分为独立的模块。如果对一个类的更改破坏了三个其他模块 — 开发人员无法以小批量提交。第四个 — 忽略功能切换:尝试提交没有标志的未完成代码会导致整个团队的主干被破坏。

移动开发中的 Trunk-Based Development

Trunk-Based Development 在移动项目中具有特殊性,因为构建时间长(Android 和 iOS 为 20–30 分钟)和质量要求严格。GoogleSpotify 在移动开发中使用 TBD,采用短期分支并在合并前强制通过 CI。功能切换通过 Firebase Remote Config 或 LaunchDarkly 进行管理。

根据 LaunchDarkly Docs, 2024,在移动开发中,TBD 提供了优势:功能在 trunk 中与其余代码一起在发布日期之前进行测试,从而降低了集成问题的风险。如果 CI 流水线耗时超过 15 分钟 — 最佳选择是 1 天的短期分支,每次推送时自动运行 CI。对于 Apple App Store 和 Google Play,TBD 需要通过功能切换配置分阶段推出。

功能标志即服务:LaunchDarkly 和 Firebase

在 TBD 中管理 功能切换 使用的平台:LaunchDarkly(企业级,完整功能)、Firebase Remote Config(小型项目免费)、Split.io(开源)。它们提供:按用户百分比定向启用功能、A/B 测试、使用监控和错误时自动禁用。在移动项目中,Firebase Remote Config 是最受欢迎的选择,因为它与 Firebase 集成且免费阈值高达 1000 用户。

常见问题

用简单的话说什么是 Trunk-Based Development?

Trunk-Based Development(TBD) — 所有开发人员在一个主分支(主干)中工作,每天多次以小批量提交代码的方法。这减少了合并冲突并加速了持续集成。

TBD 与 Git Flow 有何不同?

在 TBD 中 没有长期存在的 feature 分支和单独的 develop 分支。所有更改快速合并到主干中,未完成的代码隐藏在功能切换后面。Git Flow 使用长分支和通过发布和热修复的严格合并过程。

Trunk-Based Development 中需要功能切换吗?

是的,功能切换 — TBD 的关键机制。它们允许将未完成的代码提交到主干而不会破坏主分支。功能隐藏在一个标志后面,准备好时启用。这取代了 Git Flow 的 feature 分支。

如何在移动项目中实施 TBD?

从 CI/CD 开始:流水线应在 15–30 分钟内执行。实施功能切换(Firebase Remote Config, LaunchDarkly)。使用 1–2 天的短期分支和快速代码审查。将大功能分解为小的子任务。

Trunk-Based Development 的风险是什么?

主要风险 — 主干被破坏会阻塞整个团队。没有快速的 CI(10–15 分钟)和小提交的纪律,TBD 无法工作。还需要高质量的模块化架构和使用功能切换的经验。

总结

  • Trunk-Based Development — 在一个主分支中工作,使用 1–2 天的短期分支
  • 功能切换 — 在 trunk 中管理未完成代码可见性的主要机制
  • CI/CD 是强制性的:每次提交通过完整流水线,主干被破坏需要立即修复
  • 短期分支 — 最长 1 天,1–3 次提交,审查不超过 4 小时
  • 通过抽象分支 — 通过抽象层进行大规模变更而无需长分支的技术
  • TBD 减少合并冲突并加速交付,但需要 CI/CD 和模块化架构
  • 在移动开发中,由于构��时间较长,TBD 与短期分支一起使用

我们将开发一款交钥匙移动应用程序

IT Sectr自2017年以来为初创企业和企业打造iOS和Android应用程序。我们将为您提供咨询并提出最佳解决方案。

讨论项目

另请阅读