一. 什么是Gitflow
在工作場合實施Git的時候,有很多種工作流程可供選擇,此時反而會讓你手足無措。本文羅列了企業(yè)團隊最常用的一些git工作流程,包括Centralized Workflow、Feature Branch Workflow、Gitflow Workflow、Forking Workflow。愿以此文拋磚引玉。
在你開始閱讀之前,請記住:這些流程應(yīng)被視作為指導(dǎo)方針,而非“鐵律”。我們只是想告訴你可能的做法。因此,如果有必要的話,你可以組合使用不同的流程。
- 它是怎么工作的?
Gitflow流程仍然使用一個中央代碼倉庫,它是所有開發(fā)者的信息交流中心。跟其他的工作流程一樣,開發(fā)者在本地完成開發(fā),然后再將分支代碼推送到中央倉庫。唯一不同的是項目中分支的結(jié)構(gòu)。
-
用于記錄歷史的分支
Gitflow使用兩個分支來記錄項目開發(fā)的歷史,而不是使用單一的master分支。在Gitflow流程中,master只是用于保存官方的發(fā)布?xì)v史,而develop分支才是用于集成各種功能開發(fā)的分支。使用版本號為master上的所有提交打標(biāo)簽(tag)也很方便。
圖2
事實上,Gitflow流程就是圍繞這兩個特點鮮明的分支展開的。
-
用于功能開發(fā)的分支
每一個新功能的開發(fā)都應(yīng)該各自使用獨立的分支。為了備份或便于團隊之間的合作,這種分支也可以被推送到中央倉庫。但是,在創(chuàng)建新的功能開發(fā)分支時,父分支應(yīng)該選擇develop(而不是master)。當(dāng)功能開發(fā)完成時,改動的代碼應(yīng)該被合并(merge)到develop分支。功能開發(fā)永遠(yuǎn)不應(yīng)該直接牽扯到master。
圖3
注意:組合使用功能開發(fā)分支和develop分支的這種設(shè)計,其實完全就是Feature Branch Workflow的理念。然而,Gitflow流程并不止于此。
-
用于發(fā)布的分支
圖4
一旦develop分支積聚了足夠多的新功能(或者預(yù)定的發(fā)布日期臨近了),你可以基于develop分支建立一個用于產(chǎn)品發(fā)布的分支。這個分支的創(chuàng)建意味著一個發(fā)布周期的開始,也意味著本次發(fā)布不會再增加新的功能——在這個分支上只能修復(fù)bug,做一些文檔工作或者跟發(fā)布相關(guān)的任務(wù)。在一切準(zhǔn)備就緒的時候,這個分支會被合并入master,并且用版本號打上標(biāo)簽。另外,發(fā)布分支上的改動還應(yīng)該合并入develop分支——在發(fā)布周期內(nèi),develop分支仍然在被使用(一些開發(fā)者會把其他功能集成到develop分支)。
使用專門的一個分支來為發(fā)布做準(zhǔn)備的好處是,在一個團隊忙于當(dāng)前的發(fā)布的同時,另一個團隊可以繼續(xù)為接下來的一次發(fā)布開發(fā)新功能。這也有助于清晰表明開發(fā)的狀態(tài),比如說,團隊在匯報狀態(tài)時可以輕松使用這樣的措辭,“這星期我們要為發(fā)布4.0版本做準(zhǔn)備。”從代碼倉庫的結(jié)構(gòu)上也能直接反映出來。常用的一些措辭還有:基于develop新建分支,合并入master;命名規(guī)則為:release-或release/
-
用于維護(hù)的分支
圖5
發(fā)布后的維護(hù)工作或者緊急問題的快速修復(fù)也需要使用一個獨立的分支。這是唯一一種可以直接基于master創(chuàng)建的分支。一旦問題被修復(fù)了,所做的改動應(yīng)該被合并入master和develop分支(或者用于當(dāng)前發(fā)布的分支)。在這之后,master上還要使用更新的版本號打好標(biāo)簽。
這種為解決緊急問題專設(shè)的綠色通道,讓團隊不必打亂當(dāng)前的工作流程,也不必等待下一次的產(chǎn)品發(fā)布周期。你可以把用于維護(hù)的分支看成是依附于master的一種特別的發(fā)布分支。
二. Gitflow模擬
下面的例子將演示Gitflow流程如何被用來管理一次產(chǎn)品發(fā)布。假設(shè)你已經(jīng)創(chuàng)建好了一個中央倉庫。
-
創(chuàng)建develop分支
圖6
第一步是給默認(rèn)的master配備一個develop分支。一種簡單的做法是:讓一個開發(fā)者在本地建立一個空的develop分支,然后把它推送到服務(wù)器。
git branch develop
git push -u origin develop
develop分支將包含項目的所有歷史,而master會是一個縮減版本。現(xiàn)在,其他開發(fā)者應(yīng)該克隆(clone)中央倉庫,并且為develop創(chuàng)建一個追蹤分支。
git clone ssh://user@host/path/to/repo.git
git checkout -b develop origin/develop
到現(xiàn)在,所有人都把包含有完整歷史的分支(develop)在本地配置好了。
-
小馬和小明開始開發(fā)新功能
圖7
我們的故事從小馬和小明要分別開發(fā)新功能開始。他們倆各自建立了自己的分支。注意,他們在創(chuàng)建分支時,父分支不能選擇master,而要選擇develop。
git checkout -b some-feature develop
他們倆都在自己的功能開發(fā)分支上開展工作。通常就是這種Git三部曲:edit,stage,commit:
git status
git add <some-file>
git commit
-
小馬把她的功能開發(fā)好了
圖8
在提交過幾次代碼之后,小馬覺得她的功能做完了。如果她所在的團隊使用“拉拽請求”,此刻便是一個合適的時機——她可以提出一個將她所完成的功能合并入develop分支的請求。要不然,她可以自行將她的代碼合并入本地的develop分支,然后再推送到中央倉庫,像這樣:
git pull origin develop
git checkout develop
git merge some-feature
git push
git branch -d some-feature
第一條命令確保了本地的develop分支擁有最新的代碼——這一步必須在將功能代碼合并之前做!注意,新開發(fā)的功能代碼永遠(yuǎn)不能直接合并入master。必要時,還需要解決在代碼合并過程中的沖突。
-
小馬開始準(zhǔn)備一次發(fā)布
圖9
盡管小明還在忙著開發(fā)他的功能,小馬卻可以開始準(zhǔn)備這個項目的第一次正式發(fā)布了。類似于功能開發(fā),她使用了一個新的分支來做產(chǎn)品發(fā)布的準(zhǔn)備工作。在這一步,發(fā)布的版本號也最初確定下來。
git checkout -b release-0.1 develop
這個分支專門用于發(fā)布前的準(zhǔn)備,包括一些清理工作、全面的測試、文檔的更新以及任何其他的準(zhǔn)備工作。它與用于功能開發(fā)的分支相似,不同之處在于它是專為產(chǎn)品發(fā)布服務(wù)的。
一旦小馬創(chuàng)建了這個分支并把它推向中央倉庫,這次產(chǎn)品發(fā)布包含的功能也就固定下來了。任何還處于開發(fā)狀態(tài)的功能只能等待下一個發(fā)布周期。
-
小馬完成了發(fā)布
圖10
一切準(zhǔn)備就緒之后,小馬就要把發(fā)布分支合并入master和develop分支,然后再將發(fā)布分支刪除。注意,往develop分支的合并是很重要的,因為開發(fā)人員可能在發(fā)布分支上修復(fù)了一些關(guān)鍵的問題,而這些修復(fù)對于正在開發(fā)中的新功能是有益的。再次提醒一下,如果小馬所在的團隊強調(diào)代碼評審(Code Review),此時非常適合提出這樣的請求。
git checkout master
git merge release-0.1
git push
git checkout develop
git merge release-0.1
git push
git branch -d release-0.1
發(fā)布分支扮演的角色是功能開發(fā)(develop)與官方發(fā)布(master)之間的一個緩沖。無論什么時候你把一些東西合并入master,你都應(yīng)該隨即打上合適的標(biāo)簽。
git tag -a 0.1 -m"Initial public release" master
git push --tags
Git支持鉤子(hook)的功能,也就是說,在代碼倉庫里某些特定的事件發(fā)生的時候,可以執(zhí)行一些預(yù)定義的腳本。因此,一種可行的做法是:在服務(wù)器端配置一個鉤子,當(dāng)你把master推送到中央倉庫或者推送標(biāo)簽時,Git服務(wù)器能為產(chǎn)品發(fā)布進(jìn)行一次自動的構(gòu)建。
-
用戶發(fā)現(xiàn)了一個bug
圖11
當(dāng)一次發(fā)布完成之后,小馬便回去與小明一起開發(fā)其他功能了。突然,某個用戶提出抱怨說當(dāng)前發(fā)布的產(chǎn)品里有一個bug。為了解決這個問題,小馬(或者小明)基于master創(chuàng)建了一個用于維護(hù)的分支。她在這個分支上修復(fù)了那個bug,然后把改動的代碼直接合并入master。
git checkout -b issue-#001 master
\# Fix the bug
git checkout master
git merge issue-#001
git push
跟用于發(fā)布的分支一樣,在維護(hù)分支上的改動也需要合并入develop分支,這一點是很重要的!因此,小馬務(wù)必不能忘了這一步。隨后,她就可以將維護(hù)分支刪除。
git checkout develop
git merge issue-#001
git push
git branch -d issue-#001
三. Gitflow結(jié)合SourceTree實踐
- 創(chuàng)建本地倉庫+遠(yuǎn)程倉庫
此處略過
- 打開該倉庫SourceTree控制界面
-
添加完成之后點擊該按鈕
圖13
注意: 此處是配置,開發(fā)分支,發(fā)布分支名稱,以及開發(fā)功能分支前綴,發(fā)布分支前綴,熱修復(fù)分支前綴,以及版本號前綴。建議使用默認(rèn)的形式。
- 初始化完成
此處會多出develop與master分支
- 開發(fā)功能模塊
點擊gitflow圖標(biāo),new一個feature分支,然后輸入當(dāng)前要做的模塊名稱。
注意:此處最好在最新的develop分支上,進(jìn)行創(chuàng)建feature,這樣確保更少的沖突。
為該feature分支起一個名字
完成之后,可見當(dāng)前分支的情況。
- 完成功能模塊
完成開發(fā)之后,先commit到本地的feature分支上。然后點擊gitflow按鈕
注意:首先查看develop分支有沒有其他人提交的記錄,如果有需要pull下來的,先切回到develop分支先pull下來。然后切回到feature分支下。進(jìn)行finish current操作。
注意:一般的開發(fā)完成之后,選擇刪除當(dāng)前的feature分支,因為此處的分支為本地分支,你也可以選擇保留當(dāng)前feature分支,選擇OK之后,會將當(dāng)前的feature分支的內(nèi)容合并到本地的develop分支上。
如果需要推送到origin,即可以推送到origin對應(yīng)的分支上。
- 進(jìn)行發(fā)布
點擊gitflow按鈕,然后選擇new release
輸入需要發(fā)布的版本號,此處輸入的會將成為版本Tag信息。
然后將項目中需要改版本的號的文件進(jìn)行相對應(yīng)的提交和修改。完成之后commit到當(dāng)前的release分支上。
- 完成發(fā)布
版本配置文件修改完成之后,進(jìn)行合并,點擊gitflow按鈕,出現(xiàn)了,然后點擊Finish Current。
注意:此處輸入的信息,是對當(dāng)前的Tag定制的提交信息。
點擊完后后,會將當(dāng)前的release分支合并到develop,master分支,是否要推倒origin,由coder自己決定。
這要做的好處是,master分支上的每個節(jié)點,都是一個版本。
方便查閱。
注意:此處發(fā)布時,需要team中,負(fù)責(zé)發(fā)布的coder去操作,避免多人發(fā)布,造成版本號,Tag混亂。
- 開始熱修復(fù)
如果版本發(fā)出后,出現(xiàn)了一個bug,需要緊急的去修改,則需要使用new一個 hotfix,去進(jìn)行開發(fā)。
注意:Hotfix分支是在最新節(jié)點的master分支上創(chuàng)建的,此處填入的hotfix的版本號。
- 完成熱修復(fù)
完成Bug修復(fù)代碼工作之后,提交到當(dāng)前的本地hotfix分支上,完后進(jìn)行finish 當(dāng)前的hotfix分支,此處操作與release相同。
完成之后,會自動合并到本地的master,develop分支上,至于是否要push到origin由Coder自行決定。
四. 總結(jié)
team之間,使用Gitflow,進(jìn)行開發(fā)輔助的分支管理,一定情況的減少了沖突發(fā)生的可能,但是此處在項目初期,項目結(jié)構(gòu)發(fā)生變化較大的時候,沖突的可能會很大。此處建議盡可能在在項目搭建完成之后,進(jìn)行team開發(fā)過程。使用Gitflow在開發(fā)功能模塊,以及組件庫方面,起到了很大的作用。確保了master分支每個節(jié)點都有Tag版本號,每個節(jié)點都是一個獨立的版本。配合CI,可以讀取到,master分支提交的節(jié)點數(shù),Tag可以作為當(dāng)前版本的版本號,可配置機器并且完成自動化發(fā)布的工作,提高工作效率。