Gitflow 使用指北

代碼管理是整個(gè)項(xiàng)目管理周期中重要的一環(huán),而代碼管理是始終圍繞版本發(fā)布流程而制定的,今天討論的Gitflow就是一種版本發(fā)布方案。

Gitflow簡(jiǎn)介

Gitflow是一個(gè)基于feature分支管理的版本發(fā)布方案。它是由荷蘭程序猿Vincent Driessen設(shè)計(jì)研發(fā),開(kāi)源項(xiàng)目地址gitflow-avh

大致流程是:

  • 不同feature在不同feature分支上單獨(dú)開(kāi)發(fā)(或測(cè)試)。
  • 確定版本號(hào)和此版本將要發(fā)布的功能后,將相應(yīng)featustre分支統(tǒng)一向develop分支合并,然后拉出新的release預(yù)發(fā)布分支。
  • release分支作為持續(xù)集成關(guān)注的分支,修復(fù)bug。
  • 待release分支測(cè)試驗(yàn)收通過(guò)后,統(tǒng)一向master分支和develop分支合并,并在master分支打tag。
  • 根據(jù)tag發(fā)布apk版本。

若線上發(fā)現(xiàn)嚴(yán)重bug,需走h(yuǎn)otfix流程。

  • 基于master分支拉出hotfix分支修復(fù)線上問(wèn)題。
  • bug修復(fù)完成統(tǒng)一向master和develop分支合并。
  • master分支打上新的tag,發(fā)布新版本。

下圖是Gitflow發(fā)布的經(jīng)典圖片,直觀反映了Gitflow發(fā)布的全流程。

gitflow.png

它的特點(diǎn)是能靈活的根據(jù)實(shí)際需求發(fā)布相應(yīng)版本,較好的支持并行開(kāi)發(fā),歷史版本用tag進(jìn)行維護(hù)。

下面將介紹如何使用Gitflow命令完成上述版本發(fā)布,一條Gitflow指令可能對(duì)應(yīng)了一系列g(shù)it命令,為的是規(guī)范化開(kāi)發(fā)流程,提高代碼管理效率。

Mac平臺(tái)安裝

brew install git-flow

brew表示Homebrew,它是mac平臺(tái)常用的包管理器,沒(méi)有安裝則需先安裝,安裝可參考Mac OS下brew的安裝和使用

初始化

先將遠(yuǎn)程倉(cāng)庫(kù)克隆到本地。

git clone <project_url>

各種初始化Gitflow配置。

git flow init

命令行會(huì)提示你是否修改Gitflow提供的默認(rèn)分支前綴。不同場(chǎng)景的分支前綴不同,默認(rèn)情況下分支前綴是這樣的:

場(chǎng)景 分支前綴
新功能 feature
預(yù)發(fā)布 release
熱修復(fù) hotfix
打tag

分支前綴的作用是區(qū)分不同分支的使用場(chǎng)景,同時(shí)當(dāng)你使用Gitflow命令時(shí)就不需手動(dòng)添加分支前綴了,Gitflow會(huì)幫你加上。

比如開(kāi)發(fā)新功能需創(chuàng)建一個(gè)feature分支,名為gitworkflow,使用下面的代碼將會(huì)創(chuàng)建一個(gè)名為feature/gitworkflow本地分支。

git flow feature start gitworkflow

通常情況下不需要修改默認(rèn)的命名前綴,只需加上-d就可跳過(guò)修改命名階段。

git flow init -d

行為/Action

通常來(lái)說(shuō),一種場(chǎng)景的完整生命周期應(yīng)至少包含以下幾種行為:

  • start 開(kāi)始開(kāi)發(fā)
  • publish 發(fā)布到遠(yuǎn)程分支
  • finish 完成開(kāi)發(fā)、合并到主分支

我們首先以feature場(chǎng)景為例,看看如何完成工作流。

start

新功能開(kāi)始開(kāi)發(fā)前,需準(zhǔn)備好開(kāi)發(fā)分支。

git flow feature start <feature_name>

執(zhí)行上面的命令將會(huì)在本地創(chuàng)建名為<feature_name>的分支,并切換到該分支,而且不論當(dāng)前所處哪個(gè)分支都是基于develop分支創(chuàng)建,相當(dāng)于執(zhí)行了下面的git的命令。

