翻譯:《一個成功的Git分支模型》為什么是有害的
原文鏈接:https://barro.github.io/2016/02/a-succesful-git-branching-model-considered-harmful/
當大家開始使用Git并且開始了解到分支概念及分支方便之處的時候尉剩,你們可能會在Google上搜一搜相關知識艺糜,然后經常會搜到一篇注明的博客A success Git branching model。最大的問題是這篇文章出現在所有搜索結果的最前面茫虽,原本他應該用做一個使用分支開發(fā)的反例峦嗤。
《一個成功的分支模型》錯在了哪
直入正題,這種開發(fā)方式里你會把一切都共享到遠程分支,然后merge到本地,本來很簡單的事情變得很麻煩了谱仪。開發(fā)可靠系統(tǒng)的原則是保持理智。這個分支模型錯在一開始就沒有使用眾所周知的master分支作為工作分支德迹。
用獨立的分支來開發(fā)功能很難確保合并的時候各項功能正常芽卿。這個問題在持續(xù)集成概念被廣泛認可的今天尤其嚴重。只有通過周期性得把所有的變動集成在一起胳搞,你才才可以避免了大的集成問題,這些集成問題都會都會花費你大量的時間去解決称杨,尤其是幾百個上千個人開發(fā)的大項目肌毅。這個分支模型體現的開發(fā)實踐鼓勵程序員在各自分支上開發(fā)功能,這將導致巨大的集成問題而不是避免他姑原。
除此之外悬而,在《一個成功的分支模型里》里,合并提交記錄被鼓勵作為集成代碼變動的主要方式锭汛。我將會解釋為什么合并提交是不好的以及用了這種方法笨奠,你將失去的東西。
合并提交錯在了哪
《一個成功的分支模型》講了非向前合并提交可以被認為是一種保持某個功能相關的commit記錄的方式唤殴。然后如果你決定這個功能不合適般婆,你可以revert那個提交然后整個功能都去掉了。我認為這是一個去掉一個功能或者在第一次開發(fā)就完成這個功能是非常罕見的場景朵逝。
在Git中蔚袍,合并經常會造成額外的一些提交記錄,這些記錄有一些特殊的日志信息像“Merge branch ‘some-branch’ of git://git.some.domain/repository/”配名。這個東西不能提供任何關于代碼變動的信息啤咽。你不得不去讀commit信息,可能要讀到第二段渠脉,這還不包括得看分支歷史宇整。
有一個非線性的歷史,問題只有在集成的時候才包括芋膘,也是得git bisect更難了鳞青,你可能兩個獨立分支都非常好涩哟,但是合并提交失敗了,因為你們的改變沒有沖突盼玄。這種情況下尤其嚴重贴彼,你如一個開發(fā)者改了接口,然后其他的開發(fā)者用了舊的接口定義埃儿。這種問題很難被定位和解決器仗,但是有了線性的歷史,沒有任何合并提交記錄童番,我們可以很快發(fā)現哪次提交造成了問題精钮。
更簡單的解決方案
讓我展示一個更簡單的替代方案,我們可以稱他為仙人掌模型剃斧。這個名字來源于在這個方案中轨香,所有的分支都是從master分支切出來的并且從不合并回去。仙人掌模型反映了一個用git開發(fā)更自然的方法幼东,確保持續(xù)集成法則可用臂容。
在上圖中,你可以看到仙人掌分支模型遵守下面章節(jié)會講到的準則根蟹。一些準則可能可能需要 Gerrit 和一些類似的集成代碼審查工具
所有的開發(fā)都在master分支
master分支是你克隆項目后的默認分支脓杉,既然這樣我們?yōu)槭裁床话阉械拈_發(fā)放在這個分支呢?不再需要猜也沒必要給開發(fā)的分支寫文檔简逮。這個是唯一從中央倉庫克隆的項目并且對每個人都是最新的分支球散。個人開發(fā)者鼓勵使用本地分支,避免分享到遠端分支散庶。
開發(fā)者應該周期性git rebase 他們的變動蕉堰,保持和最新的origin/master同步。這確保我們不會在一個過期的基準線上開發(fā)悲龟。
用本地分支
仙人掌模型不是不鼓勵使用分支屋讶,因為分支是有用的。特別是一個獨立開發(fā)者應該在本地倉庫使用臨時的功能分支躲舌,然后在合適的時機把它們集成到origin/master丑婿,從而分享給大家。本地的分支主要是為了測試和代碼審查的時候没卸,在功能之間切換更簡單羹奉。
圖二、圖三通過一個可視化的樹形結構展示了一個本地分支和rebase的一個基本的準則约计。在圖二中诀拭,我們的情況是有兩個活躍的本地開發(fā)分支(紫色圓圈)和一個準備代碼審查并集成到origin/master(黃色圓圈)的分支(藍色圓圈)。在圖三中煤蚌,我們用兩次提交更新了orogin/master(黃藍圓圈)耕挨,然后提交了兩次準備代碼審查和集成的commit信息(藍色)细卧。由于分支不會自動消失,所以集成后的提交記錄仍然在本地保存(灰色圓圈)筒占。
分享遠程分支
主要原則:應該避免共享遠程分支贪庙。所有的改動應該都體現在origin/master上,其他的開發(fā)者應該通過持續(xù)的更新翰苫,把它們的改動基于最新的origin/master止邮。這確保了我們不會碰到很多功能分支合并時的集成地獄。
如果你使用代碼審查工具奏窑,像Gerrit或者github导披,然后你可以只是git fetch提交鏈然后在最新的commit上開發(fā)。然后把你的代碼變動提交到你自己倉庫特定分支里埃唯,這樣你就和origin/master保持同步了
發(fā)布分支從orgin/master分支切出來
發(fā)布分支從master分支切出來撩匕。如果我們需要熱修復,在發(fā)布分支上做墨叛,然后把使用的bug修復合并到master分支止毕。通過一些特定的tag和分支名字,我們可以做到自動發(fā)布巍实。
只有向前合并
git merge從不會被使用滓技。要合并到orign/master的變動通過git rebase和git cherry-pick來實現。這避免了因為merge而弄亂了倉庫棚潦,也避免了 圣誕樹外表 。Rebase同樣會讓提交歷史呈線性膝昆,這樣git bisect就非常容易使用了丸边。
如果你使用Gerrit,你同樣可以采用選擇性提交策略荚孵。這可以非常方便得按照意愿順序把一些列的提交合并到origin/master妹窖,而不是非要按照代碼審查的順序來。
結論
對版本控制收叶,git是一個非常棒的工具骄呼。有了它,你可以完成很多難以辦到的事情判没。分支其實是指向 特定提交記錄的指針 蜓萄,你可以非常方便得創(chuàng)建分支。同樣澄峰,你可以做合并嫉沽,這讓分支用起來更簡單。但是這些工具應該讓分支對開發(fā)者來說更簡單而不是更復雜俏竞。
我見過數以百計的開發(fā)者使用著非常糟糕的開發(fā)實踐绸硕。有些組織甚至想從中央倉庫移除master分支堂竟,這是不理智的。