本文以一虛擬項目為例,描述了Git Flow在項目中的應用;還以此為主線,以表格形式給出了速查手冊;最后,結合這兩點介紹了一個基於Git Flow的項目實例。
希望這篇文章能夠幫助Git初學者盡快上手。
1.1 什么是Git Flow?
Git Flow實際上是一種軟件項目管理模型,由大牛Vincent Driessen提出,核心思想如所圖 1示。從中可以看出,主分支有master、develop兩個組成,分別用於產品發布、功能開發;余下的三個輔助分支——hotfixes、release branches、feature branches,分別用於已發版本的bug修復、新版QA發布、新功能開發。

圖 1 Git Flow原理圖
對於使用Git的朋友來說,分支的概念一定不會陌生,但是加上“主”、“輔助”這兩個修飾詞之后可能就有些迷惑了,個人的理解如下:
1) 主分支指的是在整個軟件生命周期內一直存在的分支,不允許刪除commit的歷史記錄,更不允許刪除分支。例如,master分支記錄的就是整個軟件的發布記錄(換而言之,可以拉取其中的任一commit,無須修改即可對外發布),只能從release branches或hotfixes兩個分支中合並,每次commit必須打標簽。
2) 輔助性分支則一般用於新功能開發、bug修復、新版QA,完成相應的功能之后可以刪除這些分支,但是為了使整個開發過程有據可查,一般都予以保留。例如,已經對外發布的V0.1版需要緊急修復一個自測、內測均未發現的bug,則需要直接從master分支的V0.1開出一個緊急修復分支hotfixes-XXX,完成后同時並入master、develop兩個主分支,hotfixes-XXX分支的存留取決於項目管理員。
1.2 Git Flow速查手冊
假設項目現在處於以下狀態:
ü 已經對外發布V0.0版本。
ü 已商定V1.0的新特性及其實施計划。
ü 已安裝Git、TortoiseGit兩款軟件(也可通過360軟件管家安裝)。
根據上述假設,我制作了表 1。項目管理時,可以自上而下的查閱。例如,現在要開始V1.0的開發,則直接查閱【想要干什么】->【develop】一列中的內容,發現可以開啟分支、合並分支等操作。項目開發時,可以從左到右查閱。例如,現在工作區正處於develop狀態,則可以提交內測或者新功能開發。
表 1 Git Flow速查手冊
另外,在實際開發過程中,還應注意各個分支名稱命名的規范性。這里,使用了“分支功能名稱-負責人縮寫-描述”作為命名規范。例如,“dev-ll-1.0”表示V1.0版本的開發分支由縮寫為ll的開發人員負責,“feature-ll-description”表示新功能description的開發由縮寫為ll的開發人員負責。
1.3 項目實戰
1.3.1 准備
在實際項目中,要經常進行分支合並和沖突處理。對於分支合並而言,主要使用的命令為以下三種,依次對應了圖 2中左、中、右三種合並效果:
1) git merge –e --no-ff release-ll-1.0,單獨保留release-ll-1.0的每次提交,然后並入master,master分支中不含release-ll-1.0中提交記錄。【推薦,這樣可以保留所有分支的提交記錄】
2) git merge –e --squash release-ll-1.0,整合release-ll-1.0分支中所有的提交記錄為一條,然后並入master,master分支中不含release-ll-1.0中提交記錄。
3) git merge –e release-ll-1.0 ,直接移動master分支的HEAD指向release-ll-1.0的最新提交,release-ll-1.0完整並入master。

圖 2 分支合並的效果對比
下面討論一種特殊情況,如圖 3所示,iss53自C2分出后,原分支新增了一次C4提交,新分支增加了C3、C5兩次提交,則分支合並時會結合C2(基准參考)、C5、C4做三方合並,合並效果參考上述三種情況的第一種。

圖 3 分支合並的一種特殊情況
至於沖突處理,則可以直接使用TortoiseGit的Git Resolve工具,借助GUI工具可以輕松的處理文件或者文本沖突,具體如圖 4所示。

