分支策略概述#

分支策略是持續交付的基石。選擇正確的分支策略,可以讓團隊的協作更加順暢,減少整合衝突,提高交付效率。

沒有「最好」的分支策略,只有「最適合」的分支策略。選擇時需要考慮團隊規模、發布頻率、產品特性等因素。

主流分支策略比較#

主幹開發(Trunk-Based Development)#

主幹開發是最簡單也是最激進的分支策略:所有開發人員直接在主幹(main/master)上工作,或使用非常短命的特性分支(存活時間不超過一天)。

核心原則:

  • 保持主幹隨時可發布
  • 頻繁整合,每天至少一次
  • 使用特性開關(Feature Toggle)控制未完成功能

適用場景:

  • 持續部署的團隊
  • 有完善自動化測試的項目
  • 團隊成員經驗豐富,程式碼品質穩定
main ─────●─────●─────●─────●─────●─────→
          ↑     ↑     ↑     ↑     ↑
          │     │     │     │     │
        直接提交或短命分支(< 1 天)

主幹開發對團隊能力和基礎設施要求較高。如果自動化測試不完善,直接在主幹上工作可能導致頻繁的建構失敗。

Git Flow#

Git Flow 是一種功能完備的分支模型,由 Vincent Driessen 在 2010 年提出,適合有計劃發布週期的項目。

分支類型:

