![]() ![]() ![]() ![]() |
||
svk 分散式版本控制之道原載於 Perl.com http://www.perl.com/pub/a/2004/03/03/svk.html svk 分散式版本控制之道 高嘉良著 謝良奇譯 接觸 Subversion 整整一年,那優雅的檔案系統設計深得我心。我很快地沒辦法回頭用 CVS。這意味著,每逢用 CVS 開發專案,我就渾身不對勁。我想要可以讓 Subversion 儲庫(repository)與 CVS 儲庫同步化的工具。那不止會節省我把專案快照(snapshots)匯入廠商分支(branches)的時間,我連不上網路時,也可以透過它,看到完整的專案歷程。 我幫 Barrie 的 VCP 寫了個 Subversion 的驅動軟體,接著便親身體會到 Subversion 廣受批評的緩慢。我的驅動軟體呼叫 svn 指令,然後花了約 30 小時,把 CVS 儲庫轉成 Subversion 儲庫中的 3000 個修訂版本(revisions)。 幸運的是,Subversion 的開發人員寫出了易懂、又容易用 SWIG 包在不同語言中的程式碼。不過當時只實作出 Python 版本,所以我得自己動手搞定 Perl 的。隨著 Perl 繫結版本(bindings)完成,VCP 跑得像快馬加鞭似的,我也開始投入 SVN::Mirror 開發。這是個可在 Subversion 儲庫間映像(mirroring)的模組。無聊之餘,我順手弄了 Bloxsom 和 Kwiki 等工具的 Subversion 後端支援。 又是旅人的季節。一旦脫離網際網路,我的生產力和創造力高得嚇人,一個分散式版本控制系統的構想在我心裡浮現。我決定花一年時間開發一套工具,一套可以讓我生產力更高的工具。svk 於是在我 2003 年 9 月生日後,誕生。 Why? 分散式版本控制系統選擇不少:Arch、monotone、darcs。功能則大同小異。 而,svk,是用 Perl 打造,這表示它可以滿足更多人的黑客慾。svk 也有一堆類似 cvs 的指令。我計畫在 svk 上頭弄出跨版本控制系統的通透性替補功能(transparent interpolation)。 既然我沒有一定得用某套系統的理由,就讓你自己做選擇吧。 設計決策 Subversion 的分層設計: fs:採用 bdb 的底層版本樹狀結構程式庫(versioned tree library) repos:fs 的上層支援,如 log 訊息。 ra:儲庫存取。抽象協定處理器(handlers)。 wc:工作底本(Working)複製處理。 client:實現客戶端指令。 首先我決定丟掉 wc 和 ra 層。Subversion 的設計理念是:“易得大磁碟,難有高頻寬”,我們當在本地端留下各修訂版本的複本 ── 而SVN::Mirror 早已為此待命出發。 一旦在本地端儲庫留有完整複本,浮腫的 wc 實作對我們形同廢物。wc 程式庫的 .svn 抽象目錄不止會擾亂 diff、grep 等常用工具,它儲存的 text-base 更會讓你的 checkout 大小大上兩倍。於是我做了輕量級的checkout 複本維護工具 XD (wc 的字符加強版)。 接著,我發覺上述皆非 Subversion 的最重要元件。定義描述 tree delta 的 delta 程式庫才是重點;它才是樹狀版本控制系統的核心。它叫作“Delta Editor”。 打個比方。在修訂 1 版跟 3 版間跑 delta,會對指定的 editor 物件,進行一連串方法呼叫(add_directory、open_file、apply_textdelta、close_file、close_directory 等等)。這些方法呼叫描述了版本 1 到版本 3 之間的更動。 在 2 個月開發期內,svk 開始試運作,我試著依此一界面重構現有程式碼。Perl 給了我輕易堆積 editor 的能力,讓每個 editor 自行其事,我也加入一些回呼函式做為 API 的延伸部份,當然還有其它你想得到的 Perl 技法。大部份功能都加以抽象化,結果成了下列 svk 的核心元件: * 接收 delta 呼叫,以修改 checkout 複本的 editor。 * 可產生描述 checkout 複本修改完成之 delta 呼叫的函式。 * 可接下多個 delta 呼叫的 editor,並將其合併為樹狀結構以便產生無衝突的一連串呼叫。 萬事齊備,大多數指令背後,就只是如何將 delta 產生器與適當 editor 接合起來的問題。 此外,藉由 Perl 彈性的 PerlIO 分層系統,我一小時內就搞定了關鍵字擴充(像 cvs 裡的 $Id$)。其中的可重用部份抽象化後成為 CPAN 上的 PerlIO::via::dynamic 模組。 我們來看看 svk 怎麼用。 第一眼 我很討厭 Subversion 得打一些長得要命的 URLs。有必要把儲庫對應到較短的名字: $ svk depotmap 這一來會在 ~/.svk/local 產生預設儲庫,之後你可以用 // 來指稱它。假如你在磁碟上有個 Subversion 儲庫,可以加上另一行:test: '/path/to/repos'。你便可直接存取現有的儲庫 ── 只能用 /test/ 而非 file:///long-path-plus-auto-complete-wont-work。 現在放點東西進入: $ svk import //project/vendor /path/to/project-0.01 以上和你想的一樣:把東西匯入 //project/vendor。以新版專案,假設是 0.02 好了,重覆該指令,你會得到該路徑上的一個廠商分支。 和 Subversion 一樣,分支、tags 可以看成簡單的檔案系統複本: $ svk cp -m 'development trunk for project' //project/vendor //project/trunk 我們把它調出來: $ svk checkout //project/trunk ~/work/project 假如你用過 cvs 或 Subversion,你會發現新增、修改、刪除或提交(commit)檔案的方式很眼熟。svk log 會產生檔案、目錄的更動歷程。 假設你分支出 trunk 之後,匯入了 project-0.02,並希望將廠商分支合併進來。只要: $ svk smerge //project/vendor //project/trunk svk 會記憶分支及合併歷程,所以你勿須擔心。如果有衝突產生,用 ~/project/trunk 這類的 checkout 路徑取代 //project/trunk。你會看到這些衝突。解決後重新提交檔案。合併應該會順利進行。 合併後,你可以用 svk update,讓 trunk 的 checkout 複本,成為最新修訂版本。 >> : Page 2 >>> |
|
|