圖 4 TortoiseGit的沖突處理工具
1.3.2 初始化
1) 從遠程庫clone到本地,完成初始化提交。
$ git clone git@192.168.1.36:/home/git/repositories/sample.git
Cloning into 'sample'...
warning: You appear to have cloned an empty repository.
2) 使用Git GUI完成v0.0.txt文件的添加、提交和推送。
3) 添加標簽。
$ git tag -a V0.0 -m "初始化版本V0.0"
1.3.3 轉入開發分支
1) 從master主分支的V1.0開出開發分支dev-ll-1.0。
$ git checkout -b dev-ll-1.0
Switched to a new branch 'dev-ll-1.0'
2) 從主開發分支dev-ll-1.0開出功能開發分支feature-ll-add_email。
$ git checkout -b feature-ll-add_email
Switched to a new branch 'feature-ll-add_email'
3) 同時在dev-ll-1.0 、feature-ll-add_email完成V1.0所有功能的開發。
表 2 主開發、新功能分支同時開發
| dev-ll-1.0 |
feature-ll-add_email |
| $ git checkout dev-ll-1.0 Switched to branch 'dev-ll-1.0' |
$ git checkout feature-ll-add_email Switched to branch 'feature-ll-add_email' |
| 完成第三個功能的開發自測,使用Git GUI完成提交、推送。 |
完成第二個功能——添加郵箱地址的開發自測,使用Git GUI完成提交、推送。 |
1.3.4 修復V0.0的bug
1) 切回主分支,開出bug修復分支hotfix-ll-0.1。
$ git checkout master
Switched to branch 'master'
Your branch is up-to-date with 'origin/master'.
$ git checkout -b hotfix-ll-0.1
Switched to a new branch 'hotfix-ll-0.1'
2) 使用Git GUI完成v0.0.txt文件的提交和推送。
3) 合並到主分支,發布V0.1並打標簽。
$ git checkout master
Switched to branch 'master'
Your branch is up-to-date with 'origin/master'.
$ git merge -e --no-ff hotfix-ll-0.1
Merge made by the 'recursive' strategy.
v0.0.txt | 2 +-
v0.1.txt | 1 +
2 files changed, 2 insertions(+), 1 deletion(-)
create mode 100644 v0.1.txt
$ git tag -a V0.1 -m "V0.1"
4) 合並到主開發分支。
$ git checkout dev-ll-1.0
Switched to branch 'dev-ll-1.0'
$ git merge -e --no-ff hotfix-ll-0.1
Auto-merging v0.0.txt
CONFLICT (content): Merge conflict in v0.0.txt
Automatic merge failed; fix conflicts and then commit the result.
5) 使用右鍵菜單中的【TortoiseGit->GitResolve】來完成沖突處理,然后再通過Git GUI提交。
1.3.5 合並新功能分支
1) V1.0功能開發自測完畢,需要將新功能分支feature-ll-add_email合並到主開發分支dev-ll-1.0上。
$ git merge -e --no-ff feature-ll-add_email
Auto-merging v0.0.txt
CONFLICT (content): Merge conflict in v0.0.txt
Automatic merge failed; fix conflicts and then commit the result.
2) 使用右鍵菜單中的【TortoiseGit->GitResolve】來完成沖突處理,然后再通過Git GUI提交。
1.3.6 V1.0的QA與對外發布
1) 從主開發分支dev-ll-1.0開出待發布分支release-ll-1.0,用於發布前QA。
$ git checkout -b release-ll-1.0
Switched to a new branch 'release-ll-1.0'
2) 使用Git GUI完成QA過程所需的文件提交、推送。
3) QA完成后,將待發布分支release-ll-1.0並入master分支,並打標簽。
$ git checkout master
Switched to branch 'master'
Your branch is ahead of 'origin/master' by 3 commits.
(use "git push" to publish your local commits)
$ git merge -e --no-ff release-ll-1.0
Merge made by the 'recursive' strategy.
v0.0.txt | 8 +++++++-
1 file changed, 7 insertions(+), 1 deletion(-)
$ git tag -a V1.0 -m "V1.0發布"
還有一點需要注意,若此時V2.0版本已經展開實施,則仍需將發布分支並入dev-ll-2.0分支;否則,直接從master開出dev-ll-2.0分支。
小工具
https://github.com/github/gitignore.git
參考文獻
http://nvie.com/posts/a-successful-git-branching-model/
https://segmentfault.com/q/1010000002477106
