Contents
這篇DVCS(Distributed Version Control System)的文章, 深入淺出, 已徵得原文作者的同意, 在此將他的文章翻譯為中文.

傳統的版本控制輔助檔案的備份,追蹤與同步. 分散式的版本控制讓變更的分享簡單容易. 如果你做的對, 你可以魚與熊掌兼得: 簡單的合併同時並可以集中版本發佈.
要分散式的嗎? 一般的版本控制到底發生什麼問題?
沒有問題 — 如果你想快速回憶的話請參考VCS版本控制視覺指引 . 當然, 有些人可能會嘲笑你還在用”古老”的系統. 但在我看來仍然是OK的: 對於任何專案來說有用版本控制系統總是正向的一步.
集中的版本控制系統在1970年代出現, 當初程式設計者有了精簡型終端機(thin clients)但同時也羨慕又大又貴又快速的”big iron” mainframes(誰能不被當時風行的大小通吃8bits到1 byte的機器吸引呢?)
集中管理是簡單的概念, 很自然是第一步想到的:讓每個人到同一個地方簽入簽出, 就像集中到某個圖書館的書本上註記一樣.
如此的做法對於備份,復原和同步行得通, 不過對變更的合併與分支卻不太行. 當專案成長時, 通常會想將功能切割, 獨立開發與測試, 再逐步將變更併入主開發線. 實際做時, 分支就很麻煩, 新的功能可能要做龐大的簽入, 如果中間有任何差錯, 變更變得很難管理也很難做問題排解. 當然, 集中控管的系統也總有”可能”做合併, 但並不容易: 你需要親自確實追蹤合併的動作與內容, 以避免同樣的變更被做兩次. 分散式的版本控制系統讓分支與合併無痛執行, 因為這是此類系統的長處. (譯註: SVN支援Merge Tracking後就可以避免同樣的變更會合併兩次以上的問題)
請看一些示意圖
別的教學多是嚴肅的命令列指令, 在此提供您視覺化的說明. 讓你回想一下運用典型集中控管的版本庫的狀況:

每個人與主開發線同步也將檔案簽入主開發線: Sue加入soup, Joe加入juice, Eve加入eggs. Sue的變更必須先簽入主開發線才會被其他人看到. 的確, 理論上, Sue可以另開一個新的分支讓其他人測試她的變更, 可是在一般的版本控制系統(VCS)如此做很麻煩.
分散式版本控制系統(DVCS)
依分散式模式, 每位開發者有他們自己的版本庫. Sue的變動存在她的工作電腦的版本庫,她可以決定是否要跟Joe或Eve分享:

