替代的分支模型

分支:僅在必要時建立,遇到不相容的政策或已經過期時,選擇建立分支而不是凍結版本。

— Laura Wingerd & Christopher Seiwald
( 1998 年的 Perforce 高層次 SCM 最佳實踐白皮書)

現代主張的高吞吐量分支模型

GitHub Flow

這與以 PR 為中心的主幹開發非常接近。為什麼呢?因為這是一種分支模型,其中個別開發者或者是配對開發者同時在多個(短暫存在的)分支(或 fork)中活動。

關鍵的區別在於從哪裡進行發布。

GitHub Flow 顯示的是在合併回主幹之前從分支進行發布的步驟:

(分支圖示的說明)

這裡存在一個問題,那就是如果新版本已經推出,但相應的分支沒有及時合併回主幹,那麼下一個版本可能會小概率出現錯誤重新出現的問題。還有一點是,分支中可能缺少主幹上原本應有的某些東西,這些東西是之前版本中的一部分(這種情況實際上也會造成錯誤重新出現)。

就像 GitHub 文件中所說的,審查評論是流程的一部分。評論在時間線上像對話氣泡一樣出現,之後會有另一個提交,這個提交通常是用來回應審查意見的。

主幹開發如何修改 GitHub Flow 模型:

(分支圖示的說明)

當一切塵埃落定,短期功能分支被刪除後,提交的記錄不會像在 Subversion 和 Perforce 中那樣被合併成一個更大的提交。相反,它們會各自排列在提交歷史中的相應位置,這樣的提交歷史並不像我們在這裡展示的那樣線性:

(分支圖示的說明)

當然,如果你將一系列提交進行 rebase 或合併(squash),它們可以作為一個單一的提交進入主幹。而且,即使分支被刪除,審查評論也會保留下來。

請參見 GitHub Flow 的登陸頁面了解更多資訊

GitFlow 及類似流程

GitFlow 是與主幹開發相互矛盾的。

在現代,有許多人推崇這種模型,認為它有很大的擴展空間,並且幾乎沒有缺點。這是一種分支模型,能讓一組開發者可以同時在多個分支(或分叉)上進行活動

(分支圖示的說明)

  • 從 Vincent Driessen 2010 年的文章 A successful Git branching model 中複製的圖表

看起來你無法使用這種分支模型進行連續發布的並行開發,或者利用功能標誌抽象分支來降低風險。

傳統分支模型

多個主幹

這表面上看起來沒問題,但有很多陷阱。建議不要使用這種模型。

有些人會使用單一版本庫,但包含多個主幹(和許多分支——不論是否為發布分支)。這在沒有大小限制(包括歷史記錄)的版本控制系統中並不少見。這樣做至少允許在多個主幹之間進行原子提交,這在進行大規模重構時會發生,而原子提交始終是可行的。

root/    
  module_one/
    branches/
      rel_1.0.0/
      rel_1.1.0/          
    trunk/      
      build_file.xml
      src/
        # 產品程式碼的目錄結構
        # 測試程式碼的目錄結構
  module_two/
    branches/
      rel_1.0.0/
      rel_1.1.0/          
    trunk/      
      build_file.xml
      src/
        # 產品程式碼的目錄結構
        # 測試程式碼的目錄結構
  module_three/
    branches/
      rel_1.0.0/
      rel_1.1.0/          
    trunk/      
      build_file.xml
      src/
        # 產品程式碼的目錄結構
        # 測試程式碼的目錄結構

如果你在程式碼版本庫中,對所有單獨的主幹採取同步發布(相同節奏),擁有多個主幹會變得不理想,而且你會需要為這些主幹進行「分支發布」。這會讓從頭建置整個專案變得更難。更好的做法是只有一個主幹,裡面具有三個模組,並使用遞迴建置系統,或現代的有向圖建置系統,比如 Buck 或 Bazel。

root/    
  branches/
    rel_1.0.0/
    rel_1.1.0/          
  trunk/      
    module_one/
      build_file.xml
      src/
        # 產品程式碼的目錄結構
        # 測試程式碼的目錄結構
      module_two/
        build_file.xml
        src/
          # 產品程式碼的目錄結構
          # 測試程式碼的目錄結構
      module_three/
        build_file.xml
        src/
          # 產品程式碼的目錄結構
          # 測試程式碼的目錄結構

這樣至少你可以建立一個代表發布的分支(隨著錯誤被修復,進行 cherry-pick)。 即使有不同的發布節奏,你也可以這樣設計主幹。只需要一個建置系統,能夠減少正在測試和部署的模組,並且跳過那些不需要的模組。參見單一版本庫擴大與收縮單一版本庫

主線

主線(Mainline)與主幹開發的概念完全相反——不要這樣做。

