本文轉(zhuǎn)載自:https://segmentfault.com/a/1190000004963641[1]
在 2005 年的某一天,Linux 之父 Linus Torvalds 發(fā)布了他的又一個(gè)里程碑作品——Git。它的出現(xiàn)改變了軟件開發(fā)流程,大大地提高了開發(fā)流暢度!直到現(xiàn)在仍十分流行,完全沒有衰退的跡象。
本文不是一篇 Git 入門教程,這樣的文章一搜一大把,我是要從具體實(shí)踐角度,尤其是在團(tuán)隊(duì)協(xié)作中,闡述如何去好好地應(yīng)用 Git。既然是講在團(tuán)隊(duì)中的應(yīng)用實(shí)踐,我就盡可能地結(jié)合實(shí)際場(chǎng)景來(lái)講述。
如果一個(gè)團(tuán)隊(duì)在使用 Git 時(shí)沒有一些規(guī)范,那么將是一場(chǎng)難以醒來(lái)的噩夢(mèng)!然而,規(guī)范固然重要,但更重要的是個(gè)人素質(zhì),在使用 Git 時(shí)需要自己養(yǎng)成良好的習(xí)慣。
如何去寫一個(gè)提交信息,《Git: 教你如何在Commit時(shí)有話可說(shuō)》[2]中做了很好的說(shuō)明。在具體開發(fā)工作中主要需要遵守的原則就是「使每次提交都有質(zhì)量」,只要堅(jiān)持做到以下幾點(diǎn)就 OK 了:
·提交時(shí)的粒度是一個(gè)小功能點(diǎn)或者一個(gè) bug fix,這樣進(jìn)行恢復(fù)等的操作時(shí)能夠?qū)ⅰ刚`傷」減到最低;·用一句簡(jiǎn)練的話寫在第一行,然后空一行稍微詳細(xì)闡述該提交所增加或修改的地方;·不要每提交一次就推送一次,多積攢幾個(gè)提交后一次性推送,這樣可以避免在進(jìn)行一次提交后發(fā)現(xiàn)代碼中還有小錯(cuò)誤。
假如已經(jīng)把代碼提交了,對(duì)這次提交的內(nèi)容進(jìn)行檢查時(shí)發(fā)現(xiàn)里面有個(gè)變量單詞拼錯(cuò)了或者其他失誤,只要還沒有推送到遠(yuǎn)程,就有一個(gè)不被他人發(fā)覺你的疏忽的補(bǔ)救方法——
首先,把失誤修正之后提交,可以用與上次提交同樣的信息。
然后,終端中執(zhí)行命令 git rebase -i [SHA]
,其中 SHA 是上一次提交之前的那次提交的,在這里是 3b22372
。
最后,這樣就將兩次提交的節(jié)點(diǎn)合并成一個(gè),甚至能夠修改提交信息!
誰(shuí)說(shuō)歷史不可篡改了?前提是,想要合并的那幾次提交還沒有推送到遠(yuǎn)程!
當(dāng)自己一個(gè)人進(jìn)行開發(fā)時(shí),在功能完成之前不要急著創(chuàng)建遠(yuǎn)程分支。
請(qǐng)讀張文鈿所寫的《使用 git rebase 避免無(wú)謂的 merge》:https://ihower.tw/blog/archives/3843。[3]
在將其他分支的代碼合并到當(dāng)前分支時(shí),如果那個(gè)分支是當(dāng)前分支的父分支,為了保持圖表的可讀性和可追蹤性,可以考慮用 git rebase
來(lái)代替 git merge
;反過(guò)來(lái)或者不是父子關(guān)系的兩個(gè)分支以及互相已經(jīng) git merge
過(guò)的分支,就不要采用 git rebase
了,避免出現(xiàn)重復(fù)的沖突和提交節(jié)點(diǎn)。
Git 的一大特點(diǎn)就是可以創(chuàng)建很多分支并行開發(fā)。正因?yàn)樗撵`活性,團(tuán)隊(duì)中如果沒有一個(gè)成熟的分支模型的話,那將會(huì)是一團(tuán)糟。
要是誰(shuí)真把這么亂的提交圖表擺在我面前,就給他一個(gè)上勾拳!
有個(gè)很成熟的叫 Git Flow 的分支模型,它能夠應(yīng)對(duì) 99% 的場(chǎng)景,剩下的那 1% 留給幾乎不存在的極度變態(tài)的場(chǎng)景。
需要注意的是,它只是一個(gè)模型,而不是一個(gè)工具;你可以用工具去應(yīng)用這個(gè)模型,也可以用最樸實(shí)的命令行。所以,重要的是理解概念,不要執(zhí)著于實(shí)行的手段。
簡(jiǎn)單說(shuō)來(lái),Git Flow 就是給原本普普通通的分支賦予了不同的「職責(zé)」:
·master——最為穩(wěn)定功能最為完整的隨時(shí)可發(fā)布的代碼;·hotfix——修復(fù)線上代碼的 bug;·develop——永遠(yuǎn)是功能最新最全的分支;·feature——某個(gè)功能點(diǎn)正在開發(fā)階段;·release——發(fā)布定期要上線的功能。
看到上面的「master」和「develop」加粗了吧?代表它們是「主要分支」,其他的分支是基于它們派生出來(lái)的。主要分支每種類型只能有一個(gè),派生分支每個(gè)類型可以同時(shí)存在多個(gè)。各類型分支之間的關(guān)系用一張圖來(lái)體現(xiàn)就是:
更多信息可參考 xirong[4] 所整理的《Git工作流指南》:https://github.com/xirong/my-git/blob/master/git-workflow-tutorial.md。[5]
一直不喜歡「**最好用」這種命題,主觀性太強(qiáng),不會(huì)有一個(gè)結(jié)論。對(duì)于工具的選擇,我一直都是秉承「哪個(gè)能更好地解決問(wèn)題就用哪個(gè)」這個(gè)原則。所以,只要不影響到團(tuán)隊(duì),用什么工具都是可以接受的。但根據(jù)多數(shù)開發(fā)人員的素質(zhì)情況來(lái)看,建議使用圖形化工具,例如 SourceTree(https://www.sourcetreeapp.com/[6])。如果想用命令行,可以啊!先在心里問(wèn)下自己:「我 Git 牛逼不?會(huì)不會(huì)惹麻煩給別人?」
在團(tuán)隊(duì)中應(yīng)用 Git Flow 時(shí),推薦使用 SourceTree 與 GitLab (https://gitlab.com/[7])配合的形式:
·用 SourceTree 創(chuàng)建 feature 等分支以及本地的分支合并、刪除;·用 GitLab 做代碼審核和遠(yuǎn)程的分支合并、刪除。
SourceTree 和 GitLab 應(yīng)該是相輔相成的存在,而不是互相取代。
為了將一些規(guī)范性的東西和 Git Flow 的部分操作自動(dòng)化處理,要對(duì) SourceTree 和 GitLab 進(jìn)行一下配置。
按下 command
+ ,
調(diào)出「Preferences」界面并切換到「Git」標(biāo)簽,勾選「Use rebase instead of merge by default for tracked branches」和「Do not fast-forward when merging, always create commit」。
這樣設(shè)置之后,在點(diǎn)「Pull」按鈕拉取代碼時(shí)會(huì)自動(dòng)執(zhí)行 git pull --rebase
;并且,每次合并時(shí)會(huì)自動(dòng)創(chuàng)建新的包含分支信息的提交節(jié)點(diǎn)。
接下來(lái),點(diǎn)擊工具欄中的「Git Flow」按鈕將相關(guān)的流程自動(dòng)化。如果沒有特殊需求,直接按下對(duì)話框中的「OK」就好了。初始化完成后會(huì)自動(dòng)切換到 develop 分支。
這下再點(diǎn)「Git Flow」按鈕所彈出的對(duì)話框就是選擇創(chuàng)建分支類型的了。
在創(chuàng)建項(xiàng)目倉(cāng)庫(kù)后一定要把主要分支,也就是 master 和 develop 給保護(hù)起來(lái)。為它們?cè)O(shè)置權(quán)限,只有項(xiàng)目負(fù)責(zé)人可以進(jìn)行推送和刪除等操作。
被保護(hù)的分支在列表中會(huì)有特殊的標(biāo)記進(jìn)行區(qū)分。
在引入 Git Flow 之后,所有工作都要圍繞著它來(lái)展開,將原本的流程與之結(jié)合形成「基于 Git Flow 的開發(fā)流程」。
在確定發(fā)布日期之后,將需要完成的內(nèi)容細(xì)分一下分配出去,負(fù)責(zé)某個(gè)功能的開發(fā)人員利用 SourceTree 所提供的 Git Flow 工具創(chuàng)建一個(gè)對(duì)應(yīng)的 feature 分支。如果是多人配合的話,創(chuàng)建分支并做一些初始化工作之后就推送創(chuàng)建遠(yuǎn)程分支;否則,直到功能開發(fā)完畢要合并進(jìn) develop 前,不要?jiǎng)?chuàng)建遠(yuǎn)程分支。
功能開發(fā)完并自測(cè)之后,先切換到 develop 分支將最新的代碼拉取下來(lái),再切換回自己負(fù)責(zé)的 feature 分支把 develop 分支的代碼合并進(jìn)來(lái)。合并方式參照上文中的「合并」,如果有沖突則自己和配合的人一起解決。
然后,到 GitLab 上的項(xiàng)目首頁(yè)創(chuàng)建合并請(qǐng)求(merge request)。
「來(lái)源分支」選擇要被合并的 feature 分支且「目標(biāo)分支」選擇 develop 分支后點(diǎn)擊「比較分支」按鈕,在出現(xiàn)的表單中將處理人指派為項(xiàng)目負(fù)責(zé)人。
項(xiàng)目負(fù)責(zé)人在收到合并請(qǐng)求時(shí),應(yīng)該先做下代碼審核看看有沒有明顯的嚴(yán)重的錯(cuò)誤;有問(wèn)題就找負(fù)責(zé)開發(fā)的人去修改,沒有就接受請(qǐng)求并刪除對(duì)應(yīng)的 feature 分支。
在將某次發(fā)布的所需功能全部開發(fā)完成時(shí),就可以交付測(cè)試了。
負(fù)責(zé)測(cè)試的人創(chuàng)建一個(gè) release 分支部署到測(cè)試環(huán)境進(jìn)行測(cè)試;若發(fā)現(xiàn)了 bug,相應(yīng)的開發(fā)人員就在 release 分支上或者基于 release 分支創(chuàng)建一個(gè)分支進(jìn)行修復(fù)。
當(dāng)確保某次發(fā)布的功能可以發(fā)布時(shí),負(fù)責(zé)發(fā)布的人將 release 分支合并進(jìn) master 和 develop 并打上 tag,然后打包發(fā)布到線上環(huán)境。
建議打 tag 時(shí)在信息中詳細(xì)描述這次發(fā)布的內(nèi)容,如:添加了哪些功能,修復(fù)了什么問(wèn)題。
當(dāng)發(fā)現(xiàn)線上環(huán)境的代碼有小問(wèn)題或者做些文案修改時(shí),相關(guān)開發(fā)人員就在本地創(chuàng)建 hotfix 分支進(jìn)行修改,具體操作參考「開發(fā)功能」。
如果是相當(dāng)嚴(yán)重的問(wèn)題,可能就得回滾到上一個(gè) tag 的版本了。
這里所提到的事情,雖非必需,但知道之后卻會(huì)如虎添翼。
除了主要分支的名字是固定的之外,派生分支是需要自己命名的,這里就要有個(gè)命名規(guī)范了。強(qiáng)烈推薦用如下形式:
·feature——按照功能點(diǎn)(而不是需求)命名;·release——用發(fā)布時(shí)間命名,可以加上適當(dāng)?shù)那熬Y;·hotfix——GitLab 的 issue 編號(hào)或 bug 性質(zhì)等。
另外還有 tag,用語(yǔ)義化的版本號(hào)(http://semver.org/lang/zh-CN/)命名。[8]
發(fā)布頻率是影響開發(fā)人員與測(cè)試人員的新陳代謝和心情的重要因素之一,頻繁無(wú)規(guī)律的發(fā)布會(huì)導(dǎo)致內(nèi)分泌失調(diào)、情緒暴躁,致使爆粗口、砸電腦等狀況出現(xiàn)。所以,確保一個(gè)固定的發(fā)布周期至關(guān)重要!
在有一波或幾波需求來(lái)臨之時(shí),想擋掉是不太可能的,但可以在評(píng)審時(shí)將它(們)分期,在某個(gè)發(fā)布日之前只做一部分。這是必須要控制住的!不然任由著需求方說(shuō)「這個(gè)今天一定要上」「那個(gè)明天急著用」的話,技術(shù)人員就等著進(jìn)醫(yī)院吧!
聯(lián)系客服