git checkout -b feature/<feature_name> develop

需要注意基于的是本地的develop分支,執(zhí)行此命令前一般需要拉取最新的遠(yuǎn)程代碼。

publish

在本地開(kāi)發(fā)完成新功能并commit后,需要將本地代碼push到遠(yuǎn)程倉(cāng)庫(kù)。

git flow feature publish <feature_name>

這行指令做了三件事。

  1. 創(chuàng)建一個(gè)名為feature/<feature_name>的遠(yuǎn)程分支。
  2. 本地分支track上述遠(yuǎn)程分支。
  3. 如果本地有未push代碼,則執(zhí)行push。

轉(zhuǎn)換成git命令就是下面的樣子:

git push origin feature/<feature_name>
git push --set-upstream origin feature/<feature_name>
git push origin

注意:

如果已經(jīng)執(zhí)行過(guò)publish后又有新的代碼需push,再次執(zhí)行將報(bào)錯(cuò),因?yàn)樗冀K會(huì)試圖創(chuàng)建一個(gè)遠(yuǎn)程分支。此時(shí)需執(zhí)行正常的push命令git push origin

finish

當(dāng)功能開(kāi)發(fā)完畢后就將進(jìn)入測(cè)試階段,此時(shí)需將一個(gè)或多個(gè)feature分支統(tǒng)一合并到develop分支。

git flow feature finish <feature_name>

這行指令也做了三件事。

  1. 切換到develop分支。
  2. 合并代碼到develop分支
  3. 刪除本地feature/<feature_name>分支。

等價(jià)于執(zhí)行下面的git命令:

git checkout develop
git merge feature/<feature_name>
git branch -d feature/<feature_name>

說(shuō)到merge,就不得不提merge采用的策略,我們使用git merge命令時(shí)默認(rèn)(主分支沒(méi)有新的提交、沒(méi)有沖突等情況)使用的是fast-forward模式(以下簡(jiǎn)稱ff),即只移動(dòng)HEAD指針而不會(huì)生成提交記錄。

而Gitflow稍有不同,默認(rèn)情況下它會(huì)檢查本次merge有多少次commit記錄,如果僅有一條采用ff模式,如果超過(guò)一條則采用no-ff模式,no-ff模式下會(huì)多生成一條merge的commit記錄。

這樣做的好處是當(dāng)只有一條提交記錄時(shí)如果生成一條merge記錄實(shí)際上會(huì)復(fù)雜化代碼記錄的管理;當(dāng)有多條commit記錄時(shí)生成的一個(gè)merge記錄,可以方便的進(jìn)行代碼回退和記錄檢查。

回到finish主題,如果merge時(shí)發(fā)生了沖突,則在第二步merge時(shí)終止流程,即不會(huì)再刪除本地分支。但當(dāng)前已處于develop分支,待本地沖突解決并commit后,重新執(zhí)行git flow feature finish <feature_name>即可完成finish流程。

細(xì)心的同學(xué)可以已經(jīng)發(fā)現(xiàn)finish還有兩件事沒(méi)做。

  1. develop分支代碼還未push。
  2. 未刪除遠(yuǎn)程分支feature/<feature_name>。

也就是還需執(zhí)行

git push origin develop
git push origin :feature/<feature_name>

另外,finish指令支持三個(gè)附加參數(shù)。

  • -r 即merge前先執(zhí)行rebase(但即使rebase后符合ff條件也不一定會(huì)用ff)。
  • -F 即合并完成后連同遠(yuǎn)程分支一并刪除。
  • -k 保留本地feature分支,即不執(zhí)行delete動(dòng)作。

所以如果想連同遠(yuǎn)程分支一并刪除可使用。

git flow feature finish -F <feature_name>

如果你對(duì)feature指令感興趣,下面是其支持的所有指令。

git flow feature [list] [-v]
git flow feature start [-F] <name> [<base>]
git flow feature finish [-rFk] <name|nameprefix>
git flow feature publish <name>
git flow feature track <name>
git flow feature diff [<name|nameprefix>]
git flow feature rebase [-i] [<name|nameprefix>]
git flow feature checkout [<name|nameprefix>]
git flow feature pull <remote> [<name>]

release場(chǎng)景

上面的內(nèi)容以feature場(chǎng)景為例,詳細(xì)的分析了整個(gè)新功能執(zhí)行流程。

下面我們?cè)賮?lái)看release場(chǎng)景,連同之前的feature場(chǎng)景,整個(gè)流程如下。

release.jpg

當(dāng)新功能開(kāi)發(fā)完畢,將進(jìn)入測(cè)試階段,此時(shí)需要基于develop分支拉出release分支進(jìn)行集成測(cè)試,也有將release場(chǎng)景作為預(yù)發(fā)布環(huán)境進(jìn)行測(cè)試的,即feature場(chǎng)景已完成常規(guī)測(cè)試,在這種情況下,一般而言release只有少數(shù)改動(dòng)。在這里我們先不討論項(xiàng)目流程問(wèn)題。

使用start指令開(kāi)啟一個(gè)release場(chǎng)景,通常以版本號(hào)命令,我們以v2.0為例:

git flow release start v2.0

此命令會(huì)基于本地的develop分支創(chuàng)建一個(gè)release/v2.0分支,并切換到這個(gè)分支上。

為了讓其他協(xié)同人員也能看到此分支,需要將其發(fā)布出去。

git flow release publish v2.0

以上和feature場(chǎng)景十分類似。

待測(cè)試通過(guò)需要發(fā)布正式版:

git flow release finish v2.0

這一步做的動(dòng)作有點(diǎn)多,大致是:

  1. git fetch
  2. release/v2.0分支代碼向master合并。
  3. 生成名為v2.0的tag。
  4. release/v2.0分支代碼向develop合并。
  5. 刪除本地release/v2.0分支。
  6. 切換回develop分支。

如果merge產(chǎn)生沖突不會(huì)終止流程,只是不會(huì)將本地的release分支刪除,待解決完沖突后需再次執(zhí)行finish指令。

另外需要注意的是,如果本地還有未finish的release分支,將不允許使用start指令開(kāi)啟新的release分支,這一點(diǎn)是對(duì)并行發(fā)布的一個(gè)限制。

release finish只是完成了本地代碼的一系列操作,還需要同步到遠(yuǎn)程倉(cāng)庫(kù)。

git push origin develop
git push origin master
git push origin v2.0

或者使用下面的命令推送所有的分支和tag。

git push origin --all
git push origin --tags

hotfix場(chǎng)景

當(dāng)tag打完,也表示正式版本發(fā)布出去了,如果此時(shí)在線上發(fā)現(xiàn)了嚴(yán)重的bug,需要進(jìn)行緊急修復(fù),流程如下:

hotfix.jpg

此時(shí)我們假設(shè)版本號(hào)變?yōu)関2.0-patch。

git flow hotfix start v2.0-patch

這將創(chuàng)建一個(gè)hotfix/v2.0本地分支并切換到該分支。
hotfix沒(méi)有publish指令,認(rèn)為hotfix應(yīng)該是個(gè)小范圍改動(dòng),不需要其他協(xié)同人員參與。

待本地修改結(jié)束commit后,執(zhí)行finish指令。

git flow hotfix finish v2.0-patch

按照Gitflow工作流,它會(huì)執(zhí)行下面的任務(wù),與release基本一致。

  1. git fetch
  2. hotfix/v2.0-patch分支代碼向master合并。
  3. 生成名為v2.0-patch的tag。
  4. hotfix/v2.0-patch分支代碼向develop合并。
  5. 刪除本地hotfix/v2.0-patch分支。
  6. 切換回develop分支。

快捷腳本

在實(shí)際開(kāi)發(fā)中發(fā)現(xiàn),Gitflow命令有點(diǎn)長(zhǎng),容易敲錯(cuò)。比如git flow feature start <name>,因此我寫(xiě)了一個(gè)簡(jiǎn)化的指令,通過(guò)它可以這樣寫(xiě)./gitflow -fs <name>。也就是取Gitflow指令關(guān)鍵字的首字母組合,為新的指令集。

