貓頭鷹的深夜翻譯:開發者必須瞭解的分支發佈模型

前沿

本文只會聚焦於分支發佈策略,不會涉及任何的項目細節。
分支發佈模型圖

爲什麼選擇Git

想要深入瞭解Git和中心化代碼版本管理系統的優缺點比較,可以在網上自行查詢,這個話題一直爭論不休。作爲一個開發者,我更傾向於使用Git。Git確實改變了開發者對代碼合併和分支管理的認識。作爲一個使用過傳統的CVS工具的人,合併/開分支是一個比較恐怖的行爲,迫不得已才執行一次。

但是,Git的分支合併和創建操作就非常簡單,這些操作已經被是爲每日工作流的一部分。比如,在介紹CVS的書本中,分支和合並只會在末尾的章節面向高端開發者介紹一下,而在每一本說Git的書中,基本上在第三章就會說明。

因爲Git在這個操作上的簡潔性和重複性特性,分支開發和合並不再是一件可怕的事情。版本控制工具本就應當更好的幫助分支的創建和合並。

不談工具,接着要介紹開發模型。今天我要介紹的這個模型本質上是一組流程,每個團隊成員通過遵循這一組流程來管理軟件開發過程。

去中心化又中心化

在分支發佈模型中,我們會設置一箇中心化的“真理”倉庫。這個倉庫只是名義上的中心倉庫(因爲Git是一個去中心化的倉庫,因此從技術角度上來說這個倉庫不是中心化的)。我們將該倉庫標記爲origin,因爲origin這個命名對於所有的Git用戶來說都是很熟悉的。

每個開發者從origin拉取和上傳代碼。每個開發者之間也可以從彼此的代碼倉庫拉取或構件子代碼團隊。這種方式適用於大型團隊,即子團隊可以先在一個團隊分支上進行特性開發,在特性穩定後再提交到origin倉庫。

主分支

中央倉庫持有兩個擁有永久生命週期的分支:master和develop
origin倉庫中的master主分支對每個Git用戶都是再熟悉不過的了。和master分支平齊的分支稱爲develop開發分支。

origin/master分支是項目的主分支,源代碼的HEAD標籤永遠指向了該分支上的一個可發佈版本。

我們將origin/develop分支是爲另一種類型的主分支,該分支上的代碼始終處於一個穩定的可發佈的狀態。該分支上的所有變更都應當被合併到master分支上,並搭上一個發佈標籤。具體的操作將在後文詳細描述。

因此,每當變更被合併到master分支上時,都意味着釋放了一個新的發佈版本。我們嚴格的遵循這一定義,因此理論上來說,每當有一個代碼提交至master分支上,我們應當使用Git鉤子來自動構建和發佈代碼到生產環境服務器。

輔助分支

在主分支master和develop之外,開發過程模型還使用了各種輔助分支來實現團隊成員間的並行開發,簡化功能開發,做生產發佈的準備工作和快速修復生產環境的故障。和主分支不同,這些分支都有着一定的生命週期,因爲他們最終都會被刪除。

輔助分支的類型包括:

  • 特性分支 Feature Branch
  • 發佈分支 Release Branch
  • 修復分支 Hotfix Branch

每一類分支都有着特定的目標,並且受限於不同的約束,比如該類分支應當從哪類分支中生成,最終合併到哪類分支中去。

但是這些分支從Git的角度上來說並無區別,它們就是通常意義的Git Branch,只是我們賦予了他們不同的使用語義。

特性分支 Feature Branch

來源分支:develop開發分支
合併分支:develop開發分支
分支命名規範:master, develop, release-, 和 hotfix-


特性分支是爲了支持未來上線的新功能來進行開發分支。在開始特性分支開發時,對應的未來的發佈分支可能是未知的。特性分支的精髓在於只要該特性還在開發中,該分支就會一直存在,並會最終合併回develop開發分支(確定該特性會被髮布)或是被拋棄(特性的開發結果沒有達到預期)。

特性分支一般只存在於開發者的倉庫中。

創建特性分支

$ git checkout -b myfeature develop
Switched to a new branch "myfeature"

合併開發完成的特性分支到develop分支中

$ git checkout develop
Switched to branch 'develop'
$ git merge --no-ff myfeature
Updating ea1b82a..05e9557
(Summary of changes)
$ git branch -d myfeature
Deleted branch myfeature (was 05e9557).
$ git push origin develop

--no-ff標籤使得合併操作創建一個新的提交記錄,即使該合並可以被fast-forward快速合併到目標分支中。這種方式避免了所有在feature分支上的歷史提交記錄的丟失。對比如下:

右圖中無法從Git提交歷史中看出來哪些提交記錄構成了feature分支,你需要手動閱讀所有的日誌消息。回滾特性代碼在右圖中是一件非常麻煩的事情,但是通過--no-ff合併的左圖中就比較容易。雖然它會創建更多的提交記錄,但是總的來說優點大於缺點。

發佈分支 Release Feature

來源分支:develop開發分支
合併分支:develop開發分支和master主分支
分支命名規範:release-*

發佈分支支持爲一個新的生產環境發佈做準備。它允許在上線之前進行最後的操作。除此以外,它允許小的bug修復和發佈前的元數據準備操作(版本號,構建日期等)。通過在發佈分支上做這些事情,開發分支變得更加簡潔,只需要接收未來會發布的新特性。

