Git Flow 的問題在哪裡

長期存活的 feature branch 有一個必然的命運:merge hell

feature-A branch 從 main 分出去三週後要 merge 回來——這三週 main 已經有 50 個 commit。解衝突可能比寫 feature 還累,而且 merge 之後的整合問題只有在合併時才會發現,此時代價最高。

CI 的全名是 Continuous Integration,但如果 feature branch 存活兩週才 merge,這根本不是「持續」整合——是「偶爾」整合。


Trunk-based Development 的核心原則

  1. 唯一的長期 branch 是 main(trunk)
  2. 所有工程師每天至少 commit 一次到 main
  3. Feature branch 存活不超過 1-2 天,commit 就 merge
  4. 未完成的功能用 feature flag 隱藏,不用 branch 隔離
  5. Main 永遠是可部署的狀態(每個 commit 都通過 CI)

Feature Flag:程式碼和功能可見性分離

Feature flag(也叫 feature toggle)讓你 commit 了還沒完成的 code,但用戶看不到:

# 用 LaunchDarkly / GrowthBook / 環境變數 控制
if feature_flags.is_enabled("new_checkout_flow", user):
    return NewCheckoutView()
else:
    return OldCheckoutView()

這讓:

  • Code 可以 merge 到 main(不阻擋別人)
  • 功能可以對特定用戶 / 百分比 用戶做 canary release
  • 上線後發現問題可以立刻關掉 flag,不需要 revert + redeploy

Feature flag 的代價:code 裡多了分支邏輯,需要在功能穩定後清理舊路徑。沒有清理計畫的 feature flag 會變成技術債。


和 Git Flow 的對比

Git FlowTrunk-based
Long-lived branchesmain, develop, releasemain only
Feature branch 壽命數週1-2 天
整合頻率每個 feature 完成後每天多次
未完成功能的隔離branchfeature flag
Release 策略release branchdeploy from main + feature flag

誰適合 Trunk-based Development

適合

  • 有自動化測試覆蓋率高的 codebase(commit 到 main 不會搞壞東西)
  • CI 執行時間短(<10 分鐘能知道是否通過)
  • 團隊工程師有足夠的 discipline(能 commit 小的、可整合的單元)
  • 微服務或前後端分離(不同服務可以獨立部署)

不適合(或需要調整)

  • open source 貢獻型 workflow(外部貢獻者不能直接 push to main)
  • 有嚴格 release 節奏的行動 app(App Store review 週期)
  • 測試覆蓋率很低的舊 codebase

Google、Facebook、Spotify 都是 trunk-based development 的實踐者。對大多數有 CI/CD 的產品公司,trunk-based 是讓部署頻率從「每週一次」到「每天多次」的關鍵轉變。