不過是否有可能像群龍無首一樣? 不會的, 如果想要的話, 每個人可以將他的變動上傳(push)給同一個版本庫, 令人感到執疑地, 這不就跟上面講的集中式版本控制管理一樣. 這個版本庫(包含了Sue, Joe和Eve的變動.
我希望分散式版本控制DVC(distributed version control)可以有不同的名稱, 如 “獨立的(independent)”, “聯合的(federated)” 或 “點對點的(peer-to-peer)”. 此字 “分散”讓人聯想到分散式運算, 工作被分派給一群機器(如尋找外星智慧訊號的 SETI@home {可參考SETI@home台灣網站} 或做 蛋白質摺疊分析Protein folding).
而DVCS並不像Seti@home: 每一端(node)是各自獨立的且是否分享由各工作端自我決定(在Seti, 你必須回覆你的結果)
5分鐘說明主要觀念
此給你基本概念; 如果你有興趣, 可參考相關patch theory的說明書 .
核心概念
- 集中式版本控制聚焦於同步,追溯(tracking), 和備份檔案.
- 分散式版本控制聚焦於變動分享; 每一變更有其 全域唯一辨識碼(guid-global unique id)或unique id.
- 記錄/下載以及採用一個變更被視為分別的步驟 (在集中式系統, 此三者同時發生).
- 分散式系統沒有強制的架構. 你可以建立”中央管理”區或讓個人保持在自己的工作端運作.
新術語
- 推(push): 將變更送給其他的版本庫 (也許需要權限)
- 拉(pull): 從另一版本庫下載同步檔案變更
主要的優點
- 每個人都有自己的沙盒(local sandbox). 你可以在自己的工作電腦上修改或回覆前版, 不需要大量的簽入. 你自己的工作記錄都累積存在自己的版本庫.
- 可離線工作. 你只有當你想分享變更時才需要上線. 否則你可隨你高興一直在自己的工作電腦上獨立作業, 簽入或復原, 沒有所謂”伺服器”當掉或在飛機上無法上網的問題.(譯者註: 現在有些國際線的飛機上付費後可以上網)
- 速度很快. 差異(diff), 提交源碼與變更回復都在本地端即可完成. 沒有因網路或伺服器不穩而必須要求使用一年前舊版本的問題. (譯者註: 作者應該是指伺服器OS版本與版本控制版本匹配的問題)
- 可妥善做變動的處理. DVCS針對分享的變更做建置. 每個變更都有其獨一無二的辨識碼(GUID)以方便追蹤.
- 分支與合併很容易. 因為每一開發人員”有自己的分支”, 每一分享的變動就像交換整合(reverse integration). 但獨一無二的辨識碼(GUID)讓自動合併變更與避免重複合併動作變的簡單容易.
- 較少的管理. DVCS很容易部署; 不需要安裝“一直運作的”伺服器軟體. 此外, DVCS也不太需要你去”加”新的使用者; 你只是去選擇你想從那裡拉(pull)版本庫的URLs. 這樣可以避免大型專案中令人頭痛的政治性問題.
主要的缺點
- 仍需要備份. 有個說法是你的“備份”就是其他人有你變更資料的終端機資訊. 我無法認同—如果這些其他人終端機資料並沒有採用你所有的變更呢? 或是當你變更的時候他們都不在線上? 用DVCS, 你仍希望可以有台機器讓你push所有的變更到他那裡保存“以防萬一”. (在Subversion, 你有一台隨時待命的機器做主要的資料貯存庫, 建議您在DVCS也做一樣的事).
- 沒有所謂的“最近的版本”存在. 如果沒有集中地, 你無法馬上知道是否要到Sue, Joe或Eve那取得最近變更的版本(version). 再者, 一個中央集中的檔案庫才可幫助大家清處地知道最近的”穩定版本”為何.
- 沒有真正的修訂版號碼(revision numbers). 每一版本庫有依變更做出的修訂版號碼. 和傳統的集中式版本庫不同的做法是人們依變更的修訂號碼做溝通: “請問你有變更號碼 fa33e7b? ” (這個變更號碼GUID 似乎長的不太好看). 還好, 你可以用有意義的名稱標示你發佈的版本.
Mercurial 快速上手(Quickstart)
cd project
hg init (create repo here)
hg add list.txt (start tracking file)
hg commit -m "Added file" (check file into local repo)
hg log (see history; notice guid)
changeset: 0:55bbcb7a4c24
user: Kalid@kazad-laptop
date: Sun Oct 14 21:36:18 2007 -0400
summary: Added file
[edit file]
hg revert list.txt (revert to previous version) hg tag v1.0 (tag this version)
[edit file]
hg update -C v1.0 (“update” to the older tagged version; -C forces overwrite of local copy)


你將有:
- 一個工作拷貝(working copy). 你正在編輯的檔案群.
- 一個版本庫. 一個目錄(Mercurial的.hg)包含所有的補釘(patches)以及可演譯資料(metadat:comments, guids, dates, etc.). 因為沒有集中的伺服器, 所以這些資料都放在你這裡.
理解更新(Updates)與合併(Merging)
在研究DVCS時有幾項讓我有些混淆. 第一, 有幾步將造成更新(updates)
- 取得變更到版本庫:推(pushing) 或 拉(pulling)
- 採用變更到檔案中:更新(update) 或 合併(merging)
- 儲存新版:簽入/提交源碼(commit)
第二, 依據變更, 你可以更新或合併:
- 當無模糊地帶時,更新(Updates)發生. 譬如, 我將變更拉(pull)到一直以來都是你在編輯的檔案. 因沒有重疊的變更,檔案將跳到最近的修訂版(revision).
- 當我們的變更發生衝突時,就有必要合併(Merge). 如果我們兩個都去編輯檔案,最後會變成兩個”分支”, 類似平行宇宙(alternate universes-多種假設同時發展的各個故事)的樣子. 有個我修改的世界, 也有個你修改的世界. 在此例, 我們可能想要合併成一個單一的宇宙.

在此案,因為 (+Soup) 和 (+Juice) 為同一個母項(parent-僅一個 “Milk”的列表)的變更, 有必要做合併(merge). 經過Joe合併檔案後, Sue可以做一般的 “pull和update” 即可獲得Joe已合併的結果. 她不需要親自做合併的動作. .
在Mercuril, 你可如下執行:
hg incoming ../another-dir (see pending changes)
hg pull ../another-dir (download changes)
hg update (actually apply changes...)
hg merge (... or merge if needed)
hg commit (check in merged file; unite branches)

是的, “pull-merge-commit” 周期蠻長的. 幸運地, Mercurial有整合多指令(commands)為單一的捷徑. 雖說看起來好像蠻複雜的, 但仍比在Subversion手動合併簡單多了.
大多數的合併是自動完成的. 當發生衝突時, 一般可以很快被解決. Mercurial持續追蹤每一變更的母/子關係(我們的合併列表有兩個母項), 與”最新版(heads)”或每一分支的最近變動. 在合併前我們有兩個heads;之後, 一個.
組織一分散式專案
此為一種組織方式:

Sue, Joe和Eve將變更加入一共同的分支. 他們可以跟任一人交易補丁(patches)來做”兄弟建置(buddy builds)”:嘿 老兄, 請問要試試這些補丁嗎? 在推給實驗分支(experimental branch)前,我需要看看此是否可行.
然後, 經維護守門員在看過,將實驗分支的變更拉到穩定的分支(stable branch), 此有最近的版本. 分散式的版本控制系統(DCVS)幫助每一變更獨立進行, 但也提供集中系統所有的”單一來源(single source)”. 有多種開發的模式可用, 如”pull only”,此只有維護守門員決定是否要從別人拿取變更資料, Linux的開發採用此種,或”shared push”, 此和集中管理的系統作業模式很類似. DVCS讓您彈性選擇要採用哪種方法來維護您的專案.
練習和嚴厲批評以臻至善
我是DVCS新手,但很高興分享我目前已瞭解的. 我覺得SVN很好用, 但覺得去了解如何可以讓合併簡單容易也有趣. 我的建議是你可以從Subversion起步, 感受一下什麼是團隊協同作業,再實驗分散式的模式. 如果你適當的籌劃, DVCS可以達到集中控管系統的效果, 你也同時可享有簡易合併的好處.
- Mercurial 有超優的說明. 如果在Windows上, 你有可能需要 diffing/merging software 或 TortoiseMerge(如果你已安裝TortoiseSVN).
- Darcs 有很詳細的 wikibook (有一些相關變更的數學理論).
- Git 由Linus Torvalds創造. 以下為他相關DVCS有趣的演說 ;如果你在用集中管理的系統, 準備被訓一頓吧:
從Linus演說影片節錄:
- “How many have done a branch and merged it? How many of you enjoyed it?”
- “When you do a merge, you plan ahead for a week, then set aside a day to do it.”
- “Some people have 5, 10, 15 branches”. One branch is experimental. One branch is maintenance, etc.
- “CVS — you don’t commit. You make changes without committing. You never commit until it passes a giant test suite. People make 1-liner changes, knowing it can’t possibly break.”
所以呢…. 祝好運囉, 密切注意聖戰狀況…
Soft & Share在Facebook有經營兩個粉絲團, 歡迎來加入
喜歡我們的分享嗎? 記得使用以下社群分享按鈕分享給您的社群朋友吧!