當開發分支基本達到了發佈一個新版本的狀態時,需要從開發分支創建一個新的發佈分支。所有滿足發佈條件的特性分支此時必須已經被合併到開發分支中。而尚未達到發佈條件的特性分支無需合併到master分支,它們必須等到發佈分支生命週期結束後才能合併到開發分支上。

在創建發佈分支時,會爲本次發佈定義一個版本號(不會早於此)。直到這一刻,用於下一次發佈的開發分支才知道自己下一次的發佈版本號爲0.3還是1.0。在發佈分支創建時會按照版本號的演進規則決定本次發佈的版本號。

創建發佈分支

發佈分支創建於開發分支。比如,假設當前生產環境的版本號爲1.1.5,並且接着會有一個重大的發佈。此時開發分支已經達到了下一次發佈的要求,並且我們決定該版本爲1.2(不是1.1.6或是2.0)。因粗我們創建分支並且在發佈分支的命名中帶上了新的版本號:

$ git checkout -b release-1.2 develop
Switched to a new branch "release-1.2"
$ ./bump-version.sh 1.2
Files modified successfully, version bumped to 1.2.
$ git commit -a -m "Bumped version number to 1.2"
[release-1.2 74d9424] Bumped version number to 1.2
1 files changed, 1 insertions(+), 1 deletions(-)

在創建了新的分支並切換到該分支上後,我們開始切換版本號。在此處,bump-version.sh是一個虛擬的shell腳本,它會在發佈版本文件上執行一些版本操作(當然了這些操作可以通過手動完成)。接着,版本操作被提交。

這個新分支會存在一段時間,直到發佈被完全執行。在此期間,可以在分支上修復bug(而非develop分支上),但是禁止添加大的新特性。它們必須先被合併到開發分支,然後等待下一個發佈節點。

結束髮布分支

當發佈分支確實可以發佈時,在此之前需要執行一些操作。首先,發佈分支被合併到master分支上。接着,提交到master分支上的代碼必須打上標籤,從而在未來可以引用該歷史版本。最後,發佈分支上的代碼必須被合併會開發分支,使得開發分支上的代碼也包含了發佈版本的內容以及修復的bug。

$ git checkout master
Switched to branch 'master'
$ git merge --no-ff release-1.2
Merge made by recursive.
(Summary of changes)
$ git tag -a 1.2

此時發佈已經完成,並且打上了標籤以便引用。
接着將變更合併會develop分支:

$ git checkout develop
Switched to branch 'develop'
$ git merge --no-ff release-1.2
Merge made by recursive.
(Summary of changes)

這一步合併操作可能會存在衝突,需要解決衝突並提交。
在這些都完成後,我們可以刪除掉髮布分支,因爲我們不再需要該分支了:

$ git branch -d release-1.2
Deleted branch release-1.2 (was ff452fe).

修復分支 Hotfix Branch

來源分支:master主分支
合併分支:develop開發分支和master主分支
分支命名規範:hotfix-*

修復分支和發佈分支很接近,因爲它們都是爲了生產環境發佈做準備的一個分支。修復分支產生的緣由在於需要立刻對生產環境中的代碼進行快速變更。當生產環境版本代碼出現重大bug需要立刻處理時,可以從對應版本的生產環境代碼拉一個修復分支進行處理。

該分支的核心點在於團隊的其他成員可以繼續基於開發分支進行開發,而負責修復的成員可以獨立的快速修復生產環境問題。

創建修復分支

修復分支創建於master分支。比如版本1.2是當前正在運行的生產環境版本,並且因爲一個缺陷出現了故障。但是開發分支上的代碼尚不穩定。我們需要創建修復分支並開始修復問題:

$ git checkout -b hotfix-1.2.1 master
Switched to a new branch "hotfix-1.2.1"
$ ./bump-version.sh 1.2.1
Files modified successfully, version bumped to 1.2.1.
$ git commit -a -m "Bumped version number to 1.2.1"
[hotfix-1.2.1 41e61bb] Bumped version number to 1.2.1
1 files changed, 1 insertions(+), 1 deletions(-)

切換新的發佈版本後不要忘了切換代碼中的版本號
接着在一次或多次提交的代碼中修復問題。

$ git commit -m "Fixed severe production problem"
[hotfix-1.2.1 abbe5d6] Fixed severe production problem
5 files changed, 32 insertions(+), 17 deletions(-)

關閉修復分支

修復完畢後,修復分支需要合併會主分支,也需要合併回開發分支,從而確保該修復包含在下次發佈代碼中。這與發佈分支的關閉過程完全相同。
首先,更新master代碼的標籤併發布:

$ git checkout master
Switched to branch 'master'
$ git merge --no-ff hotfix-1.2.1
Merge made by recursive.
(Summary of changes)
$ git tag -a 1.2.1

接着將代碼合併回開發分支:

$ git checkout develop
Switched to branch 'develop'
$ git merge --no-ff hotfix-1.2.1
Merge made by recursive.
(Summary of changes)

這裏一個特殊點在於,如果此時存在一個發佈分支,修復分支的變更需要合併到發佈分支中,而非開發分支。合併到發佈分支中,可以最終將該修復通過發佈分支帶回到開發分支中。(如果開發分支也需要立刻修復該問題,無法等到發佈分支合並回來,也可以先將該變更安全的合併會發布分支)

$ git branch -d hotfix-1.2.1
Deleted branch hotfix-1.2.1 (was abbe5d6).
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章