替代的分支模型 #

分支:僅在必要時使用,當提交政策不相容時使用,盡可能推遲建立,以及作為凍結版本的替代方案。

— Laura Wingerd & Christopher Seiwald
1998 年 Perforce 使用者大會《High-Level SCM Best Practices》白皮書

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

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 伺服器的積極建置和分析下看到綠燈,而不是紅燈。

其他參考資料#

show references

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
03 May 2015, Blog Entry
GitFlow considered harmful
08 Jan 2016, Blog Entry
GITFLOW HMMMM