分支用途生命週期
main生產環境程式碼永久
develop開發主線永久
feature/*新功能開發臨時
release/*版本發布準備臨時
hotfix/*緊急修復臨時

工作流程:

main     ─────────────●───────────●─────────→
                      ↑           ↑
                      │           │
release  ─────────────●───────────●
                      ↑           ↑
                      │           │
develop  ────●────●───●────●──────●────●────→
             ↑    ↑        ↑      ↑
             │    │        │      │
feature/A ───●    │        │      │
                  │        │      │
feature/B ────────●────────●      │
                                  │
feature/C ────────────────────────●

優點:

  • 結構清晰,職責分明
  • 支援並行開發多個版本
  • 適合有固定發布週期的項目

缺點:

  • 流程複雜,學習成本高
  • 分支切換頻繁,容易出錯
  • 不適合持續部署

GitHub Flow#

GitHub Flow 是 GitHub 推薦的簡化工作流,核心理念是「主幹即生產」。

工作流程:

  1. 從 main 建立特性分支
  2. 在特性分支上開發和提交
  3. 建立 Pull Request
  4. 程式碼審查和討論
  5. 部署到預覽環境測試
  6. 合併到 main 並部署到生產
main      ─────────────●───────────●─────────→
                       ↑           ↑
                       │           │
feature/A ─────────────●           │
                                   │
feature/B ─────────────────────────●

GitHub Flow 的關鍵是:main 分支上的任何程式碼都是可部署的。這要求有完善的自動化測試和 CI/CD 流水線。

GitLab Flow#

GitLab Flow 是 GitHub Flow 的延伸,增加了環境分支的概念,更適合需要多環境部署的場景。

分支類型:

main        → 開發主線
pre-prod    → 預生產環境
production  → 生產環境

工作流程:

production   ─────────────────────●─────────●─────→
                                  ↑         ↑
                                  │         │
pre-prod     ─────────────●───────●─────────●─────→
                          ↑       ↑         ↑
                          │       │         │
main         ────●────●───●───●───●────●────●─────→
                 ↑    ↑       ↑   ↑    ↑
                 │    │       │   │    │
              特性分支開發

分支策略選擇指南#

因素主幹開發Git FlowGitHub FlowGitLab Flow
團隊規模小型中大型小中型中大型
發布頻率持續固定週期高頻高頻
複雜度
適合場景持續部署版本軟體Web 應用多環境部署
特性開關(Feature Toggle)

特性開關是主幹開發的關鍵技術,允許在程式碼中控制功能的啟用和停用。

常見類型:

類型用途生命週期
發布開關控制未完成功能短期
實驗開關A/B 測試中期
維運開關緊急關閉功能長期
權限開關控制功能權限永久

實作範例(偽程式碼):

if (featureToggle.isEnabled("new-checkout-flow")) {
    return newCheckoutService.process(order);
} else {
    return legacyCheckoutService.process(order);
}

注意事項:

  • 及時清理過期的開關
  • 維護開關的文檔
  • 測試開關的各種狀態組合

依賴管理#

良好的依賴管理是持續交付的重要組成部分,可以避免「在我電腦上能跑」的窘境。

Maven 依賴管理最佳實踐#

1. 使用依賴清單(BOM)

BOM(Bill of Materials)可以統一管理多個相關套件的版本:

<dependencyManagement>
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-dependencies</artifactId>
            <version>2.7.0</version>
            <type>pom</type>
            <scope>import</scope>
        </dependency>
    </dependencies>
</dependencyManagement>

2. 父 POM 繼承

建立組織級的父 POM,統一管理:

  • 公共依賴版本
  • 外掛程式組態
  • 建構設定
<parent>
    <groupId>com.company</groupId>
    <artifactId>company-parent</artifactId>
    <version>1.0.0</version>
</parent>

3. 依賴收斂

依賴衝突是 Java 專案的常見問題。當同一個套件被不同版本間接引入時,可能導致難以排查的執行期錯誤。

解決方法:

  • 使用 mvn dependency:tree 分析依賴樹
  • 使用 <exclusions> 排除衝突依賴
  • 使用 Maven Enforcer 外掛程式強制依賴收斂
<plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-enforcer-plugin</artifactId>
    <executions>
        <execution>
            <goals>
                <goal>enforce</goal>
            </goals>
            <configuration>
                <rules>
                    <dependencyConvergence/>
                </rules>
            </configuration>
        </execution>
    </executions>
</plugin>

私有倉庫管理#

組織應該建立私有 Maven 倉庫(如 Nexus、Artifactory),用於:

  • 快取公共套件,加速建構
  • 發布內部套件
  • 控制外部依賴的准入

程式碼回滾#

程式碼回滾是持續交付的安全網,理解不同場景下的回滾策略至關重要。

回滾場景分類#

場景一:個人分支回滾

在個人開發分支上撤銷提交,可以使用 git reset

# 撤銷最近一次提交,保留工作區變更
git reset --soft HEAD~1

# 撤銷最近一次提交,丟棄工作區變更
git reset --hard HEAD~1

# 強制推送到遠端(僅限個人分支)
git push -f origin feature/my-branch

git reset --hardgit push -f 是危險操作,會重寫歷史。絕對不要在共享分支(如 main、develop)上使用。

場景二:整合分支回滾

在已經合併到主幹的程式碼上回滾,應該使用 git revert

# 撤銷某次提交,建立一個新的反向提交
git revert <commit-hash>

# 撤銷一個合併提交
git revert -m 1 <merge-commit-hash>

git revert 的優點:

  • 不會重寫歷史
  • 可以追溯回滾記錄
  • 安全地用於共享分支

Reset vs Revert 比較#

特性git resetgit revert
歷史記錄重寫歷史保留歷史
適用分支個人分支共享分支
協作影響影響他人不影響他人
操作結果移除提交新增反向提交
緊急回滾流程

當生產環境出現問題需要緊急回滾時:

第一步:確認問題

  • 確定問題確實由最近的發布引起
  • 評估影響範圍

第二步:執行回滾

# 方法一:部署回滾(推薦)
# 在 CI/CD 系統中重新部署上一個穩定版本

# 方法二:程式碼回滾
git revert <problematic-commit>
git push origin main
# 觸發 CI/CD 流水線

第三步:事後分析

  • 記錄問題原因
  • 更新測試用例
  • 改進發布流程

團隊分支實踐案例#

以下是一個「兩個披薩團隊」的週迭代分支管理實踐:

週一:迭代開始#

# 從 main 建立本週的特性分支
git checkout main
git pull origin main
git checkout -b feature/sprint-42-user-profile

週二至週四:開發階段#

# 每天同步主幹變更
git fetch origin main
git rebase origin/main

# 頻繁提交小變更
git add .
git commit -m "feat: add avatar upload component"

提交訊息應該遵循 Conventional Commits 規範:

  • feat: 新功能
  • fix: 錯誤修復
  • docs: 文檔變更
  • refactor: 重構
  • test: 測試相關

週五:整合與發布#

# 最後一次同步主幹
git fetch origin main
git rebase origin/main

# 推送並建立 Pull Request
git push origin feature/sprint-42-user-profile

Pull Request 流程:

  1. 自動化測試通過
  2. 至少一位同事審查
  3. 解決審查意見
  4. 合併到 main
  5. 自動部署到測試環境
  6. 驗證後部署到生產

分支命名規範#

前綴用途範例
feature/新功能feature/user-auth
fix/錯誤修復fix/login-timeout
hotfix/緊急修復hotfix/security-patch
refactor/重構refactor/api-layer
docs/文檔docs/api-guide

總結#

程式碼管理是持續交付的基礎設施,良好的分支策略和版本控制實踐可以顯著提升團隊效率。

關鍵要點:

  1. 根據團隊特點選擇合適的分支策略
  2. 保持主幹的健康狀態,確保隨時可發布
  3. 建立完善的依賴管理機制
  4. 理解不同場景下的回滾策略
  5. 遵循一致的提交和分支命名規範

工具和流程都是為人服務的。分支策略的最終目標是提升團隊協作效率,而不是增加流程負擔。如果現有策略造成太多摩擦,應該及時調整。