成功的GIT開發分支模型和策略

詳細圖文並茂以及git flow工具解釋參考: http://danielkummer.github.io/git-flow-cheatsheet/index.zh_CN.htmlhtml

原文地址:http://nvie.com/posts/a-successful-git-branching-model/  git

本文中我將介紹我在多年的項目開發中使用的開發模型,這個模型被實踐檢驗爲正確有效的模式。本文中,我將不會涉及到項目的任何細節,只討論關於分支策略和release管理
github

爲何要使用Git?shell

網上有不少關於Git和集中式代碼管理控制系統的比較,做爲一個開發人員,我更喜歡Git,Git實際上顛覆了開發人員關於merge/branch的想法。從經典的CVS/SVN世界過來,merging/branching老是被認爲是一個痛苦和使人膽寒的事情。可是在Git中,這些行爲是很是簡單和代價低廉的。好比在CVS/SVN的書籍中,branching和merging每每都在最後幾章中討論(專爲高級用戶所寫),而在每一本Git的書籍中,這些merge/branch總在前三章中介紹(由於它們很基礎)。app

正是源於這些操做在Git中簡單,重複的特性,branching/merging再也不是一個使人生畏的事情。分佈式

Decenteralized but cdentralized:工具

庫做爲中央「truth」repo.在Git中,雖然這個repo可能被認爲是中央的repo,可是你要明白GIT是一個分佈式的版本控制系統,也就是說從技術角度來講沒有這個central repo!咱們更確切地將這個central repo稱爲originpost

 

每一個開發人員pull/push to origin.可是除了中央式的pull/push關係,每個開發人員之間也可能從他們的子team之間pull changes。例如,對於兩個或更多的開發人員同時工做在一個大的feature上,這種模型就更加有用了(特別是正在工做中的feature代碼永久性push到origin前)。上面的圖中,在alice和bob,alice和david,clair和david之間造成了subteam。ui

技術上說,實際上就是Alice定義了一個Git remote, 命名爲bob,指向bob的repo,一樣反之亦然。this

The main branches

核心上說,開發模型被已有的模型所啓發,中央repo將永久保留兩個主要的branches:

  • master
  • develop

origin上的master分支對於每個GIT用戶來講是很是熟悉的.和master branch平行的,有一個另外叫作develop的分支。

咱們考慮orgin/master做爲main branch,這個分支上的HEAD老是反映了一個production-ready的狀態;

咱們將origin/develop視做一個HEAD永遠指示爲了下一個release而最近遞交的開發變化。有些人比較喜歡將此稱爲integration branch.在這個分支上,每日的build將從這裏構建。

當在develop分支上的代碼達到一個穩定狀態點,達到能夠發佈的狀態時,全部的變動都應該merge back到master,而且在master上tag一個release number。

這樣每次當變動merge back到master時,這就是一個新的production release by definition.咱們更傾向於對此很是嚴格,所以理論上,咱們可使用一個Git hook sciprt實現每當有一個向master的commit,咱們自動構建和部署master上的軟件到生產環境上去(由於master老是一個Production ready的狀態)

Supporting branches:

除了main branches: master和develop,咱們的開發模型中也將使用一系列的supporting branches以便支持在team member之間實現並行開發,更加容易地實現feature的tracking,更方便地準備產品release,更好的輔助解決產品的問題。不像main branch(master,develop),這些branch老是有一個生命週期,由於他們最終將被刪除。

咱們建議如下幾種類型的分支:

  • feature branches;
  • release branches
  • hotfix branches

每種非main branch都有一個特定的目的,而且有嚴格的定義規則:這個分支應該從那個分支來建立,以及該分支最終的merge targets都有明確的定義。下面咱們將明確說明。

從技術角度來講,這些branch自己並沒有特別之處。這些branch的類型是由"how we use them"來分類的。他們就是簡單的普通的Git branch.

Feature branches:

May branch off from: develop;

Must merge back into: develop;

Branch naming convention: 任何除了master,develop,release-*,hotfix-*以外均可以

Feature branch(或者被叫作topic branch)被用來爲了即將到來的(upcoming)或者長遠計劃的release而作開發之用的。當開始開發一個feature時,這個feature的target release(目標release)在那時可能根本還肯定。feature branch的本質是:只要feature仍在開發中,它將一直存續,可是最終它將被merged back到dvelop分支(to definitely add the new feature to the upcoming release)或者被discarded(in case of a disappointing experiment)。

Feature branche典型地只存在於開發人員的repo中,並不在origin repo中存在。

當開始一個新的feature開發時,feature branch從develop branch中建立出來

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

結束的feature將被merged into the develop branch以便在即將到來的release中添加這個feature.

$ 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 flag使得這個merge動做即使是這個merge屬於fast-forward(no conflict)也總會產生一個新的commit object。這樣就避免了關於曾近爲了開發一個新的feature而作了feature branch並遞交了多個文件的歷史。

上圖中,後一個fast-forward merge的場景,你將沒法得知哪些commit objects最終造成了那個feature---你可能必須手動的查閱全部的log信息才能得知。一樣在後一個場景中,你想rollback一個feature也是一個很是頭疼的問題,然而若是咱們增長了--no--ff flag則很容易作到這些。

固然,使用--no-ff flag確實會產生一些多是空的commit objects,可是這個壞處相比其帶來的好處是能夠忍受的。

Release branches:

May branch off from: develop

Must merge back into: develop and master

Branch naming convention: release-*