主線是一個在 ClearCase 實現中推廣的分支模型,它是主幹開發所反對的主要分支模型。主線是一個將永遠存在的分支✱。 基於此,團隊會建立分支來進行開發工作。當工作完成後,可以從該分支進行發布,然後進行一次大規模的合併回主幹。在發布過程中,分支可能會被凍結。

這就是主線模型的示意圖:

(分支圖示的說明)

當錯誤不可避免的發生:

(分支圖示的說明)

每次修復錯誤後,必須將其合併到主幹。這個修改後的分支圖沒有錯誤,但你應該能猜到最糟糕的分支/合併情況。如果你猜不到的話:

(分支圖示的說明)

針對上述情況的合併

  1. 1.1 版本團隊說服 1.0 版本團隊在他們分支之前,將一些東西提前(且不完整)合併回主線。
  2. 1.1 版本團隊在 1.0 版本工作看似完成後進行合併。
  3. 1.0 版本團隊將發布後的錯誤修復合併回主線,並祈禱 1.0 分支現在可以真正結束。
  4. 1.2 版本團隊說服 1.1 版本團隊在他們分支之前,將一些東西提前(且不完整)合併回主線。
  5. 1.1 版本團隊從主線進行合併,接收第 3 步的內容。
  6. 1.2 版本團隊在 1.1 版本工作看似完成後進行合併。
  7. 1.1 版本團隊將發布後的錯誤修復合併回主線,並祈禱 1.0 分支現在可以真正結束。
  8. 1.2 版本團隊從主線進行合併,接收第 7 步的內容。

所有這些妥協與計劃中的「接連開發連續版本」相違背,在很多情況下會更糟糕,特別是當開發者數量增加時。

有一點需要注意,相比於主幹開發,使用主線分支模型的團隊幾乎從不進行 cherry pick。不管什麼原因,他們都是進行「合併所有尚未合併的內容」這種合併。

最基本的是,他們使用的版本控制系統應該具有「合併點追蹤」功能。在更複雜情況下,還應該包括「僅記錄」合併,以及之後的正常合併。

✱ 我們認為,選擇「主線」模型的公司會逐漸衰退甚至消失,所以並不會一直存在。

合併

發布之後,程式碼會大量合併回主線。這些合併可能會很困難且耗時。可能團隊在項目進行過程中從主線進行合併,也可能團隊將合併推送到主線

有多少分支?

我們剛剛描述了兩個分支模型——主線和專案分支。可能這個應用在任何時候都有多個正在進行中的專案,這意味著會有多個專案分支,這會帶來更多的中間合併壓力,從而導致合併難度增加。

隨時準備發布?

根本不可能!計劃的工作需要完成,並且需要有估算來指導何時完成。缺陷需要被消除,正式的測試階段需要啟動。在這裡,我們在第一個分支圖上新增紅色、橙色和綠色來顯示已知的建置中斷、建置通過但缺少自動化測試的情況,這些可能會隱藏缺陷,綠色表示可以上線。至少對於那些缺少或無效的自動化測試在 CI 流水線中運行的最差情況:

(分支圖示的說明)

瀑布模型

瀑布模型與主幹開發不兼容——不要這麼做。

這種方法的想法是每個版本都有自己的分支,每個版本團隊每天從「上游(upstream)」分支進行合併。他們只有在 CI 伺服器顯示上游建置通過時才會這樣做。

(分支圖示的說明)

這種模型存在的問題會隨著同時處理的發布版本數量增加而加劇。上游的變化可能會導致下游難以合併的巨大變動。下游的合併開始被跳過或放棄。或者合併成功,但程式碼錯誤,因此需要在分支內進行修復,而這些修復對上游並不適用。現實情況如下(再次疊加顯示的中斷情況):

(分支圖示的說明)

請記住,在這個模型中,合併從來不是 cherry-pick ——而是合併所有尚未合併的內容(或者合併到選定的提交號碼,以便更易於處理)。

當然,只有較大的組織才需要擔心連續發布的並行開發,而且許多人可能會認為應用程式本身過於龐大(而微服務是解決方案)。

持續整合對你的分支模型的證明或反駁

這裡有個想法。配置你的 CI 伺服器,無論使用的是什麼分支模型都讓它關注每個分支。具體來說,對每個提交進行建置,並進行變革推動者中描述的推測可合併性分析。

如果所有地方都是綠色的,那麼你就可以隨時準備好發布。但是,很少有團隊能在 CI 伺服器的積極建置和分析下看到綠燈,而不是紅燈。

其他參考資料

顯示參考資料

31 Aug 2011, Blog Entry
GitHub Flow
04 Dec 2013, Blog Entry
What is Your Branching Model?
05 Apr 2013, Blog Entry
What is Trunk-Based Development?
19 Mar 2013, Blog Entry
The Cost of Unmerge
15 Oct 2015, InfoQ Interview
More Feature Branching Means Less Continuous Integration
03 May 2015, Blog Entry
GitFlow considered harmful
08 Jan 2016, Blog Entry
GITFLOW HMMMM