詳情參見(jiàn)Github gitflow.sh

Sourcetree支持

Sourcetree完全支持Gitflow的所有操作,如果你習(xí)慣于使用圖形化工具管理你的代碼,可以直接使用Sourcetree的Gitflow功能。

Sourcetree操作界面.png

了解了上面的命令,這個(gè)圖形化界面基本就都能見(jiàn)名知意了。

其他代碼工作流

與Gitflow相似的代碼管理工作流還有,Github flow和Gitlab flow。

Github flow是簡(jiǎn)化版的Gitflow,它使用master和feature來(lái)管理代碼,它只有一個(gè)長(zhǎng)期分支,就是master。Gitlab flow更關(guān)注代碼的持續(xù)集成,一個(gè)版本需要?jiǎng)?chuàng)建測(cè)試環(huán)境、預(yù)覽環(huán)境、生產(chǎn)環(huán)境的分支,最終匯總到stable branch用于發(fā)布,感興趣的小伙伴可以自行了解。

下表是筆者對(duì)三者特點(diǎn)的理解:

項(xiàng)目 Gitflow Github flow Gitlab flow
特點(diǎn) 基于master和develop分支 基于master分支和PR 基于master分支,使用“上游優(yōu)先”原則
易用性 復(fù)雜,需結(jié)合Gitflow工具 簡(jiǎn)單 一般
并行開(kāi)發(fā) 簡(jiǎn)單 一般
側(cè)重點(diǎn) 靈活性、多feature管理/版本管理 分支維護(hù)效率 持續(xù)集成
歷史版本維護(hù) tag tag或stable branch stable branch

實(shí)際上Gitflow的發(fā)布流程一直飽受爭(zhēng)議,反對(duì)者認(rèn)為feature開(kāi)發(fā)周期一般較長(zhǎng),也就是可能在較長(zhǎng)時(shí)間內(nèi)不能合并到主干分支,這不利于持續(xù)集成,且在合并到主干時(shí)可能產(chǎn)生大量沖突,參看這篇Gitflow有害論

但筆者認(rèn)為如果你正在參與一個(gè)企業(yè)級(jí)的項(xiàng)目,一個(gè)版本將要上線的features可能因各種原因變動(dòng)或下線,此時(shí)如果沒(méi)有獨(dú)立的feature分支而全部在主干分支,將極難處理代碼的回滾和保護(hù);換個(gè)角度說(shuō),merge沖突也可以通過(guò)其他方式規(guī)避,比如良好的代碼分層、事先約定好跨模塊通信的接口等。

從持續(xù)集成的角度來(lái)說(shuō),由于Gitflow管理的分支類型較多,不應(yīng)所有分支都參與持續(xù)集成,可結(jié)合實(shí)際場(chǎng)景選擇開(kāi)啟持續(xù)集成的分支類型,比如master和release。

最后,沒(méi)有最好的方案,只有最適合的方案,實(shí)際的項(xiàng)目管理過(guò)程中應(yīng)根據(jù)不同工作流的特點(diǎn)選擇適合的方案即可。

如果你還有什么疑問(wèn),歡迎留言探討。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 228,316評(píng)論 6 531
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 98,481評(píng)論 3 415
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人,你說(shuō)我怎么就攤上這事。” “怎么了?”我有些...
    開(kāi)封第一講書(shū)人閱讀 176,241評(píng)論 0 374
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我,道長(zhǎng),這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 62,939評(píng)論 1 309
  • 正文 為了忘掉前任,我火速辦了婚禮,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 71,697評(píng)論 6 409
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書(shū)人閱讀 55,182評(píng)論 1 324
  • 那天,我揣著相機(jī)與錄音,去河邊找鬼。 笑死,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,247評(píng)論 3 441
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書(shū)人閱讀 42,406評(píng)論 0 288
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 48,933評(píng)論 1 334
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 40,772評(píng)論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 42,973評(píng)論 1 369
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,516評(píng)論 5 359
  • 正文 年R本政府宣布,位于F島的核電站,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 44,209評(píng)論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 34,638評(píng)論 0 26
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 35,866評(píng)論 1 285
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 51,644評(píng)論 3 391
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 47,953評(píng)論 2 373