作者:Dirkjan Ochtman
譯者:謝路云
狀態(tài):完成
原文鏈接:http://www.aosabook.org/en/mercurial.html
Mercurial是一個(gè)現(xiàn)代分布式版本控制系統(tǒng)(VCS),主要由Python語言編寫,以及一小部分C代碼,以提高性能。在本章中,我會(huì)討論Mercurial設(shè)計(jì)上的一些關(guān)于算法和數(shù)據(jù)結(jié)構(gòu)的決策。首先,請?jiān)试S我簡短的回顧一下版本控制系統(tǒng)的歷史,介紹一些必要的背景知識。
12.1.版本控制簡史
雖然這一章的主要內(nèi)容關(guān)于Mercurial的體系結(jié)構(gòu),但其中的許多思想和其他版本控制系統(tǒng)是共通的。為了更好的討論,我想先說明一些存在于不同版本控制系統(tǒng)中的概念和行為。為了恰當(dāng)?shù)恼f明這一切,我還將簡單的介紹一下這個(gè)領(lǐng)域的歷史。
版本控制系統(tǒng)的發(fā)明是為了幫助軟件系統(tǒng)的開發(fā)人員并行的工作,而不必相互傳遞文件的拷貝并人工的記錄文件的修改歷史。我們可以將軟件的源代碼文件擴(kuò)展到任意文件樹。版本控制的主要功能之一就是傳遞樹的變化。工作流程的基本循環(huán)是這樣的:
第一個(gè)動(dòng)作,也就是獲取一份本地的文件樹,被稱為“檢出”(checkout)。我們獲取和發(fā)布所有修改的地方叫做“版本庫”(repository),而檢出得到的目錄則被稱為“工作目錄”、“工作樹”或是“工作拷貝”。用版本庫中的最新文件更新工作拷貝的動(dòng)作就叫做“更新”(update)。有時(shí)候這還會(huì)涉及到“合并”(merge),也就是組合不同用戶對同一個(gè)文件作出的修改。diff命令使我們能夠查看樹或文件在兩個(gè)版本之間的變化,它最常見的用途是檢查你的工作目錄中的本地(未發(fā)布的)修改。修改的發(fā)布是通過一個(gè)“提交”(commit)命令完成的,它會(huì)將工作目錄的改變保存到版本庫中去。
12.1.1.集中式版本控制
史上第一個(gè)版本控制系統(tǒng)叫做“源代碼控制系統(tǒng)”(Source Code Control System, SCCS),出現(xiàn)于1975年。它的主要功能是將差異保存在文件中,這比保存一個(gè)文件的多個(gè)版本的完整拷貝更經(jīng)濟(jì),但它無法將這些差異傳播給其他人。它的繼任是1982年出現(xiàn)的“修訂控制系統(tǒng)”(Revsion Control System, RCS)。RCS是SCCS更加先進(jìn)并且免費(fèi)的替代品(它至今仍在GNU項(xiàng)目的維護(hù)之下)。
RCS之后是“并行版本系統(tǒng)”(Concurrent Versioning System, CVS),發(fā)布于1986年。它最初是一組批量處理RCS修訂文件的腳本。CVS最大的創(chuàng)新是實(shí)現(xiàn)了多個(gè)用戶同時(shí)編輯相同的文件并在最后合并所有的修改(并行編輯)的模式。這也產(chǎn)生了“編輯沖突”的概念。開發(fā)者提交的新版本文件必須基于版本庫的最新版本之上。如果版本庫和我的工作目錄都對文件作出了修改,那么我必須解決這些修改所產(chǎn)生的所有沖突(修改了同一行的情況)。
CVS也開創(chuàng)了“分支”(branch)以及“標(biāo)簽”(tag)的概念。分支使得開發(fā)者能夠并行的工作在不同的任務(wù)之上,標(biāo)簽則可以用來標(biāo)記版本庫的一個(gè)快照以便引用。雖然CVS一開始是通過將版本庫放在共享文件系統(tǒng)上來傳遞差異的,但隨后CVS實(shí)現(xiàn)了C/S架構(gòu)以適應(yīng)大型網(wǎng)絡(luò)中的應(yīng)用(例如因特網(wǎng))。
在2000年,三位開發(fā)者為了糾正CVS中的設(shè)計(jì)缺陷一同完成了一個(gè)新的版本控制系統(tǒng),叫做Subversion。Subversion最主要的特點(diǎn)將工作樹作為一個(gè)整體對待。也就是說,每個(gè)修訂所作出的變更都應(yīng)該具有原子性、一致性、隔離性和持久性。Subversion能夠在工作目錄中記錄工作拷貝的檢出版本,這樣常用的diff操作(比較本地的工作樹和檢出的版本)就能更快的在本地進(jìn)行。
Subversion的一個(gè)有趣的概念是標(biāo)簽和分支都是項(xiàng)目樹的一部分。一個(gè)Subversion項(xiàng)目通常分為三個(gè)部分:tags
、branches
、trunk
。事實(shí)證明這種設(shè)計(jì)對于不熟悉版本控制系統(tǒng)的用戶非常直觀,盡管這種設(shè)計(jì)的天然靈活性也為各種版本庫轉(zhuǎn)換工具帶來了大量問題,大部分是因?yàn)樵谄渌姹究刂葡到y(tǒng)中,tags
和branches
有更加結(jié)構(gòu)化的表示方法。
以上提到的都是“集中式”的版本控制系統(tǒng)。也就是說,盡管它們知道如何交換變更(從CVS開始),但是它們?nèi)匀灰蕾囉诹硗庖慌_(tái)計(jì)算機(jī)來記錄版本庫的歷史。而“分布式”的版本控制系統(tǒng)則會(huì)在存在工作拷貝的每臺(tái)計(jì)算機(jī)上都保存版本庫的完整或是部分歷史。
12.1.2.分布式版本控制
盡管Subversion相比CVS有了明顯的進(jìn)步,但它仍有許多缺點(diǎn)。首先,在所有的集中式版本控制系統(tǒng)中,由于版本庫的歷史集中在同一個(gè)地方,變更集的提交和發(fā)布實(shí)際上是一回事,這也意味著在沒有網(wǎng)絡(luò)的情況下是無法提交變更的。其次,在集中式版本控制系統(tǒng)中,訪問版本庫總是需要一次或者多次的網(wǎng)絡(luò)請求,比分布式版本控制系統(tǒng)中的本地訪問要慢的多。再次,以上提到的所有版本控制系統(tǒng)都不擅長于記錄合并(隨著系統(tǒng)的改進(jìn),有些能夠支持)。在有許多人并行工作的大型團(tuán)隊(duì)之中,版本控制系統(tǒng)必須能夠記錄每個(gè)新的修訂版本都包含了哪些變更,這樣才能保證不丟失任何工作,并且后續(xù)的合并也能使用這些信息。第四,傳統(tǒng)版本控制系統(tǒng)的集中特性有時(shí)非常別扭,它強(qiáng)迫你只能在一個(gè)地方進(jìn)行集成。分布式版本控制的提倡者認(rèn)為,使用分布式系統(tǒng)的團(tuán)隊(duì)的組織更加自然,開發(fā)者們能夠根據(jù)項(xiàng)目的需要在任何推送和集成變更。
為了滿足這些需求,已經(jīng)出現(xiàn)了許多新的工具。我(從開源世界的角度)認(rèn)為,2011年中最重要的三個(gè)當(dāng)屬Git、Mercurial和Bazaar。Git和Mercurial都始于2005年,當(dāng)時(shí)Linux內(nèi)核的開發(fā)者們決定不再繼續(xù)使用專有系統(tǒng)BitKeeper。兩者都是由Linux內(nèi)核開發(fā)者發(fā)起的(分別是Linus Torvalds和Matt Mackall),以滿足對能夠處理上萬文件的成百上千個(gè)變更集進(jìn)行管理的版本控制系統(tǒng)的需求。Matt和Linus都深受另一個(gè)版本控制系統(tǒng)Monotone的影響。同一時(shí)期的Bazaar的開發(fā)則相對獨(dú)立,但在被Canonical采納為所有項(xiàng)目的版本控制系統(tǒng)之后也得到了很廣泛的使用。
構(gòu)建一個(gè)分布式的版本控制系統(tǒng)顯然會(huì)遇到許多挑戰(zhàn),其中一部分是所有分布式系統(tǒng)所固有的。例如,在集中式系統(tǒng)中源代碼控制服務(wù)器總是保存著一份統(tǒng)一的版本歷史,但在分布式系統(tǒng)中是不存在統(tǒng)一的版本歷史的。分布式系統(tǒng)允許并行的提交變更,這使得在任何版本庫中按照時(shí)間將修訂歷史排序都是不可能的。
幾乎所有的系統(tǒng)都采用了有向無環(huán)圖(DAG)而非線性的變更集方式組織來解決這個(gè)問題( 圖12.1 )。也就是說,新提交的變更是其基礎(chǔ)版本的子版本,且不可能有任何版本的基礎(chǔ)是自己或是自己的子嗣。在這個(gè)方案中,我們有三種特殊類型的修訂版本: 沒有父版本的“根版本”(root revision),一個(gè)版本庫可以有多個(gè)根版本),有一個(gè)以上父版本的“合并版本”(merge revision),和沒有子版本“頭版本”(head revision)。每個(gè)版本庫都是從一個(gè)空的根版本開始不斷產(chǎn)生一系列變更集,最后得到一個(gè)或者多個(gè)頭版本。當(dāng)兩個(gè)用戶分別獨(dú)立的提交了變更且其中一個(gè)人希望從另一個(gè)人那里拉?。╬ull)變更集時(shí),他必須明確的將另一個(gè)人的變更合并從而得到一個(gè)新的版本,這個(gè)版本的提交將得到一個(gè)合并版本。
更多建議: