為發布建立分支

分支:只在必要時使用,提交政策不相容時使用,盡可能延遲建立,以及用來取代凍結版本。

— Laura Wingerd & Christopher Seiwald
(1998 年《Perforce 版本控制系統的高階軟體配置管理最佳實踐白皮書》)

如果一個團隊每月進行一次產品發布,他們通常也會在計劃的發布週期內推出錯誤修復版本。為了便於這一過程,基於主幹的開發團隊通常會在發布前幾天根據實際需要建立一個發布分支。這個分支將成為一個穩定的地方,因為開發者仍以全速向主幹提交他們的程式碼。

根據 Wingerd 與 Seiwald 所述,當提交政策不相容時建立分支,即發布分支「不應該繼續接收開發工作」。

(分支圖示的說明)

^ 主幹、兩個完整的發布分支、一個部分完整的發布分支、五次發布(兩次計劃的,三次非計劃的),以及兩次使用 cherry-pick 進行的錯誤修復。

持續交付團隊不採用發布分支

高產出的持續交付團隊可以忽略以下的內容。如果在正式環境中遇到問題,會選擇向前滾動的策略來解決,這意味著錯誤的修復是在主幹中完成的,並且正式環境的發布也直接從主幹進行。

誰在哪裡提交?

開發者們以最高的效率(綠點表示)向主幹提交程式碼,並且在接近建立分支或發布時不會減慢速度或凍結版本。作為一個團體,開發者們不會向發布分支提交(見下圖)。

(分支圖示的說明)

建立分支本身就是一次提交。從技術上講,譬如 Subversion 和 Perforce 版本控制系統,在這裡會有一個較大的提交,然而當今使用的版本控制系統都會將這次提交視為「輕量級」,因為它對歷史記錄或儲存的影響很小,且建立所需的時間也很短。

那個紅點是一個意外的建置中斷,不久後(以某種方式)被修復了。

推遲建立發布分支

有些團隊選擇從主幹的一個標籤發布,而不在發布時建立分支。這本身就是一種與「為發布建立分支」不同的做法

這些團隊會等到一個已發布版本出現需要修復的錯誤時,才從該發布標籤建立分支(除非他們不打算直接從主幹發布另一個版本)。

Brad Appleton 指出,許多人未意識到分支可以事後建立。這在「從標籤發布」後遇到的錯誤處理,或者即使是為小版本更新所做的修改中,這種做法都被充分利用了。

在主幹上修復正式環境錯誤

對主幹開發的團隊來說,最佳作法是在主幹上重現錯誤,隨後配合測試進行修復,並確保持續整合常駐程式可以驗證這一項修復。接著,將修復內容透過 cherry-pick 至發布分支,並等待專注於發布分支的持續整合服務同樣確認無誤。是的,用於保護主幹的持續整合流水線,在活動的發布分支上也需要做相同的設置以保護它。

Cherry-pick 不是一般的合併

Cherry-pick 會從來源分支中挑選特定的提交(或多個提交),並將其合併到目標分支。它會跳過在此之前,但在建立分支之後發生的一個或多個提交。所有版本控制系統工具都會追蹤哪些提交已經合併,哪些尚未合併,因此你可以之後進行更多的 cherry-pick。

Cherry-pick 僅應從主幹到分支進行。

你不應該在發布分支上修復錯誤,並期望將它們透過 cherry-pick 操作回到主幹。為什麼呢?因為在緊張的工作情況下,你可能會忘記這麼做。忘記這一步將導致幾週後在正式環境重新出現錯誤,並可能導致某人被解雇。如果事情在夜深人靜時由一位疲憊的開發者修復,他們想要趕快回床上休息,這種情況就可能發生。

(分支圖示的說明)

即使在各方面都在實踐主幹開發的團隊中,這條規則對於團隊來說仍然很難接受。然而,只需一次回退錯誤,就足以促使團隊改變政策。

當然,有時候你無法在主幹上重現錯誤。在這種情況下,儘管上述所有提及的,你不得不採取相反的做法,但請理解你已經引入了回退的風險。

Google 的工程師 Rachel Potvin 談論 Cherry-picks

在 2015 年 9 月舉行的 @Scale 研討會中,Google 的工程師 Rachel Potvin 在一場名為「為什麼 Google 將數十億行程式碼儲存在單一程式碼版本庫中」的演講中,於投影片中展示了一張分支圖,其中描述了 cherry-pick 操作的方法:

演講者 Rachel Potvin 在演講中(14分鐘處)說道:

「在 Google,我們實行的是主幹開發。我應該指出,正是主幹開發與集中式程式碼版本庫的結合,真正定義了原始碼管理的整體模式。對我們來說,主幹開發意味著 Piper(Google 內部使用的程式碼版本工具)使用者直接從 HEAD 進行開發,或者從最新版本的基準程式碼中建立單一的工作副本。當開發者向 Piper 提交時,他們的更改立即讓其他工程師可見且可用。在 Google 為了開發而建立分支是極為罕見的,而主幹開發之所以有益,部分原因是可以避免經常發生合併長期分支時的痛苦。然而,分支通常用於發布。因此,發布分支通常從主幹的一個快照建立,並可選擇性地將在主幹上開發的若干提交透過 cherry-pick 操作拉入分支中。

我們標註了 cherry-pick 的部分。細心的讀者會注意到 Rachel 提到主幹以外的分支是「罕見」的。我們可以俏皮地建議 Google 應該了解更多抽象分支

「合併專家」角色

在團隊中,由單一開發者或兩位開發者(如果實行極限開發)負責使用「cherry-pick」將提交從主幹挑選到發布分支。即使如此,這仍是一項兼職活動。在進行 cherry-pick 前,開發者可能需要檢查一系列規則。例如,哪位業務代表批准了合併。也許這個角色應該每天輪換一次。

有些團隊更新維基以審核哪些內容在建立分支後進入了發布分支,而有些團隊則使用需求追蹤系統,因為這種做法本質上需要中斷並要求有一個審批的審計軌跡。

修補程式版本

可能你的團隊已經從一個發布分支推出了一個版本,現在需要在正式環境中修復一個錯誤。如果發布節奏適合,那麼在主幹上修復的錯誤將透過 cherry-pick 到發布分支,然後從發布分支釋出修復錯誤的小版本號,是很好的作法。

使用標籤而非分支

如果可能的話,對許多團隊而言,從主幹上透過標籤發布是一種不錯的最佳化方式。標籤可以為發布編號(例如 v1.1.1),從而完全避免使用分支。如果正式環境中出現錯誤,可以從該標籤追溯性地建立一個分支,並且發布修補程式版本(見上文)。

發布分支的刪除

發布分支在其發布活動結束後的一段時間內會被刪除。不會立即刪除,直到確定該版本不會在正式環境中運行時,便會進行刪除。發布分支不會被合併回主幹。通常是在後續的發布分支已經上線時才進行刪除。在所有的版本控制系統中,這是一項無害的整理活動,分支都可以輕鬆地再次恢復。在 Git 中,在刪除發布分支之前,需要從已發布的提交建立一個標籤,因為懸空的提交將會被垃圾回收。

其他參考資料

顯示參考資料

1998, White Paper
High-level Best Practices in Software Configuration Management
2018, Edward Thompson on MSDN
Release Flow: How We Do Branching on the VSTS Team