原來對于源碼管理中分支的創(chuàng)建并沒有很好的概念痊乾,只有一個簡單樸素的概念:在已經發(fā)布的以前版本上進行開發(fā)時介评,就創(chuàng)建一個分支更米;或者要同時開發(fā)兩個版本,就創(chuàng)建分支抄罕,并沒有對分支進行什么樣的管理允蚣。今天看了這篇文章(A successful Git branching model)后,對分支有了一個更好的認識呆贿,感覺在源碼管理中嚷兔,確實應該利用好分支的概念。這兒就參照前面這篇文章講的整理一下其中的內容做入。
關于Git的幾個理念
- 分支與合并:在Git中分支與合并是很平常的事情冒晰,在開發(fā)過程中要適應經常進行分支和合并操作。在Git中竟块,分支只是一個指針壶运,并不會進行物理拷貝,所以快捷易用浪秘。
- 非中心化:雖然平常都有一個Git服務器蒋情,稱為origin埠况,實際上origin跟每個開發(fā)人員機器上的代碼庫是平等的。我認為只是我們在借用它來永久保存代碼棵癣,來在各開發(fā)人員之間協(xié)同辕翰。但從技術上來說,它跟各人機器上的庫沒有什么不同狈谊。
- 分支:Git上所有的分支都是一樣的喜命,雖然一般都有一個master分支,但它與我們創(chuàng)建的其它分支并沒有什么不同的畴,只是我們在使用上區(qū)別對待而已渊抄。
總述
分支模型,主要講在開發(fā)過程中需要創(chuàng)建的幾種分支的管理方式丧裁。這兒說的“幾種”是為管理需要护桦,只是邏輯上的區(qū)分。主要有以下幾種分支:
- 主要分支:
- master
- develop
- 輔助分支:
- feature
- release
- hotfix
這個圖比較系統(tǒng)地體現了它們之間的關系:
一個分支可以認為是一個被隔離的工作空間煎娇,master和develop是兩個長期保留的工作空間二庵,其它的工作空間根據需要隨時創(chuàng)建,完成相應任務后缓呛,將工作成果合并到develop和maste上催享,然后刪除之。
主要分支
主要分支是所有開發(fā)過程中必不可少的分支哟绊。原來我都是只用master這一個因妙,現在覺得需要再加develop這一個。
master和develop是兩個并行的分支票髓,在代碼庫創(chuàng)建一開始攀涵,就把它們都建好。這兩個分支的生命周期最長洽沟,應該跟整個產品的生命周期一樣以故。主要分支都創(chuàng)建在origin上。
master分支:我們把正式發(fā)版的產品代碼放到master分支中裆操。master中的每一次提交怒详,都對應產品的一個版本,HEAD總是最新的版本踪区。
develop分支:是開發(fā)用的主要分支昆烁,HEAD反應了開發(fā)人員為開發(fā)下一版本所提交的最新狀態(tài)。這個分支常用來進行每天晚上的自動構建朽缴。
合并時機
develop分支上的代碼穩(wěn)定之后善玫,將要發(fā)版之時,將develop合并到master上,并打標簽茅郎。合并使使用--no-ff選項蜗元,避免在master上生成大量的revision。(有時在將要發(fā)版時系冗,會創(chuàng)建release分支奕扣,這時就不是develop分支直接向master合并,而是release分支分別向master和develop合并掌敬。)
每一次向master的合并惯豆,都是一次定義明確的發(fā)版,必須嚴格遵循這個約定奔害。所以理論上講楷兽,我們可以在master上加一個觸發(fā)器,每次提交時华临,自動觸發(fā)進行產品新版本的構建芯杀。
輔助分支
輔助分支是根據開發(fā)需要而創(chuàng)建的分支,它們的生命周期一般不會很長雅潭,用完(向master或develop分支合并后)就可以刪除了揭厚。
輔助分支都是為一個特定目的而創(chuàng)建的,而且扶供,對于它們應該從哪個分支上創(chuàng)建及最后應該合并到哪個分支上筛圆,都有嚴格的約束。
feature分支
- 分支來源:develop
- 最后合并:develop
- 命名規(guī)則:除master椿浓、develop太援、release-*、或 hotfix-*之外的都可以扳碍。
- 目的:feather分支是為將來版本開發(fā)一個新的功能粉寞,這個功能將要在哪個版本中體現還不一定。也可能開發(fā)了一段時間之后最后放棄不要了左腔。
feature分支有時可能只存在于開發(fā)人員的庫中,并沒有push到origin上捅儒。
新功能開發(fā)完成后液样,合并到develop分支,確定在下一個版本中體現該功能巧还。合并時也要使用--no-ff選項鞭莽。
- 創(chuàng)建feature分支
$ 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
release分支
- 分支來源:develop
- 最后合并:master和develop
- 命名規(guī)則:release-*
- 目的:用來準備一個新版本的發(fā)布。當想要發(fā)布一個新版本麸祷,但develop分支還要繼續(xù)開發(fā)下一版本時澎怒,就創(chuàng)建一個release分支來做要發(fā)布的新版本的開發(fā)工作。
可以參看最前面的那個完整的圖阶牍。
- 創(chuàng)建一個release分支
$ 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是一個假想的命令喷面,意思是要做一些關于修改版本號之類的工作星瘾。
- 完成release工作,合并分支
這個新版本發(fā)布后惧辈,一方面琳状,要合并到master上,形成一個新的版本盒齿;另一方面念逞,要把做的所有修改都合并到develop上。
$ 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
$ 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).
在release分支的開發(fā)過程中边翁,也可能多次向develop分支合并修復的bug翎承。
如果要發(fā)布新版本時,沒有同時進行下一版本的開發(fā)符匾,就沒有必要新建release分支叨咖,直接在develop分支上進行即可。等完成發(fā)版的測試工作待讳,確定要發(fā)版后芒澜,把develop分支合并到master上。
hotfix分支
- 分支來源:master
- 最后合并:master和develop
- 命名規(guī)則:hotfix-*
- 目的:對已發(fā)布的版本出現的重大bug進行修復创淡。跟release分支類似痴晦,完成修復后要發(fā)布一個新版本。
hotfix應該是對最新版本的修復琳彩。如果已經發(fā)布2.0誊酌,就不能再去在1.0上去修復出一個1.1版本,而是需要用2.0版本或修復后的2.1版本去完成bug的修復露乏。如果說由于某些限制(比如2.0跟1.0不兼容碧浊,或商務上不允許以2.0去修復1.0)而必須需要在1.0上修復出一個1.1版本,參見后面的討論瘟仿。
- 創(chuàng)建一個hotfix分支
比如箱锐,當前已經發(fā)布1.2版本,develop上正在進行下一版本(1.3或2.0)的開發(fā)劳较,這時驹止,需要對1.2版本的bug做緊急修復,修復后要發(fā)版观蜗。
$ 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(-)
- 完成修復后臊恋,合并hotfix分支
完成修復后需要把這個分支合并到master和develop分支。
$ 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).
有一個例外情況是墓捻,如果當前正有一個release分支進行中抖仅,那么hotfix分支應該合并到release分支上而不是develop分支,在release分支結束時,將修復一并合并到develop分支上撤卢。
多master环凿、develop分支
上面所述的模型是一個基本的模型。對于一般情況下的軟件開發(fā)只需要一個master和一個develop分支凸丸,直接套用這個模型即可拷邢。對于有多條主線同時進行的產品研發(fā)來說,在這個模型上變通一下屎慢,復制多份就是瞭稼。
比如,象tomcat腻惠,同時有6.x环肘、7.x和8.x版本在維護升級著,不可能只有一個master分支集灌,否則悔雹,這個分支上的tag就會在6.x、7.x欣喧、8.x之間來回跳躍腌零,顯得很亂∷舭ⅲ可以這樣來處理:
比如當前已經發(fā)布7.0版本益涧,前一版本是6.4,現在需要將6.4版本升級到6.5驯鳖,就可以在當前master分支上的6.4版本上創(chuàng)建一個分支闲询,叫master-6.4,同時從master-6.4上創(chuàng)建一個develop-6.4浅辙,將這兩個分支做為主要分支扭弧,參考上面的模型,進行6.x版本的后續(xù)開發(fā)记舆。
同樣鸽捻,若當前已經發(fā)布8.0版本,想從上一版本7.5開始維護7.x版本泽腮,就可以創(chuàng)建master-7.5和develop-7.5兩個分支泊愧,參考上面的模型,進行7.x的后續(xù)開發(fā)盛正。
前面在討論hotfix分支時提到,在發(fā)布2.0版本后屑埋,“如果說由于某些限制(比如2.0跟1.0不兼容豪筝,或商務上不允許以2.0去修復1.0)而必須需要在1.0上修復出一個1.1版本”,這時就可以采用類似上面的辦法,創(chuàng)建一個master-1.0分支续崖,這兒可能就不需要創(chuàng)建develop-1.0分支了敲街,直接創(chuàng)建hotfix-1.1分支,完成修復后严望,將hotfix-1.1合并到master-1.0上多艇。可根據需要將hotfix-1.1也合并或不合并到master分支上像吻。
所有的master*分支和develop*分支都是主分支峻黍,都應該長期保存。