Git 是目前最流行的源代碼管理工具箫津。大量的軟件項(xiàng)目由 GitHub胎食、Bitbucket 和 GitLab 這樣的云服務(wù)平臺或是私有的 Git 倉庫來管理凯肋。在使用 Git 時(shí)通常會遇到的一個(gè)問題是采用何種分支管理實(shí)踐仑濒,即如何管理倉庫中作用不同的各類分支。和軟件開發(fā)中的其他實(shí)踐一樣朝墩,Git 分支管理并沒有普遍適用的最佳做法醉拓,而只有對每個(gè)團(tuán)隊(duì)和項(xiàng)目而言最適合的做法。簡單來說收苏,在項(xiàng)目開發(fā)中使用多個(gè)分支會帶來額外的管理和維護(hù)開銷亿卤,但是多個(gè)分支對于項(xiàng)目的團(tuán)隊(duì)合作、新功能開發(fā)和發(fā)布管理都是有一定好處的鹿霸。不同的團(tuán)隊(duì)可以根據(jù)團(tuán)隊(duì)人員組成和意愿排吴、項(xiàng)目的發(fā)布周期等因素選擇最適合的策略,找到最適合團(tuán)隊(duì)的管理方式懦鼠。本文將介紹三種常見的 Git 分支管理方式钻哩。
單主干
單主干的分支實(shí)踐(Trunk-based development,TBD)在 SVN 中比較流行肛冶。Google?和?Facebook?都使用這種方式街氢。trunk 是 SVN 中主干分支的名稱,對應(yīng)到 Git 中則是 master 分支睦袖。TBD 的特點(diǎn)是所有團(tuán)隊(duì)成員都在單個(gè)主干分支上進(jìn)行開發(fā)珊肃。當(dāng)需要發(fā)布時(shí),先考慮使用標(biāo)簽(tag)馅笙,即 tag 某個(gè) commit 來作為發(fā)布的版本近范。如果僅靠 tag 不能滿足要求,則從主干分支創(chuàng)建發(fā)布分支延蟹。bug 修復(fù)在主干分支中進(jìn)行,再 cherry-pick 到發(fā)布分支叶堆。圖 1 是 TBD 中分支流程的示意圖阱飘。
圖 1. TBD 中的分支流程的示意圖
由于所有開發(fā)人員都在同一個(gè)分支上工作,團(tuán)隊(duì)需要合理的分工和充分的溝通來保證不同開發(fā)人員的代碼盡可能少的發(fā)生沖突虱颗。持續(xù)集成和自動(dòng)化測試是必要的沥匈,用來及時(shí)發(fā)現(xiàn)主干分支中的 bug。因?yàn)橹鞲煞种撬虚_發(fā)人員公用的忘渔,一個(gè)開發(fā)人員引入的 bug 可能對其他很多人造成影響高帖。不過好處是由于分支所帶來的額外開銷非常小。開發(fā)人員不需要頻繁在不同的分支之間切換畦粮。
GitHub flow
GitHub flow?是 GitHub 所使用的一種簡單的流程散址。該流程只使用兩類分支,并依托于 GitHub 的 pull request 功能预麸。在 GitHub flow 中吏祸,master 分支中包含穩(wěn)定的代碼。該分支已經(jīng)或即將被部署到生產(chǎn)環(huán)境蹈矮。master 分支的作用是提供一個(gè)穩(wěn)定可靠的代碼基礎(chǔ)鸣驱。任何開發(fā)人員都不允許把未測試或未審查的代碼直接提交到 master 分支丐巫。
對代碼的任何修改,包括 bug 修復(fù)碑韵、hotfix祝闻、新功能開發(fā)等都在單獨(dú)的分支中進(jìn)行遗菠。不管是一行代碼的小改動(dòng)辙纬,還是需要幾個(gè)星期開發(fā)的新功能,都采用同樣的方式來管理蓖谢。當(dāng)需要進(jìn)行修改時(shí)闪幽,從 master 分支創(chuàng)建一個(gè)新的分支涡匀。新分支的名稱應(yīng)該簡單清晰地描述該分支的作用。所有相關(guān)的代碼修改都在新分支中進(jìn)行腕够。開發(fā)人員可以自由地提交代碼和 push 到遠(yuǎn)程倉庫燕少。
當(dāng)新分支中的代碼全部完成之后,通過 GitHub 提交一個(gè)新的 pull request崇决。團(tuán)隊(duì)中的其他人員會對代碼進(jìn)行審查恒傻,提出相關(guān)的修改意見建邓。由持續(xù)集成服務(wù)器(如 Jenkins)對新分支進(jìn)行自動(dòng)化測試官边。當(dāng)代碼通過自動(dòng)化測試和代碼審查之后,該分支的代碼被合并到 master 分支契吉。再從 master 分支部署到生產(chǎn)環(huán)境捐晶。圖 2 是 GitHub flow 分支流程的示意圖惑灵。
圖 2. Github flow 中的分支流程的示意圖
GitHub flow 的好處在于非常簡單實(shí)用英支。開發(fā)人員需要注意的事項(xiàng)非常少哮伟,很容易形成習(xí)慣澈吨。當(dāng)需要進(jìn)行任何修改時(shí)谅辣,總是從 master 分支創(chuàng)建新分支婶恼。完成之后通過 pull request 和相關(guān)的代碼審查來合并回 master 分支柏副。GitHub flow 要求項(xiàng)目有完善的自動(dòng)化測試割择、持續(xù)集成和部署等相關(guān)的基礎(chǔ)設(shè)施荔泳。每個(gè)新分支都需要測試和部署虐杯,如果這些不能自動(dòng)化進(jìn)行擎椰,會增加開發(fā)人員的工作量达舒,導(dǎo)致無法有效地實(shí)施該流程。這種分支實(shí)踐也要求團(tuán)隊(duì)有代碼審查的相應(yīng)流程昨登。
git-flow
git-flow?應(yīng)該是目前流傳最廣的 Git 分支管理實(shí)踐糯俗。git-flow 圍繞的核心概念是版本發(fā)布(release)得湘。因此 git-flow 適用于有較長版本發(fā)布周期的項(xiàng)目淘正。雖然目前推崇的做法是持續(xù)集成和隨時(shí)發(fā)布鸿吆。有的項(xiàng)目甚至可以一天發(fā)布很多次惩淳。隨時(shí)發(fā)布對于 SaaS 服務(wù)類的項(xiàng)目來說是很適合的思犁。不過仍然有很大數(shù)量的項(xiàng)目的發(fā)布周期是幾個(gè)星期甚至幾個(gè)月。較長的發(fā)布周期可能是由于非技術(shù)相關(guān)的因素造成的棉磨,比如人員限制学辱、管理層決策和市場營銷策略等项郊。
git-flow 流程中包含 5 類分支着降,分別是 master、develop蓄喇、新功能分支(feature)交掏、發(fā)布分支(release)和 hotfix盅弛。這些分支的作用和生命周期各不相同。master 分支中包含的是可以部署到生產(chǎn)環(huán)境中的代碼见秽,這一點(diǎn)和 GitHub flow 是相同的解取。develop 分支中包含的是下個(gè)版本需要發(fā)布的內(nèi)容返顺。從某種意義上來說振乏,develop 是一個(gè)進(jìn)行代碼集成的分支。當(dāng) develop 分支集成了足夠的新功能和 bug 修復(fù)代碼之后秉扑,通過一個(gè)發(fā)布流程來完成新版本的發(fā)布昆码。發(fā)布完成之后,develop 分支的代碼會被合并到 master 分支中。
其余三類分支的描述如表 1所示赋咽。這三類分支只在需要時(shí)從 develop 或 master 分支創(chuàng)建。在完成之后合并到 develop 或 master 分支吨娜。合并完成之后該分支被刪除脓匿。這幾類分支的名稱應(yīng)該遵循一定的命名規(guī)范,以方便開發(fā)人員識別宦赠。
對于使用 Apache Maven 的項(xiàng)目來說陪毡,Atlassian 的?JGit-Flow?是一個(gè)更好的 git-flow 實(shí)現(xiàn)。JGit-Flow 是一個(gè)基于?JGit?的純 Java 實(shí)現(xiàn)的 git-flow勾扭,并不需要安裝額外的腳本,只需要作為 Maven 的插件添加到 Maven 項(xiàng)目中即可丐谋。JGit-Flow 同時(shí)可以替代?Maven release 插件來進(jìn)行發(fā)布管理定庵。JGit-Flow 會負(fù)責(zé)正確的設(shè)置不同分支中的 Maven 項(xiàng)目的 POM 文件中的版本,這對于 Maven 項(xiàng)目的構(gòu)建和發(fā)布是很重要的。
在 Maven 項(xiàng)目的 pom.xml 文件中添加代碼清單1中的插件聲明就可以使用 JGit-Flow蜜唾。中包含的是 JGit-Flow 不同任務(wù)的配置咱揍。
清單 1. JGit-Flow 的 Maven 設(shè)置
在啟用了 JGit-Flow 之后,可以通過 mvn 運(yùn)行 jgitflow:feature-start 和 jgitflow:feature-finish 來開始和結(jié)束新特性的開發(fā)欣硼。與版本發(fā)布和 hotfix 相關(guān)的命令分別是 jgitflow:release-start 和 jgitflow:release-finish 以及 jgitflow:hotfix-start 和 jgitflow:hotfix-finish焦匈。在運(yùn)行命令之后,JGit-Flow 會完成相關(guān)的 Git 分支創(chuàng)建、合并、刪除渴析、添加 tag 等操作漓帚,不需要開發(fā)人員手動(dòng)完成。
每個(gè)分支的 pom.xml 中的版本號的格式并不相同衙熔。如 master 分支的版本號是標(biāo)準(zhǔn)的發(fā)布版本號,如 1.2.3;develop 分支中則是 SNAPSHOT 版本婉称,比 master 分支的版本號要高,如 1.2.4-SNAPSHOT;release 分支可以通過配置來指定版本號的后綴,如 1.2.3-RC-SNAPSHOT;feature 分支可以通過配置來把 feature 分支名稱作為后綴添加到版本號中,如 1.2.3-my-awesome-feature-SNAPSHOT;hotfix 分支的版本號基于 master 分支的版本號,如 1.2.3.1 是對于 1.2.3 版本的第一個(gè) hotfix。當(dāng)使用 jgitflow:release-finish 完成一個(gè) release 分支時(shí),develop 分支的版本號會被自動(dòng)更新成下一個(gè)小版本莫瞬,如從 1.2.3 到 1.2.4疼邀。當(dāng)需要手動(dòng)修改版本號時(shí)拐袜,可以使用?Versions 插件秉撇,如 mvn versions:set -DnewVersion=2.0.0-SNAPSHOT甜攀。
持續(xù)集成
由于 JGit-Flow 是純 Java 的 Maven 插件實(shí)現(xiàn),可以很容易的與常用的持續(xù)集成服務(wù)器進(jìn)行集成琐馆。不過在與 Atlassian 的 Bamboo 集成時(shí)规阀,有幾個(gè)細(xì)節(jié)需要注意谁撼。首先是 Bamboo 在進(jìn)行構(gòu)建的時(shí)候墨榄,使用的是一個(gè)虛擬的 Git 倉庫之剧,其倉庫地址是一個(gè)不存在的文件系統(tǒng)路徑贰盗。因此需要在 JGit-Flow 的配置中手動(dòng)設(shè)置 Git 倉庫的地址,保證 Git 操作可以正確執(zhí)行锨能。
另外在開始新的 release 之前,需要確保前一個(gè)發(fā)布分支已經(jīng)被刪除芍耘。JGit-Flow 在默認(rèn)情況下會自動(dòng)在發(fā)布完成之后址遇,刪除對應(yīng)的 Git 分支。但是可能本地倉庫中還保留有之前的發(fā)布分支斋竞,這會導(dǎo)致新的 release-start 任務(wù)執(zhí)行失敗倔约。一種解決方式是每次都重新 checkout 新的倉庫,這樣可以保證不會出現(xiàn)已經(jīng)在遠(yuǎn)程被刪除的分支坝初。不過可能會增加構(gòu)建的時(shí)間浸剩。另外一種解決方式是通過 Git 命令來刪除本地分支。
Git 分支合并沖突處理
當(dāng)把發(fā)布分支合并到 develop 時(shí)鳄袍,可能會出現(xiàn)沖突绢要。因?yàn)樵诎l(fā)布分支中有與 bug fix 相關(guān)的改動(dòng),在 develop 分支中有可能修改相同的文件拗小。當(dāng)有沖突時(shí)重罪,直接運(yùn)行 JGit-Flow 的 release-finish 任務(wù)會出錯(cuò)。這個(gè)時(shí)候需要開發(fā)人員手動(dòng)把發(fā)布分支合并到 develop 分支哀九,并解決相應(yīng)的沖突剿配。然后再次運(yùn)行 release-finish 任務(wù)即可。
選擇合適的實(shí)踐
每個(gè)開發(fā)團(tuán)隊(duì)都應(yīng)該根據(jù)團(tuán)隊(duì)自身和項(xiàng)目的特點(diǎn)來選擇最適合的分支實(shí)踐阅束。首先是項(xiàng)目的版本發(fā)布周期呼胚。如果發(fā)布周期較長,則 git-flow 是最好的選擇息裸。git-flow 可以很好地解決新功能開發(fā)蝇更、版本發(fā)布沪编、生產(chǎn)系統(tǒng)維護(hù)等問題;如果發(fā)布周期較短簿寂,則 TBD 和 GitHub flow 都是不錯(cuò)的選擇漾抬。GitHub flow 的特色在于集成了 pull request 和代碼審查。如果項(xiàng)目已經(jīng)使用 GitHub常遂,則 GitHub flow 是最佳的選擇纳令。GitHub flow 和 TBD 對持續(xù)集成和自動(dòng)化測試等基礎(chǔ)設(shè)施有比較高的要求。如果相關(guān)的基礎(chǔ)設(shè)施不完善克胳,則不建議使用平绩。
小結(jié)
Git 作為目前最流行的源代碼管理工具,已經(jīng)被很多開發(fā)人員所熟悉和使用漠另。在基于 Git 的團(tuán)隊(duì)開發(fā)中捏雌,Git 分支的作用非常重要,可以讓團(tuán)隊(duì)的不同成員同時(shí)在多個(gè)相對獨(dú)立的特性上工作笆搓。本文對目前流行的 3 種 Git 分支管理實(shí)踐做了介紹性湿,并著重介紹了 git-flow 以及與之相關(guān)的 Maven JGit-Flow 插件。