分支策略決定了團隊如何並行開發、如何整合、以及如何發布。沒有「最好」的策略,只有「最適合當前團隊與發布節奏」的策略。本章比較四種主流模型,並提供選型決策表。
一、為什麼分支策略很重要#
分支策略本質上是在回答三個問題:
- 工作如何隔離:新功能、修復、實驗各自在哪裡進行?
- 變更如何整合:什麼時候、用什麼方式把變更合回主線?
- 版本如何發布:哪條分支代表「正式上線的程式碼」?
分支策略的核心矛盾是:分支隔離了風險,卻也延遲了整合。分支活得越久,與主線的偏離越大,最終合併時的衝突與風險也越高。
二、Git Flow#
Git Flow 是最早被廣泛採用的結構化模型,圍繞多條長命分支建立嚴謹的發布流程。
| 分支 | 角色 |
|---|---|
main | 永遠對應已上線的正式版本,每次合併都打 tag |
develop | 整合中的下一個版本 |
feature/* | 從 develop 切出,完成後合回 develop |
release/* | 準備發布,只允許修 bug 與調整版本號 |
hotfix/* | 從 main 切出緊急修復,合回 main 與 develop |
gitGraph
commit id: "init"
branch develop
checkout develop
commit
branch feature/login
checkout feature/login
commit
commit
checkout develop
merge feature/login
branch release/1.0
checkout release/1.0
commit id: "bump 1.0"
checkout main
merge release/1.0 tag: "v1.0"
checkout develop
merge release/1.0Git Flow 適合有明確版本概念、需要同時維護多個版本的產品(如桌面軟體、需長期支援的 SDK)。但對追求每日多次發布的 Web 服務而言,它的長命分支會拖慢整合節奏。
三、GitHub Flow#
GitHub Flow 極度簡化:只有一條長命分支 main,其餘都是短命的 feature 分支。
gitGraph
commit
branch feature/search
checkout feature/search
commit
commit
checkout main
merge feature/search tag: "deploy"
branch feature/cart
checkout feature/cart
commit
checkout main
merge feature/cart tag: "deploy"工作流程:
- 從
main切出描述性命名的分支(如feature/search)。 - 持續提交,推送到遠端,開啟 Pull Request。
- 通過審查與 CI 後合併回
main。 main隨時可部署,合併即發布。
GitHub Flow 假設
main永遠可部署,因此高度依賴自動化測試與 CI。適合持續部署的 Web 服務與單一正式版本的產品。
四、GitLab Flow#
GitLab Flow 在 GitHub Flow 之上補回「環境」與「版本」的概念,用環境分支或 release 分支銜接部署流程。
環境分支變體(適合持續部署到多環境):
flowchart LR
F[feature/*] -->|MR| M[main]
M -->|自動/手動推進| S[staging]
S -->|驗證後推進| P[production]main合併後自動部署到測試環境。- 通過驗證後,把
main合併進staging、再合併進production,程式碼只能單向往下游環境流動。
release 分支變體(適合需要對外發布版本號的產品):
- 從
main切出release/2.3,正式版本從這裡產生。 - 修復先進
main,再 cherry-pick 回需要的 release 分支(upstream first 原則)。
GitLab Flow 的核心原則是 upstream first:任何修復都先進入主線,再往下游分支傳播,避免下游修復遺漏回主線造成「修了又壞」。
五、Trunk-Based Development#
主幹開發(TBD)把整合做到極致:所有人都頻繁地(每天至少一次)把小變更直接整合進主幹 main,分支生命週期以小時或一兩天計。
gitGraph
commit
commit
branch short-lived
checkout short-lived
commit
checkout main
merge short-lived
commit
branch short-lived-2
checkout short-lived-2
commit
checkout main
merge short-lived-2
commit- 未完成的功能用 Feature Flags 隱藏,而非用長命分支隔離(見 ../03-ci-cd-and-pipelines/)。
- 發布時從主幹切出短命的 release 分支,或直接從主幹某個 commit 發布。
TBD 是持續整合的「原教旨」實踐,也是高效能 DevOps 團隊的常見選擇。它要求成熟的自動化測試與 Feature Flag 基礎設施,否則頻繁直推主幹會頻繁破壞建置。
六、分支拆分維度#
跳脫具體模型,分支策略其實是沿三個維度切分工作:
| 維度 | 做法 | 風險 |
|---|---|---|
| Branch by Feature | 每個功能一條分支 | 功能越大分支活越久,整合衝突越大 |
| Branch by Release | 每個發布版本一條分支 | 修復需在多版本間移植(backport) |
| Branch by Team | 每個團隊一條長命分支 | 團隊間整合被嚴重延遲,最易產生大爆炸式合併 |
Branch by Team 看似讓團隊互不干擾,實則把整合風險累積到最後一刻。團隊規模越大越應避免,改以模組化/服務化在程式碼層面解耦。
七、與持續整合的張力#
分支策略與 CI 存在本質張力:
flowchart LR
A[長命分支] -->|延遲整合| B[合併時衝突大]
B --> C[整合風險高]
D[短命分支 / 主幹開發] -->|頻繁整合| E[小步衝突]
E --> F[整合風險低]- 長命分支 提供強隔離,但每多活一天就離主線更遠,違背 CI「頻繁整合」的初衷。
- 短命分支 / 主幹開發 持續整合,衝突小而頻繁、容易處理,但要求
main隨時綠燈。
「持續整合」的字面意思就是持續地把變更整合進共用主線。任何讓分支長期不合回主線的策略,嚴格來說都在削弱 CI。
八、選型決策表#
| 因素 | Git Flow | GitHub Flow | GitLab Flow | Trunk-Based |
|---|---|---|---|---|
| 團隊規模 | 中~大 | 小~中 | 中 | 任意(含大型) |
| 發布頻率 | 低(週/月) | 高(每日) | 中~高 | 極高(持續部署) |
| 多版本維護 | 強 | 弱 | 中(release 變體) | 弱 |
| 多環境部署 | 中 | 弱 | 強(環境變體) | 中 |
| CI/自動化要求 | 中 | 高 | 高 | 極高 |
| Feature Flag 依賴 | 低 | 低 | 中 | 高 |
flowchart TD
A[選擇分支策略] --> B{需要同時維護<br/>多個發布版本?}
B -->|是| C[Git Flow 或<br/>GitLab Flow release 變體]
B -->|否| D{有成熟的 CI 與<br/>Feature Flag?}
D -->|是| E[Trunk-Based Development]
D -->|否| F{需要多環境<br/>逐級部署?}
F -->|是| G[GitLab Flow 環境變體]
F -->|否| H[GitHub Flow]不確定時,從 GitHub Flow 起步:它最簡單,且能隨團隊成熟逐步演進到 GitLab Flow 或 Trunk-Based。過早採用 Git Flow 的繁複流程,往往是團隊感受到摩擦的常見來源。
九、命名慣例#
無論選哪種策略,一致的分支命名能讓追蹤與自動化更容易:
feature/<issue-id>-short-description # 新功能
bugfix/<issue-id>-short-description # 一般修復
hotfix/<issue-id>-short-description # 緊急上線修復
release/<version> # 發布準備在分支名中嵌入 issue 編號,可讓 commit、分支、議題追蹤系統自動關聯,分支本身就成為一份可追溯的工作紀錄。延伸用法見 ../04-merge-request-workflow/。