Trunk Based Development

Trunk Based Development(主幹開發,簡稱 TBD)是一種 Git 分支策略。它的核心精神是:所有開發者都圍繞著同一條主幹分支(trunk,通常就是 main)進行協作,並且頻繁地(至少每天一次)將自己的修改整合回主幹。

核心規則

  • 只有一條長期存在的分支:main(也就是 trunk)。
  • 功能分支(feature branch)即使存在,也是短命的,生命週期通常以「小時」或「一兩天」為單位,完成後立刻合併回主幹並刪除。
  • 主幹必須隨時保持在可發布的狀態,每一次合併進來的程式碼都要能通過建置與自動化測試。
  • 不應該長期維護 developreleasefeature/* 等多條平行的長壽分支。
main:  A───B───C───D───E───F  (隨時可發布)
            \   \       /
             \   └─ 短命分支(數小時內合併)
              └──── 短命分支

與 Git Flow 的差異

很多團隊熟悉的是 Git Flow,它有 maindevelopfeature/*release/*hotfix/* 等多條長壽分支。兩者的差別大致如下:

比較項目 Git Flow Trunk Based Development
長壽分支數量 多(main、develop、release…) 一條(main)
分支存活時間 長,可能數週 短,數小時到一兩天
整合頻率 低,接近發布時才大量整合 高,每天多次
合併衝突 容易累積成大型衝突 小且頻繁,容易解決
適合的發布節奏 版本式、週期較長的發布 持續交付 / 持續部署

優點

  1. 減少合併衝突(merge hell):因為每個人都頻繁地把小批量的修改合進主幹,每次整合的差異都很小,衝突自然又小又好解。相對地,長壽分支拖越久,最後合併時的衝突就越痛苦。
  2. 更快得到回饋:程式碼很快進到主幹並跑過自動化測試,問題能在第一時間被發現,而不是累積到發布前才爆發。
  3. 降低整合風險:「持續整合(Continuous Integration)」這個詞的本意就是「持續地把大家的程式碼整合在一起」。TBD 才是真正落實 CI 精神的分支策略。
  4. 單一事實來源:所有人看的都是同一條 main,不會出現「到底哪條分支才是最新的?」這種困惑。
  5. 更容易做持續部署:主幹隨時可發布,搭配自動化流程就能做到一天部署多次。

為什麼在敏捷開發下會是比較好的選擇

敏捷開發強調小步快跑、快速迭代、儘早且持續地交付可用的軟體。Trunk Based Development 的特性正好支撐這些目標:

  • 小批量交付:敏捷希望把工作切成小塊、頻繁交付。TBD 的短命分支與頻繁整合,天然鼓勵把工作拆小。
  • 快速回饋迴圈:敏捷重視快速回饋。程式碼越快進到主幹、越快跑測試,就越快知道方向對不對。
  • 擁抱變化:當每次整合的差異都很小,要調整方向、回退、重做的成本也低,符合敏捷「擁抱變化」的精神。
  • 支撐 CI/CD:敏捷團隊通常搭配持續整合與持續交付,而 TBD 是讓 CI/CD 真正運作起來的前提——分支拖太久,CI 就名存實亡。

TBD 的好處來自於完善的 CI

Trunk Based Development 並不是「無條件地比較好」,它有前提。 它的優點是建立在以下配套之上的:

  • 完善的自動化測試:因為主幹要隨時可發布,必須靠自動化測試把關,否則頻繁整合反而會頻繁地把 bug 帶進主幹。
  • Feature Flag(功能旗標):當一個功能還沒做完、卻又要頻繁合進主幹時,常用 feature flag 把未完成的功能藏起來,先合併、但先不啟用。
  • 小而頻繁的提交習慣與快速的 code review 文化:分支要能短命,review 就不能變成瓶頸。

換句話說,TBD 與其說是一條「規定」,不如說是一套「需要團隊紀律與自動化基礎設施支撐的實踐」。在缺乏自動化測試、團隊還不習慣小步提交的情況下貿然導入,可能會踩到「主幹常常壞掉」的坑。先把測試與 CI 補起來,再導入 TBD,會順利很多。

實務上的常見做法

  • 直接在 main 上做小修改,或開生命週期極短的分支,當天合併。
  • 透過 Pull Request 搭配自動化測試與 code review 把關,但要追求快速 review、快速合併
  • 用 feature flag 隱藏尚未完成或尚未要上線的功能。
  • 需要對外發布版本時,從 main 拉出一條 release 分支(這條 release 分支本身也是短命的,只用來打 tag 與必要的修補),而不是長期維護它。

參考資料