Subversion與CVS的對比

Subversion 是什麼?

Subversion是一個自由/開源版本控制系統,它管理文件和目錄可以超越時間。一組文件存放在中心版本庫,這個版本庫很像一個普通的文件服務器,只是它可以記錄每一次文件和目錄的修改,這便使你可以取得數據以前的版本,從而可以檢查所作的更改。從這個方面看,許多人把版本控制系統當作一種“時間機器”。

Subversion可以通過網絡訪問它的版本庫,從而使用戶可以在不同的電腦上使用。一定程度上可以說,允許用戶在各自的地方修改同一份數據是促進協作。由於所有的工作都有歷史版本,你不必擔心由於失去某個通道而影響質量,如果存在不正確的改變,只要取消改變。

Subversion 的歷史

早在2000年,CollabNet, Inc.(http://www.collab.net)開始尋找CVS替代產品的開發人員,CollabNet提供了一個協作軟件套件CEE(CollabNet Enterprise Edition),它的一個組件是版本控制系統。儘管CEE在初始時使用CVS作爲其版本控制系統,但是CVS的侷限性在一開始就很明顯,CollabNet知道遲早要找到一個更好的替代品。遺憾的是,CVS成爲了開源世界事實上的標準,因爲沒有更好的產品,至少是沒有可以自由使用的。所以CollabNet決定寫一個新的版本控制系統,建立在CVS思想之上的,但是修正其錯誤和不合理的特性。

2000年2月,他們聯繫Open Source Development with CVS(Coriolis, 1999)的作者Karl Fogel,並且詢問他是否希望爲這個新項目工作,巧合的是,當時Karl正在與朋友Jim Blandy討論設計一個新的版本控制系統。在1995年,他們兩個曾經開辦一個提供CVS支持的公司Cyclic Software,儘管他們最終賣掉了公司,但還是天天使用CVS進行日常工作,在使用CVS時的挫折最終促使他們認真地去考慮如何管理標記版本的數據,而且他們當時不僅僅提出了“Subversion”這個名字,並且做出了Subversion版本庫的基礎設計。所以當CollabNet提出邀請的時候,Karl馬上同意爲這個項目工作,同時Jim也得到了他的僱主,RedHat軟件贊助他到這個項目並提供了一個寬鬆的時間。CollabNet僱傭了Karl和Ben Collins Sussman,詳細的設計從三月開始,在Behlendorf、CollabNet、Jason Robbins和Greg Stein(當時是一個獨立開發者,活躍在WebDAV/DeltaV 系統規範階段)的恰當激勵的幫助下,Subversion很快吸引了許多活躍的開發者,結果是許多有CVS經驗的人們很樂於有機會爲這個項目做些事情。

最初的設計小組固定在簡單的目標上,他們不想在版本控制方法學中開墾處女地,他們只是希望修正CVS,他們決定Subversion匹配CVS的特性,保留相同的開發模型,但不復制CVS明顯的缺陷。儘管它不需要成爲CVS的繼任者,它也應該與CVS保持足夠的相似性,使得CVS用戶可以輕鬆的做出轉換。

經過14個月的編碼,2001年8月31日,Subversion自己能夠“成爲服務”了,開發者停止使用CVS保存Subversion的代碼,而使用Subversion本身。

當CollabNet開始這個項目的時候,曾經資助了大量的工作(它爲全職的Subversion開發者提供薪水),Subversion像許多開源項目一樣,被一些激勵知識界精英的寬鬆透明的規則支配着。CollabNet的版權許可證完全符合Debian的自由軟件方針,也就是說,任何人可以自由的下載,修改和重新發布,不需要經過CollabNet或其他人的允許。

功能性對比

一、Subversion包含絕大部分CVS功能

Subversion 作爲CVS 的重寫版和改進版,其目標就是作爲一個更好的版本控制軟件,取代目前流行的CVS。Subversion的主要開發人員都是業界知名的CVS專家。Subversion支持絕大部分的CVS功能/命令;Subversion的命令風格和界面也與CVS非常接近。當然,不同的地方正是對CVS的改進。

二、全局性的版本編號

一個新的版本,並得到一個自增量的版本號N+1,該版本號並不針對某個特定的文件,而是全局性的、針對整個版本庫的。因此,我們可以將Subversion的版本庫看作是一個文件系統或文件目錄樹的數組。

從技術的角度來說,在Subversion中,“文件foo.c的第5版本”這個說法是錯誤的;正確的說法應該是“文件foo.c在版本庫被修改了5次,即執行5次commit後是什麼樣子?”。顯然,在Subversion中,版本庫被修改5次後foo.c的內容,和被修改了6次後foo.c的內容很可能完全一樣,因爲版本庫的第6次修改很可能只修改了版本庫的其他部分,而並沒有對foo.c的進行修改。相反,在CVS中,文件foo.c的第1.1版本和第1.2版本總是不同的。

Subversion的全局性版本編號爲Subversion帶來了諸多的優勢:如對目錄或文件執行拷貝,無論涉及多少文件,Subversion不需要對單個文件依次執行拷貝命令,僅僅需要建立一個指向相應的全局版本號的一個指針即可。

三、目錄的版本控制

CVS只能對文件進行版本控制,不能對目錄進行版本控制,因此CVS沒有任何關於文件“移動”(move)操作的概念。當人爲進行文件移動操作時,CVS只能注意到,一個文件在一個位置被刪除了,而在一個新位置創建了另外一個文件。由於它不會連接兩個操作,因此也很容易使文件歷史軌跡丟失。設置CVS存儲庫時,必須非常謹慎地爲每個文件選擇準確的位置,因爲在設置之後,幾乎就要一直使用這個位置了。

同樣由於CVS不記錄目錄的版本歷史,CVS不支持對文件的“重命名”(rename),人爲的對文件進行重命名會使得命名前後的文件失去歷史聯繫,而記錄歷史本來是版本管理的主要目的。

還有,CVS不支持對文件的“拷貝”(copy),人爲的拷貝對CVS而言,只能看到新的文件的增加,而不能記錄拷貝源文件和目標文件之間的聯繫。

綜上所述,缺乏對文件“移動”、“重命名”、“拷貝”的支持的根源在於CVS不能記錄目錄的版本歷史,而這些操作在當前的軟件開發過程中經常發生,這正是Subversion被開發並取代CVS的主要原因之一。

Subversion將目錄作爲一類特殊的文件來處理(事實上,從文件系統的角度來看,目錄確實是一類特殊的文件,當目錄中的子目錄/文件被刪除、重命名、或新的子目錄/文件被創建時,目錄的內容將發生改變)。因此,Subversion象記錄普通文件的修改歷史一樣記錄對目錄的修改歷史,當發生文件/目錄的移動、重命名或拷貝操作時,Subversion能夠準確記錄操作前後的歷史聯繫。同樣,象對文件的不同歷史版本進行比較一樣,Subversion支持對目錄的不同歷史版本的比較,清晰展現目錄的變化歷史。

四、原子性提交

從使用者的角度來看,CVS和Subversion都支持對多個文件修改的批量提交,但二者在實現方式上存在本質的區別。

CVS採用線性、串行的批量提交,即依次地,一個接一個地執行提交,每成功提交一個文件,該文件的一個新的版本即被記錄到版本庫中,提交時用戶提供的日誌信息被重複地存儲到每一個被修改的文件的版本歷史中。

CVS串行批量提交模式的弊端在於——當任何原因造成批量操作的中斷時(典型原因包括:網絡中斷、客戶端死機等),版本庫往往處於一個不一致的狀態:原本應該全部入庫的文件只有一部分入庫,很有可能版本庫中的最新版本不能順利編譯,更爲嚴重的是,隨着其他的用戶執行cvs update操作,該不一致性將迅速在開發團隊中擴散,從而嚴重影響團隊的開發效率,並存在質量隱患。另外,假如該批量提交的中斷沒有被及時發現,開發團隊往往要花更多的時間進行軟件調試和排錯。

CVS即使在批量提交不發生中斷時也會造成不一致:假設用戶A啓動一個需要較長時間才能完成的批量提交;與此同時,用戶B執行cvs update操作。此時,用戶B很有可能得到一個不一致的更新,即用戶B通過“更新”操作,得到用戶A的部分修改文件。

Subversion徹底消除了CVS的以上弊端。無論批量提交包含多少文件修改,只有當全部文件修改都成功入庫,該提交才變得有效,纔對其他用戶可見;否則,無論任何原因造成中斷,Subversion都會自動執行“回滾”(rollback)操作。換一個說法,Subversion保證所有的修改要麼全部入庫生效,要麼一個也不入庫,即對版本庫不作任何的修改。這就是Subversion的原子性提交(atomic commit)。

由於Subversion的原子性提交特性和全局版本編號方式,當提交成功完成時,一個唯一的、新的全局版本編號產生,而提交時用戶提供的日誌信息與該新的版本編號關聯,只進行一次存儲(區別於CVS的按文件重複存儲)。

五、支持變更集概念

由於Subversion的所有提交是原子性的,每次成功提交形成的唯一的全局版本號對應此次批量提交的所有文件修改,也就是說,一個Subversion版本號其實對應了一個邏輯上的變更集(change set),該變更集可能對應於對一個BUG的修復,或者對應於對一個已有功能的改進,或者對應於一個新功能的實現。可以說,變更集是一個軟件開發活動的邏輯結果,該變更集可以通過其對應的版本號在軟件開發的其他過程中(如軟件合併/集成過程,軟件發佈管理,變更管理系統,缺陷追蹤系統)被引用。因此,Subversion將版本管理從單純的、單個的文件修改的層次通過邏輯上的抽象,上升到更便於理解和交流的開發活動的層次。

六、差異化的二進制文件處理

由於歷史原因,CVS主要是爲早期的程序員設計的,CVS能夠有效處理文本文件(或ASCII文件,源代碼文件),可以對文本文件進行差異化的存儲、新舊版本的比較,文件合併等;但對於二進制文件,CVS則明顯力不從心。在CVS的版本庫中,對於二進制文件的歷史版本,CVS唯一能做的就是對不同的版本進行獨立的、冗餘的存儲,哪怕版本之間其實只存在微小的差異。舉例而言,一個10M的二進制文件(照片、圖形文件、機械設計文件、電子設計文件)假如每週修改一次,無論每次修改的大小,一年下來,僅該文件就要消耗500M以上的存儲空間。而且,客戶端每次獲取該文件的新版本都要消耗10M的網絡流量。

對於目前的開發團隊,無論是軟件開發,Web站點的開發,手機等電子產品的研發,需要進行版本管理的不僅是源代碼等文本文件,還需要管理需求文檔、設計文檔、測試文檔、用戶手冊,圖形圖像文件,機械/電子設計文件等諸多的二進制文件,CVS顯然不是一個好的選擇。

與CVS不同,Subversion採用統一的二進制差異算法(binary differencing algorithm),即對文本文件和二進制文件採用相同的差異比較算法,並以相同的方式在版本庫中進行存儲:每次提交後版本庫中只存儲相對於先前版本的差異,從而可以節省大量的存儲空間。

該二進制差異算法不僅應用在版本的存儲上,更爲重要的是,Subversion對二進制文件與文本文件一視同仁,當客戶端需要獲取新的版本時(如執行svn update),在網絡上只有版本的差異被傳輸,從而大大減少對網絡帶寬的消耗。更多細節參見“七、雙向的差異化-壓縮網絡傳輸”。

七、雙向的差異化-壓縮網絡傳輸

如上所述,CVS對二進制文件不能進行有效的差異化處理。對於文本文件,CVS僅僅支持單向的差異化傳輸:從CVS服務器到客戶端的傳輸是差異化的,即執行cvs update時,只有差異的部分從服務器傳輸到客戶端;而當執行cvs commit時,無論代碼變化多少,CVS都需要從客戶端向服務器完整傳輸被修改文件的全部內容,不能只傳輸差異。

相反,無論是文本文件還是二進制文件,Subversion都進行雙向的差異化傳輸,並且差異化內容還要進行壓縮/解壓縮的過程:在服務器端獲取差異顯而易見,與CVS類似;Subversion在客戶端獲取差異的祕密在於——Subversion在客戶端的工作拷貝中隱含了每個文件的一個“只讀的、乾淨的”副本(該副本隱藏在隱含目錄.svn裏,通常不可見,該副本還有更多的妙用,參見“十二、更多的本地/離線操作”),通過比較用戶在客戶端的修改和該隱含的副本,Subversion獲取需要真正傳送到服務器的差異,並對差異進行壓縮後才進行網絡傳輸。

對CVS而言,操作的成本(網絡帶寬消耗是最大的操作成本)與被修改的文件的大小成比例,而與修改本身的大小無關;對Subversion而言,操作成本只與修改本身的大小成比例,而與被修改的文件的大小無關。因此,與CVS相比,Subversion消耗更少的網絡帶寬(以客戶端的存儲空間換取更少的帶寬消耗在目前的計算環境下應該是個相當不錯的選擇!)。Subversion更加適合基於互聯網(或廣域網)進行協作開發的地理上分佈的團隊——版本服務器集中、單一;客戶端廣泛分佈。

八、高效、快捷創建分支和基線

CVS和Subversion都支持分支(branch)和基線(tag),通過分支與合併,可以有效支持大項目的並行開發模式;通過基線管理,可以準確標識一組文件的版本,有效進行軟件發佈管理和必要時的歷史回溯。

但CVS和Subversion在實現分支和基線的方式上存在很大的不同。CVS在創建分支的時候,需要對所有進行分支的文件進行依次的操作,因此分支的建立成本(主要是建立分支所需的時間,或消耗的計算資源)與參與分支的文件數量成比例,項目越大,版本庫越大,文件越多,分支的建立成本越高;基線(tag)的建立與此類似。

Subversion的分支和基線是通過執行“拷貝”來建立的:回想一下在沒有引入版本管理工具的時候我們是如何進行所謂的“分支”和“基線”管理的?答案顯然是“拷貝”——我們通過“拷貝”或“備份”來建立基線;同樣,爲支持多個開發人員可以同時進行開發,我們爲每個開發人員創建一份“拷貝”。由此看來,Subversion通過“拷貝”來建立分支和基線顯得非常自然,有點“返樸歸真”的意思。

由於Subversion的全局版本號特性,Subversion中分支或基線的創建過程,或Subversion中的“拷貝”過程,真正的操作是在版本庫中創建一個到某一全局版本號的指針(pointer),不再需要針對衆多的單個文件依次執行操作。因此,該操作的成本爲一個很小的常數,與項目大小,版本庫大小,文件數目的多少無關;並且,分支或基線的建立不需要進行版本的冗餘存儲,新建立的分支或基線基本不佔用版本庫空間,分支的後續存儲空間的開銷也只與修改的大小有關。

九、集成Apache Web Server,提供更多的特性

Subversion通過與Apache Web Server的集成,可以提供基於http/https協議的版本庫訪問機制,從而支持Subversion跨越防火牆的安全訪問。除此以外,Subversion還可以利用更多的Apache特性,包括但不限於:Apache豐富的用戶認證機制(包括通過LDAP服務器如Windows Active Directory服務器的用戶認證),基於目錄路徑的精細粒度的訪問控制,對傳輸的網絡流量進行壓縮/解壓縮,瀏覽版本庫目錄結構等等。

十、支持WebDAV

WebDAV(Web-based Distributed Authoring and Versioning)是一種基於HTTP 1.1協議的通信協議.它擴展了HTTP 1.1,在GET、POST、HEAD等幾個HTTP標準方法以外添加了一些新的方法,使應用程序可直接對Web Server直接讀寫,並支持寫文件鎖定(Locking)及解鎖(Unlock),還可以支持文件的版本控制。

Microsoft windows2000/XP及IE,Office還有Adobe/MicroMedia的DreamWeaver等都支持WebDAV,這又大大增強了Web應用的價值,以及效能。對於需要大量發佈內容的用戶而言,應用WebDAV可以降低對CMS系統的依賴,而且能夠更自由的進行創作。上傳、下載變得輕鬆自如。

Subversion通過與Apache Web Server的集成,支持WebDAV協議,使得業務用戶(business users)或非技術用戶在不安裝任何版本管理客戶端的情況下輕鬆訪問Subversion版本庫,不改變業務用戶已有使用習慣,支持分佈的業務用戶對文檔的評審、修改並實現版本控制,真正將軟件開發的生命週期從開發/技術團隊擴展到項目的全部干係人(stakeholder),避免通過電子郵件傳遞文檔的混亂與無序、通過Windows操作系統共享造成的安全漏洞、病毒攻擊、歷史版本被覆蓋或丟失、審計困難等諸多典型問題。

十一、更好的衝突標識與處理

CVS和Subversion都支持通過分支與合併進行並行開發,並可以自動檢測到合併時的衝突(conflicts),並在合併結果中以<<<<<< …>>>>>>標識合併的衝突部分。

在CVS中,經常會出現由於用戶的疏忽(如,沒有注意到衝突,或沒有完全處理好衝突)而將仍然帶有<<<<<< …>>>>>>衝突標識符號的文件直接進行提交(commit),從而在版本庫中產生垃圾版本。

Subversion有效解決了CVS的以上問題:Subversion記錄並保持文件的衝突狀態,只有當用戶明確執行svn resolved命令後,該衝突狀態標識才被複位,該文件才能被提交,從而大大減少了將仍然帶有<<<<<< …>>>>>>衝突標識符號的文件直接進行提交的可能性。

十二、更多的本地/離線操作

衆所周知,CVS客戶端的工作拷貝中包含了一個隱含目錄CVS,該目錄中記錄了客戶端需要的一些管理信息;與此類似,Subversion的客戶端工作拷貝中也包含了一個隱含目錄.svn,該目錄中同樣記錄了客戶端需要的一些管理信息,如版本庫URL,當前訪問版本號等。

與CVS不同的是,Subversion的.svn目錄中還包含了工作拷貝中每一個文件的一個“只讀的、乾淨的”副本。正是由於該副本的存在,使得Subversion與CVS相比,可以執行更多的本地/離線操作,即某些操作不需要訪問版本庫服務器,因此不需要存在從客戶端到服務器的網絡鏈接,當然也不消耗任何網絡帶寬,這進一步增強了Subversion對廣域網的友好支持。

Subversion的以下命令可以進行離線操作:
svn status - 顯示工作拷貝上的本地修改概況;
svn diff -顯示工作拷貝上的本地修改細節,比較修改前後的內容;
svn revert - 撤銷工作拷貝上的本地修改;

十三、對符號鏈接進行版本管理

在Unix文件系統中,符號鏈接(symbolic links,包括硬鏈接和軟鏈接)是一種重要的文件系統元素。CVS不能對符號鏈接進行版本管理;Subversion則可以對符號鏈接進行版本管理。

十四、元數據管理

與CVS相比,Subversion增加了元數據(metadata)管理機制。即可以對版本庫中的文件或目錄附加任意的“屬性”(property),並記錄屬性的變化歷史,也就是對元數據進行版本管理。一個Subversion屬性是一個“屬性名稱/屬性值”的二元組,如“BugNumber=100”就是一個屬性,可以將該屬性附加到版本N上,以說明版本N改正了編號爲100的BUG。

Subversion元數據的目的是提供附件的信息以滿足流程或過程自動化的需要,以增強Subversion的管理能力和自動化程度。Subversion自身就通過“屬性”來存儲一些特殊的信息。一個使用Subversion元數據的例子:可以在一些批處理的腳本程序或Subversion的鉤子程序(hooks)中創建、訪問、修改“屬性”元數據來滿足流程自動化的要求。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章