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 的核心原則
- 唯一的長期 branch 是 main(trunk)
- 所有工程師每天至少 commit 一次到 main
- Feature branch 存活不超過 1-2 天,commit 就 merge
- 未完成的功能用 feature flag 隱藏,不用 branch 隔離
- 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 Flow | Trunk-based | |
|---|---|---|
| Long-lived branches | main, develop, release | main only |
| Feature branch 壽命 | 數週 | 1-2 天 |
| 整合頻率 | 每個 feature 完成後 | 每天多次 |
| 未完成功能的隔離 | branch | feature flag |
| Release 策略 | release branch | deploy 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 是讓部署頻率從「每週一次」到「每天多次」的關鍵轉變。