文/劉冉
介紹這個話題祈餐,有兩個原因:
- 從開始工作到現(xiàn)在,我經(jīng)歷過沒有代碼版本管理哄陶、代碼集中式管理帆阳,以及現(xiàn)在的分布式管理,我深刻體會到它在軟件開發(fā)過程中的重要性屋吨;
- 我在工作中遇到的很多客戶都存在對于代碼版本管理的各種問題蜒谤、困惑和不同的需求山宾。
所以我希望將我在這個方面的經(jīng)驗分享給更多人,希望能幫助更多的團(tuán)隊解決在代碼版本控制方面的問題和疑惑芭逝。
一,代碼版本管理系統(tǒng)的歷史
代碼版本管理系統(tǒng)大致可以分為三個時代:
第一代渊胸,本地式
這代主要的特點提供本地代碼版本控制旬盯,比如SCCS(1972)、 PVCS(1985)等翎猛。
這代主要實現(xiàn)了基本的代碼版本管理胖翰,但缺點是無法讓多人同時對一個版本庫進(jìn)行修改。這個也和當(dāng)時軟件規(guī)模不夠大有關(guān)切厘,也沒有這樣的需求萨咳。
第二代,客戶端-服務(wù)器式
這代主要的特點是提供集中式服務(wù)器端代碼版本控制,比如 CVS(1986), ClearCase(1992), Visual SourceSafe(1994), Perforce(1995), Subversion(2000) 等疫稿。
這代主要是實現(xiàn)了中心服務(wù)器端的代碼版本管理培他,特點是可以讓多人同時對一個代碼版本庫進(jìn)行同步和修改,但缺點也相當(dāng)明顯:
- 在無法連接服務(wù)器的情況下遗座,無法查看日志以及提交和比較代碼版本(慢速網(wǎng)絡(luò)和遠(yuǎn)程異地工作的程序員的痛)舀凛,以及當(dāng)服務(wù)或者網(wǎng)絡(luò)出現(xiàn)問題的時候很多人員就會無法工作。
- 不支持local branch途蒋,導(dǎo)致branch創(chuàng)建管理復(fù)雜猛遍,并且一旦創(chuàng)建就很難修改(快速迭代開發(fā)中的程序員的痛)
- 由于只有一個中心端服務(wù)器,一旦發(fā)生災(zāi)難性問題号坡,那么所有日志都會丟失懊烤,所以需要經(jīng)常做備份(備份需要不小的成本)
- 如果軟件代碼量過于龐大,一般會出現(xiàn)速度緩慢的情況宽堆,因為每次的日志查詢腌紧、不同版本之間的代碼比較和代碼提交等操作都需要和服務(wù)器通信,造成服務(wù)器端的負(fù)載過大畜隶。
第三代寄啼,分布式
這代主要的特點是提供分布式代碼版本控制,比如Git(2005), Mercurial(2005)等。
這代結(jié)合了第一代和第二代的優(yōu)點并實現(xiàn)了分布式的代碼版本管理代箭。
這代的優(yōu)點:分布式管理墩划,在沒有和服務(wù)器有連接的情況下仍然可以查看日志,提交代碼嗡综,創(chuàng)建分支乙帮;支持local branch,可以快速方便的實現(xiàn)各種分支管理极景;支持分布式察净,從而可以實現(xiàn)分塊管理驾茴,以及負(fù)載分流管理。
缺點是有一定的學(xué)習(xí)曲線氢卡,比如分布方式下的代碼同步锈至,local branch的理解與運用,分布式代碼管理的理解與運用等译秦。詳細(xì)的比較可以參考:這里峡捡。
二,大型分布式團(tuán)隊
曾經(jīng)有這樣一個分布式團(tuán)隊筑悴,他們在多個城市都有小分隊们拙,并且正在開發(fā)一個大型項目,見下圖
他們使用的代碼版本管理工具是第二代代碼管理工具SVN阁吝,管理方案如下:
但是他們在使用的過程中卻遇到了下面這些問題與痛點。
由于是分布式團(tuán)隊突勇,所以:
- 基于團(tuán)隊的代碼模塊分離困難
當(dāng)服務(wù)器不可用時:
- 不能查看提交記錄
- 不能比較文件
- 不能提交代碼
創(chuàng)建代碼分支時:
- 分支創(chuàng)建速度慢
- 多分支管理困難
在提交代碼時:
- 希望有Code Review
- 希望有CI Review
因為代碼龐大:
- 查看日志慢
備份代碼庫的時候:
- 需要停機(jī)備份
- 備份成本高
針對以上問題,可以使用新一代的分布式的代碼版本管理系統(tǒng)來解決验夯,見下圖:
其中每一個團(tuán)隊都有自己獨立的代碼庫,有一個中心庫用于同步這些獨立的代碼庫摔刁,并且每個庫都由團(tuán)隊自己管理和維護(hù)挥转。而且代碼版本管理系統(tǒng)需要支持輕量分支共屈,代碼評審,離線提交拗引,離線查看日志等功能借宵。
但是由于當(dāng)前沒有一個單一的代碼版本管理工具能同時滿足以上所有需求,所以很多公司都基于它們開發(fā)集成管理系統(tǒng)矾削,比如Gerrit,GitLab哼凯,GitHub,BitBucket等断部。其中的Gerrit由于其開源,免費她渴,以及由Google開發(fā)和維護(hù),并管理著Android趁耗,OpenStack等大型項目源代碼的特點,成為了大型分布式團(tuán)隊優(yōu)先選擇的系統(tǒng)满葛。
三著拭,Gerrit
Gerrit是由Google開發(fā)的牍帚,用于管理Google Android項目源代碼的一個系統(tǒng)。它是基于Java和Prolog等開發(fā)的暗赶,支持Git,權(quán)限管理十嘿,代碼評審等綜合的一個管理系統(tǒng)岳锁。它與GitLab和GitHub最大的不同是它隱藏了代碼分庫管理的細(xì)節(jié),使得開發(fā)人員不需要進(jìn)行fork這樣的手工分庫和同步操作就可以進(jìn)行代碼開發(fā)和提交激率,節(jié)省了開發(fā)人員的時間,見下圖。
由于Android本身是一個開源項目乒躺,所以貢獻(xiàn)者非常多,開發(fā)團(tuán)隊也遍布多個地方(存在時差)嘉冒,導(dǎo)致“如何保證代碼質(zhì)量”成為一個很大的問題。為此Google在Gerrit中加入了功能強(qiáng)大并且十分嚴(yán)格的代碼評審系統(tǒng)顶籽。
首先當(dāng)代碼提交以后并不會直接merge到中心庫里面银觅,它會暫時存在一個臨時庫里面,同時生成一個代碼評審記錄,并向特定的評審人員發(fā)送請求評審的郵件久脯。當(dāng)評審者在評審代碼之后镰吆,如果通過就需要在Gerrit系統(tǒng)里面對代碼進(jìn)行打分,如果通過了就可以將代碼merge到中心庫里面去万皿,如果沒有通過,那么這個代碼提交就需要被返還給開發(fā)者進(jìn)行修改蹬耘。
與此同時它還可以自動觸發(fā)一次包含本次代碼提交的CI構(gòu)建(前提需要手工預(yù)先配置)减余,如果CI自動構(gòu)建和測試通過,也可以自動在Gerrit系統(tǒng)里面進(jìn)行打分如筛,可以給最終進(jìn)行merge的人員進(jìn)行參考抒抬。示意流程見下圖。
由于Android源代碼由上百個獨立的代碼庫組成妖胀,并且編譯一個Android系統(tǒng)需要大部分代碼庫里面的代碼惠勒,所以如何管理如此多的代碼庫也是一個難題,比如如何一次性同步需要編譯一個需要支持特定設(shè)備的代碼庫組合捉撮。為此Google基于Python語言開發(fā)一個工具叫Repo ,這個工具可以自定義你需要的代碼庫的組合肉康,并且一次性對這些代碼庫進(jìn)行同步灼舍,比如pull和push,見下圖炫乓。
四,SVN到Git的遷移
對于想從集中式代碼管理系統(tǒng)遷移到分布式代碼管理系統(tǒng)的團(tuán)隊來講侠姑,如果團(tuán)隊規(guī)模小箩做,那么問題一般都不大,但是對于大型分布式團(tuán)隊卻是困難重重邦邦。最主要的兩個困難:
- 代碼量太大,很難一次性將所有的代碼和日志等在短時間內(nèi)遷移成功鬼店。
- 由于下屬團(tuán)隊太多黔龟,很難同一時間讓所有團(tuán)隊都切換至新的代碼管理工具。
為了解決這些難題稽荧,一般都會首先選用1個團(tuán)隊來使用新的代碼版本管理工具。如果這個團(tuán)隊轉(zhuǎn)換成功芬首,再將其作為標(biāo)桿向其他團(tuán)隊推廣涉瘾,從而逐步的將所有團(tuán)隊切換到新的工具上去。
SVN到Git的遷移方案一般主要會使用兩種工具:
- 開源免費的git-svn泻红;
- 商業(yè)收費的Subgit霞掺。
其中使用Subgit的遷移方案如下圖:
如果團(tuán)隊組資源充足,還可以使用Gerrit搭建一個獨立的Git服務(wù)器缠劝,從而以分布式的方式進(jìn)行代碼遷移骗灶,如下圖:
五,多產(chǎn)品線的管理
使用同一個中心代碼庫管理多產(chǎn)品線一直是大型項目的一個困難點脱羡,特別是使用SVN這樣的工具更是難以管理,因為SVN這種工具的Branch本質(zhì)上是一個目錄拷貝帆竹,并且速度慢脓规,而且代碼回遷也需要手動進(jìn)行。但是如果使用Git的特性來管理多產(chǎn)品線抖拦,比起SVN是事半功倍。具體方案見下圖:
總結(jié):
分布式代碼版本管理系統(tǒng)并不一定適合所有團(tuán)隊噩茄,比如中小團(tuán)隊可能更關(guān)心的只是成本更低复颈,簡單易用,那么SVN等這類集中式版本管理工具還是更為適合凿菩。但是不管團(tuán)隊最終選用什么代碼版本管理工具帜讲,只要適合自己的團(tuán)隊的開發(fā)流程和工作方式似将,并且代碼管理順暢就可以了。