注意release branch通常命名只包含major+minor,而不包含patch。好比release-1.0,release-2.3,對於release-1.5.1這樣的tag只存在於hotfix生成的版本中

Release branches支持準備一個新的產品release而存在。They allow for last-minute dotting of i’s and crossing t’s.並且,他們容許曉得bug fix而且爲那個release準備一些meta-data(好比version number, build dates,etc)。這些工做都在一個release branch上作,那麼develop分支老是很清晰地準備爲下一個大的release接受新的feature.

開始從develop branch off一個新的release branch的時機每每是在當develop基本反映了新的release的可接受狀態時。至少全部的必須在這個release中deliver的feature必須被merge到了develop分支,這個時刻就是建立release branch的時機。全部爲未來release計劃的feature都不能merge下來直到上一個release branch已經被建立。

一般直到將要到來的release被賦予一個版本號,這將是這個release branch的一個起點。直到那個時刻,develop分支反映了下一個release的變化,可是關因而否那個下一個release會最終變成0.3或者1.0並非很清晰,直到release branch開始工做。這個決定在release branch 開始時決定下來,由項目的版本號命名規則來決定

Release branch由develop branch來建立。好比,版本v1.1.5是當前產品release,而咱們將有一個大的release將被release。develop分支的狀態已經爲下一個release作好了準備,而咱們決定這個release將命名爲v1.2(而不是v1.1.6或者v2.0)。那麼咱們能夠branch off而且給這個release branch一個1.2的名稱:

$ 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(-)

在建立一個新的release branch而且切換到該branch後,咱們bump the version number。這裏bump-verison.sh是一個虛構的shell腳本,該腳本更改一些文件以便反映新的版本號變動。(這固然也能夠是一個手工的變動)而後,這個bumped version number is commited.

這個新的branch可能會存續一段時間,直到這個release被正式rollout.在這個時間段內,bugfix可能會被應用到這個release branch上去(而不是應用到develop branch上去)。在這裏增長大的新功能將被嚴格禁止。這些bugfix必須被merge到develop分支上去,這樣又開始等待下一個大的release.

當releasea branch的狀態真正達到實際可以release質量時,也須要作一些工做。首先,release branch須要merge到master(可能包含一些bug fix)(since every commit on master is a new release by definition, remember!)。接着,那個對master的commit必須被打上tag,以便該歷史版本未來可以容易地被引用。最後,在release branch上作的bugfix變動須要被merge到develop上去,以便未來的release中包含這些bugfix。

前兩步Git操做:

$ 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

 

release如今已經結束了,而且被打了標籤1.2以便未來引用

爲了將release branch上作的bugfix保持好,咱們須要將這些fix merge到develop分支上:

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

在這一步,咱們可能會碰到merge conflict(probably even, since we have changed the version number),若是發現conflict,則解決它而且commit掉

如今咱們確實完成了這個release的工做,release branch能夠被刪除了:

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

Hotfix branches:

May branch off from:

master

Must merge back into:

develop and master

Branch naming convention:

hotfix-*

 hotfix branch和release branch很是類似,由於他們自己也是用於爲準備一個新的產品release而存在的(儘管是非計劃的,每每由某個release現場發現緊急問題而觸發的)。他們每每是由一個現場運行的產品release上報的問題來觸發產生的。當一個critical bug必須立刻解決時,一個hotfix branch將從master branch中的相應tag版本處branch off出來。這樣作的本質是:團隊其餘成員能夠在develop branch上繼續工做,而指定團隊一我的在這個hotfix branch上準備一個快速產品fix版本。

hotfix branch由master branch來建立。好比,假設v1.2是當前報嚴重問題的產品release版本,可是因爲在develp branch上的變動還不穩定,因此咱們開始從master上拉一個hotfix branch開始工做:

$ 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(-)

不要忘記bump the version number after branching off~!

而後,fix the bug,commit the fix in one or more seperate commits:

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

Finishing a hotfix branch:

當完成該問題的fix時,bugfix須要merged back到master中去,同時也須要merge到develop branch中去,只有這樣才能保證bugfix自己將會在下一個release中自動包含。這和release branch結束的動做是同樣的。

首先,更新master而且tag the release:

$ 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

下一步,也須要同時包含bugfix到develop分支中去:

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

在這裏有一個例外的rule:當一個release branch當前存續,那麼這個hotfix change須要merge到那個release branch中去,而不是develop分支。Back-merging the bugfix into the release branch will eventually result in the bugfix being merged into the develop too, when the release branch is finished, (If work in develop immediately requires this bugfix and cannot wait for the release branch to be finished, you may safely merge the bugfix into the develop now already as well.)

最後,刪除這個臨時的branch

$ git branch -d hotfix-1.2.1
Deleted branch hotfix-1.2.1 (was abbe5d6).

原創:在github上大型項目團隊branch策略:

Summary:

雖然本篇文章自己對於分支策略並沒有使人震驚之處,可是那個big picture圖片確實對咱們的項目成功有很是重要的意義。它構建了一個優雅地心智模型,而該模型易於理解而且容許團隊充分理解整個產品的branching/releasing流程。

 兩個team member有兩個repo,互爲remote,當git push時,有可能出現conflict,這時須要作的事情是必須先git pull操做,解決衝突之後,再作git push。這和在一個repo時merge衝突是相似的。

https://github.com/nvie/gitflow 是一個對git擴充的flow慣例,很是實用

相關文章
相關標籤/搜索