劉悅之
同濟(jì)大學(xué),上海 201804
現(xiàn)在的軟件項(xiàng)目開發(fā)中,必然涉及版本控制。
版本控制的功能在于跟蹤記錄整個(gè)軟件的開發(fā)過程,包括軟件本身和相關(guān)文檔。在空間上可以保證完成集中統(tǒng)一管理,解決一致性和冗余問題。在時(shí)間上全程跟蹤記錄工具將會自動記錄開發(fā)過程中的每個(gè)更改細(xì)節(jié),和不同時(shí)期的不同版本,以便對不同階段的軟件及相關(guān)文檔進(jìn)行表示并進(jìn)行差別分析,對軟件代碼進(jìn)行可撤消的修改,便于匯總不同開發(fā)人員所做的修改,輔助協(xié)調(diào)和管理軟件開發(fā)團(tuán)隊(duì)。
相對于其他流行的軟件版本開源管理軟件,Git的優(yōu)勢在哪里呢?
1.1.1 對網(wǎng)絡(luò)的依賴性更低
雖然現(xiàn)在網(wǎng)絡(luò)非常普及,但是并不是隨時(shí)隨地都有高速網(wǎng)絡(luò),低速的網(wǎng)絡(luò)會讓人心情煩躁,有時(shí)候就呆呆地盯著屏幕上的提交進(jìn)度,什么事情也干不了。而Git的絕大部分操作在本地完成,不用和集中的代碼管理服務(wù)器交互,只有最終完成的版本才需要向一個(gè)中心的集中的代碼管理服務(wù)器提交。
1.1.2 方便的原子提交跟蹤
Git的每次提交都會根據(jù)SHA-1算法生成唯一的commit id。而不像CVS那樣都是對單個(gè)文件分別進(jìn)行版本的更改。所以當(dāng)你跟蹤以前某次提交的代碼時(shí),不用考慮到底提交了哪些文件,所有的變動代碼會一次性的取出來。
1.1.3 更方便的分支合并操作
Git的分支管理相對CVS 等系統(tǒng)容易多了,無論是建立新的分支,還是在分支之間切換都一條命令完成,不需要建立多余的目錄。分支之間合并時(shí),不僅代碼會合并在一起,提交歷史也會保留,這點(diǎn)非常有助于分支的管理與追蹤。
對于一個(gè)大型項(xiàng)目而言,在項(xiàng)目管理的過程中,只依靠Git原有的功能來進(jìn)行版本控制管理是遠(yuǎn)遠(yuǎn)不夠的。Git無法滿足大型項(xiàng)目的管理要求。
1.2.1 對創(chuàng)建倉庫、分支等操作的管理權(quán)限分級
Git是分布式版本控制工具,任何人都可以將自己的本地創(chuàng)建的分支、標(biāo)簽等注入到中央代碼倉庫中,極大的提高了中央倉庫的維護(hù)成本。不利于大型項(xiàng)目的協(xié)同開發(fā)。
1.2.2 對多個(gè)倉庫進(jìn)行同步管理。
Git的每個(gè)倉庫都是獨(dú)立的,無法做到跟蹤軟件本身的同時(shí),對軟件相關(guān)文檔也進(jìn)行跟蹤,無法對不同階段的軟件及相關(guān)文檔進(jìn)行差別分析,不利于團(tuán)隊(duì)協(xié)作和管理。
1.2.3 保護(hù)中央代碼倉庫以防污染
在用戶從本地倉庫向中央倉庫提交代碼的過程中,Git只是做了純文本的合并,對代碼規(guī)范、質(zhì)量等不會做檢查,無法避免中央代碼倉庫受到污染。
1.2.4 并行開發(fā)代碼的提交沖突
并行開發(fā)帶來的又一大問題就是代碼提交沖突,Git需要手動解決沖突后再次提交,極大的降低了工作效率。
所以我們需要設(shè)計(jì)一個(gè)基于Git的分布式版本控制系統(tǒng)來彌補(bǔ)Git所存在的不足。
為了彌補(bǔ)Git的不足,本系統(tǒng)提出了一下方法來滿足大型項(xiàng)目版本控制的需求。
眾所周知,對于一個(gè)大型項(xiàng)目,由于需求的不確定性風(fēng)險(xiǎn)、決策層溝通障礙風(fēng)險(xiǎn)或者技術(shù)路線風(fēng)險(xiǎn)都會使得項(xiàng)目發(fā)布日期的不斷延遲并最終導(dǎo)致整個(gè)項(xiàng)目的失敗,為了避免這種情況,大型項(xiàng)目往往采用了迭代式的開發(fā)模型,當(dāng)開發(fā)到某一階段就會發(fā)布一個(gè)版本給用戶,然后根據(jù)用戶體驗(yàn),修改存在的問題或增加新的功能。
在大型項(xiàng)目的版本管理控制過程中,不僅需要管理項(xiàng)目源代碼倉庫,源代碼對應(yīng)的測試腳本倉庫、環(huán)境配置文件倉庫、與之相關(guān)的任何文件倉庫都應(yīng)該能被同時(shí)追蹤,以此來保證項(xiàng)目生命周期內(nèi)的任意時(shí)刻被追蹤時(shí),其相關(guān)的其他倉庫代碼也能被迅速定位。
為此,本系統(tǒng)提供了分支管理模塊來讓開發(fā)人員更好的管理各個(gè)發(fā)布版本并同步各代碼倉庫。
系統(tǒng)用主分支來維護(hù)團(tuán)隊(duì)內(nèi)部日常代碼開發(fā)的主線。每當(dāng)要發(fā)布新版本時(shí),系統(tǒng)管理員就可以選擇各個(gè)倉庫主分支上的某一次的原子提交,在這些原子提交上打上同一個(gè)標(biāo)簽,并在所有倉庫中新建分支。這樣,我們就可以根據(jù)標(biāo)簽同時(shí)追蹤所有的倉庫代碼。
對于新建的分支,它已經(jīng)包含主分支上直到所選擇的原子提交的所有代碼,當(dāng)團(tuán)隊(duì)成員向本次準(zhǔn)備發(fā)布的新版本提交特定的代碼時(shí),選擇此版本的分支,新代碼將只會提交到新分支上,而不會影響主分支上的代碼。
如果提交的代碼不僅僅需要用應(yīng)用在此新版本上,在其他以后的版本或者已存在的版本也需要使用,比如修復(fù)了項(xiàng)目的某些BUG,那么開發(fā)人員可以使用代碼合并模塊來合并此次提交到特定的一些分支上。
由于Git只是一個(gè)分布式的版本控制軟件,它并不對代碼質(zhì)量進(jìn)行審核,如何更有效的減少中央倉庫污染對大型項(xiàng)目至關(guān)重要。對于一個(gè)大型項(xiàng)目,開發(fā)團(tuán)隊(duì)人數(shù)往往由幾十人甚至幾百人組成,每個(gè)人每天都要向中央代碼庫提交多次代碼,在開發(fā)人員將代碼提交到中央代碼倉庫之前,檢查代碼是否符合規(guī)范、是否有潛在的質(zhì)量問題、避免互相影響造成額外的、非預(yù)期的錯(cuò)誤是本系統(tǒng)的又一大主要功能。
首先,代碼審核模塊為管理員提供了配置項(xiàng)目子系統(tǒng)的功能。管理員可以將項(xiàng)目代碼中不同目錄下的文件劃分不同的項(xiàng)目子系統(tǒng),也可以稱作模塊。并設(shè)置一個(gè)或多個(gè)子系統(tǒng)審核員,他們可以是項(xiàng)目模塊負(fù)責(zé)人、模塊設(shè)計(jì)者等等。當(dāng)開發(fā)人員提交了新代碼后,系統(tǒng)將解析新代碼對源代碼中哪些文件做了修改,并根據(jù)文件路徑辨識此次變動屬于哪些子系統(tǒng),然后,通知子系統(tǒng)審核員去審核新代碼。如果審核人員發(fā)現(xiàn)代碼存在問題,審核人員可以在系統(tǒng)中寫下批注,拒絕提交成功,并退回給開發(fā)人員以供修改。
如果提交的代碼通過了審核人員的審核,系統(tǒng)將把新代碼文件上傳至中央編譯服務(wù)器,在中央編譯服務(wù)器中,首先克隆一份最新的中央代碼倉庫的副本,將變動文件注入到副本中,如果在新代碼提交的過程中,有別的開發(fā)者對同樣的文件做了修改,并先一步提交到了中央代碼倉庫,那么此新代碼將會和中央代碼倉庫中的文件產(chǎn)生沖突,系統(tǒng)將把沖突信息返回給開發(fā)人員,要求他基于最新的代碼倉庫提交變動代碼。
當(dāng)新代碼通過了以上兩步檢驗(yàn)后,中央編譯服務(wù)器將對新代碼進(jìn)行編譯,以保證新的改動不會導(dǎo)致原程序編譯失敗。
本系統(tǒng)提供了一種名叫依賴補(bǔ)丁的選項(xiàng),來盡量避免代碼沖突產(chǎn)生,提高工作效。
當(dāng)開發(fā)人員A提交了代碼補(bǔ)丁文件后,系統(tǒng)會根據(jù)A的補(bǔ)丁文件記錄的所有修改文件的歷史記錄,通知其相關(guān)的開發(fā)人員,并把A的補(bǔ)丁文件上傳至服務(wù)器,此時(shí)B發(fā)現(xiàn)克隆到本地的最新中央代碼倉庫中不包含A的代碼,他可以通過本系統(tǒng)下載A的補(bǔ)丁文件,并將補(bǔ)丁文件加載到本地倉庫中,在此基礎(chǔ)上進(jìn)行開發(fā)。這樣就可以大量避免代碼沖突的產(chǎn)生。
但是,由于B的代碼是基于A的補(bǔ)丁,如果B的代碼被先審核,那么在補(bǔ)丁加載的過程中一定會失敗,因?yàn)榇藭r(shí)中央代碼倉庫中并不存在A的代碼。所以B提交代碼的時(shí)候必須選擇A的補(bǔ)丁作為依賴項(xiàng),在A的補(bǔ)丁沒有通過審核流程時(shí),B的補(bǔ)丁則不能被審核。以此來保證正確的審核順序。
隨著項(xiàng)目的開發(fā)周期越來越長,分支和提交也會越來越多,也就不可避免的出現(xiàn)代碼合并與分支合并。
根據(jù)本系統(tǒng)設(shè)計(jì)的理念,每個(gè)發(fā)布版本所對應(yīng)的分支都是相對獨(dú)立的,這樣盲目的的分支合并存在的風(fēng)險(xiǎn)遠(yuǎn)遠(yuǎn)大于某次特定代碼的合并。所以,我們通過實(shí)時(shí)的代碼合并,來取代風(fēng)險(xiǎn)較大的分支合并。
根據(jù)系統(tǒng)設(shè)計(jì),主分支是項(xiàng)目開發(fā)的主線,其他分支上的大部分的代碼提交,除了那些與發(fā)布版本特性有關(guān)的代碼,都應(yīng)該被合并到主分支上。為此,系統(tǒng)在開發(fā)人員提交代碼時(shí),系統(tǒng)會默認(rèn)當(dāng)前提交需要被合并到主分支,同時(shí)會提醒開發(fā)人員,如果他的當(dāng)前提交不需要合并到主分支,則應(yīng)該取消該選項(xiàng)。新代碼通過了子系統(tǒng)管理者的審核后,會在主分支和原目標(biāo)分支上分別作沖突檢查和編譯檢查。
正如我們前面提到過的,代碼倉庫中不僅有項(xiàng)目的核心代碼,也會有測試腳本、配置文件等其他文件。由于編譯檢查是串行工作的,如果讓腳本代碼、配置文件這些變動更頻繁的提交,每次合并都要對整個(gè)項(xiàng)目進(jìn)行編譯檢查的話,會大大影響核心代碼的提交效率,從而影響工作效率。所以本系統(tǒng)還提供了讓管理員手動合并代碼的功能。對于已經(jīng)提交的代碼,系統(tǒng)管理員可以將多次提交一次性地合并到多個(gè)分支上,這些合并只會做代碼沖突檢查,而不會做編譯檢查。
版本控制是大型軟件項(xiàng)目管理必不可少的一部分,版本控制系統(tǒng)的合理設(shè)計(jì)和使用,是提高開發(fā)效率,減少人為錯(cuò)誤的一大保證。本文通過分析Git的優(yōu)缺點(diǎn),給出了構(gòu)建合理可靠的版本控制系統(tǒng)的實(shí)現(xiàn)方案,并已應(yīng)用到一個(gè)具體的大型項(xiàng)目中。
[1][美]Jon Loeliger.Version Control with Git[M].東南大學(xué)出版,2010.
[2][美]Travis Swicegood.Pragmatic Version Control Using Git[M].電子工業(yè)出版社,2010.
[3][中]蔣鑫,Git權(quán)威指南[M],機(jī)械工業(yè)出版社,2011.