項目管理--git分支模型

我們公司的軟件產品迭代採用的是scrum敏捷開發流程,代碼使用git進行版本管理。在新人最初的幾次開發任務中,我對於git的使用也僅限於一些基本的命令,包括:add、commit、rebase、cherry-pick、push、checkout等等。
直到有一天,我發現遠程分支上存在着一些歷史feature分支,這對於我這個初入職場的小白來說還是有些好奇:feature分支在本地建立不就行了嗎?爲何還需要推送到遠程倉庫?
帶着這一些列的疑問,我仔細研究了一些我們基於gerrit的code review流程,終於明白了爲何會有feature遠程分支。這一切都與git的分支模型有關。
期間,我在一個英文博客上看到了一篇關於git分支模型的介紹,看完後覺得不錯,對其進行簡要地整理,以呈現給大家。

分權集中

下圖中心的倉庫,是我們建立並在使用的倉庫,具有分支模型,其通常會被認爲是“真正的中心倉庫”。然而,事實上,其僅僅是被認爲是中心倉庫而已,因爲git作爲一個分佈式版本控制系統(DVCS),在技術層面並不存在哪個倉庫是中心倉庫。而這個被認爲是“中心”的倉庫,我們更願意稱之爲origin,這個名字對於所有git用戶都是很熟悉的。

每個開發者都會從origin進行pull或向其進行push操作。但是除了與origin具有push-pull關係之外,開發者們還可能從其他同級的夥伴那裏pull最新的改動,從而形成一個sub team。比如,對於兩個以上的開發者,在過早地向origin推送開發進展之前,其可以開闢一個新的feature分支來共同工作。如上圖所示,存在着這樣幾個開發小組:Alice & Bob,Alice & David,Clair & David。

從技術角度而言,這僅僅意味着Alice定義了一個遠程倉庫,名字是Bob,其指向了Bob的倉庫,反之亦然,僅此而已。

主分支

歸根到底,開發模型也受到了上述思想的影響。在中心倉庫中,在其無限的生命週期中,始終存在着兩條主分支:

  • master
  • develop

大家對origin上的master分支應該並不陌生。而另一個與之平行的分支,我們稱之爲develop分支。

origin/master:在這個分支上,源代碼的HEAD指針的指向始終都是就緒/可發佈的產品狀態。

origin/develop:在這個分支上,源代碼的HEAD指針的指向始終都是下一個版本的產品狀態。

develop分支的源代碼到達某一個可發佈的穩定點時,所有的改動都應該合併到master分支,然後打上版本的tag標籤。

因此,每次將改動合併至master分支時,意味着一個新版本的誕生。我們往往對這個過程控制得非常嚴格。所以每次master分支上有commit時,我們都應該使用git hook腳本來自動編譯、發佈軟件至產品服務器上。

支持分支

與主分支masterdevelop相鄰的則是各種支持分支,用於幫助團隊成員之間進行平行開發,跟蹤功能,準備產品發佈以及幫助修復在線產品的一些Bug。與主分支不同,這些分支總是具有有限的生命週期,因爲它們最終都是要被刪除的。

我們可能用到的幾種不同的支持分支:

  • Feature分支
  • Release分支
  • Hotfix分支

上述的每一個分支都具有特定的目的,並且必須遵守嚴格的規則。比如:哪些分支可以是它們的源頭分支,哪些分支必須是它們的合併目標。

當然,從技術角度來說,這些分支並沒有什麼特殊之處。所謂的分支類型只是我們根據如何使用它們而進行分類的。

Feature分支

規則

可以源自develop分支
必須合併到develop分支
命名:除masterdeveloprelease-*hotfix-*之外

Feature分支(也稱:topic分支)用來爲即將發佈的版本或更遠的版本開發新的feature。當開發一個新的功能的時候,我們不知道這個功能會被納入哪個目標版本。Feature分支的本質就是,只要該功能處於開發階段,feature分支就會存在,並最終會被合併至develop分支(以確保將新功能添加到即將發佈的版本中)或者丟棄(在實驗失敗的情況下)。

Feature分支通常只存在與開發者自己的倉庫中,而不是origin

創建feature分支

當開始開發一個新的功能時,需要從develop主分支中開闢一個新分支。

1
$ git checkout -b myfeature develop //表示切換到一個新的分支“myfeature”

 

將完成的功能納入develop

完成的功能可以合併至develop分支,以加入即將發佈的版本之中。

1
2
3
4
$ git checkout develop  //切換至develop分支
$ git merge --no-ff myfeature //
$ git branch -d myfeature   //刪除myfeature分支
$ git push origin develop

 

–no-ff選項會在合併分支時創建一個新的commit對象,即使合併可以是一次fast-forward操作。這可以避免丟失feature分支的歷史存在信息,並將該feature分支上的所有commit放在在一起。

如上圖所示,相比較而言,後面一種情況是不可能從git歷史記錄中看到哪些提交對象一起實現了一個功能,你必須手動讀取所有日誌信息。在後一種情況下,恢復整個功能(即一組提交)是非常困難的,而如果使用了–no-ff選項,則很容易實現。

當然,這會創建一些空的commit對象,但收益遠大於成本。

Release分支

規則

可以源自develop分支
必須合併到develop分支和master分支
命名:release-*

Release分支用於支持準備新的產品版本,它們允許對版本進行小錯誤修復和元數據準備(版本號,構建日期等)。通過在Release分支上進行所有這些工作,develop分支會被清理以接收下一個大版本的功能。

develop分支達到了新版本的期望狀態時,即可從develop分支開闢新的release分支。當然,必須要等到所有待發布的功能合併至develop分支之後纔可以。

正是在release分支的開始,即將發佈的版本會被分配版本號。直到這一刻起,develop分支“下一個版本”的改動。但是“下一個版本”會變爲0.3還是1.0,需要等到release分支開始才知道。這是在release分支開始時,由版本規則決定的。

創release分支

Release分支從develop分支創建而來。例如,1.1.5版本是當前的產品版本,我們即將有一個大的版本。develop已經爲“下一個版本”準備就緒了,並且我們已經決定這將成爲1.2版本(而不是1.1.6或2.0)。所以我們開闢一個分支,並予以相應的版本號。

1
2
3
$ git checkout -b release-1.2 develop å
$ ./bump-version.sh 1.2 
$ git commit -a -m "Bumped version number to 1.2"

 

結束release分支

當release分支的狀態已經準備好成爲y一個真正的版本,需要完成一些操作。首先,將release分支合併至master分支(master上的每一個commit都是一個新的版本)。然後,master上的commit必須被打上標籤,以便參考歷史版本。最後,將在release分支上作出的改動合併到develop分支上,以便未來的版本還包含這些錯誤修復。

1
2
3
4
5
6
7
8
9
10
// step 1
$ git checkout master å
$ git merge --no-ff release-1.2
// step 2
$ git tag -a 1.2
// step 3
$ git checkout develop
$ git merge --no-ff release-1.2
// 完成後,我們可以將release分支刪除
$ git branch -d release-1.2

Hotfix分支

規則

可以源自develop分支
必須合併到develop分支和master分支
命名:hotfix-*

Hotfix分支與release分支非常相似,其也是用於爲新的產品版本做準備,儘管是計劃之外的。它們是對發佈版本的不良狀態作出的迴應。當產品版本中的一個關鍵bug必須要被修復時,可以從master分支上相應的tag標籤中開闢一個hotfix分支。

Hotfix分支的本質是可以使develop分支上的工作得以繼續,而另外有人進行bug修復。

創建hotfix分支

Hotfix分支從master分支創建而來。例如,1.2版本是當前產品的版本號,正在在線運行,由於服務器bug出現了一些問題。但是develop分支上的改動還不穩定。我們需要開闢一個hotfix分支來進行bug修復。

1
2
3
4
5
$ git checkout -b hotfix-1.2.1 master
$ ./bump-version.sh
$ git commit -a m "Bumped version number to 1.2.1"
// 修復bug並commit
$ git commit -m "Fixed server production problem"

結束hotfix分支

當完成bug修復之後,hotfix分支需要合併到master分支,當然也需要合併至develop分支,這與release分支是非常相似的。

1
2
3
4
5
6
7
8
9
// step 1: 合併至master,打上版本標籤
$ git checkout master
$ git merge --no-ff hotfix-1.2.1
$ git tag -a 1.2.1
// step 2: 合併至develop
$ git checkout develop
$ git merge --no-ff hotfix-1.2.1
// step 3: 刪除hotfix分支
$ git branch -d hotfix-1.2.1

這裏有一個例外需要注意,當一個release分支當前還存在時,hotfix分支的修改應該合併至release分支,而不是develop分支。因爲release分支完成後,需要合併至develop分支。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章