[翻譯]Git 與 Mercurial 的分析

本文翻譯自下面網址:
http://code.google.com/p/support/wiki/DVCSAnalysis

注意:這個分析在 2008 年夏天進行,起因於 Google Code 評估加入分散式版本管理功能

摘要

這份文件總結了 Google Code 在希望加入分散式版本管理功能所做的初步研究,基於普及性,只考慮了兩個分散式版本管理系統: Git 與 Mercurial 。這份文件說明了兩個系統的功能,也提供一個將它整合進 Google Code 所需要進行的工作。

分散式版本控制

在傳統的版本控制系統,一般會有一個集中的資料庫控管所有記錄,用戶必須與這個資料庫互動來驗證檔案的記錄、檢視其他分支與提交異動。通常用戶端會複製一份資料進行處理,但是這個版本並不會儲存早期版本與其他分支的資料。

分散式版本管理系統(以下簡稱 DVCS)使用了不一樣的結構,使用 DVCS 時,每個使用者會有一個本地端的資料庫、完整的專案異動記錄、分支等等,切換到不同的分支、檢驗檔案異動記錄或甚至提交異動都是在本地端進行操作。而個別的資料庫間可以透過推(push)與拉(pull)操作進行資訊的交換,一個推的操作會將本地端的部份資訊傳送到遠端資料庫,而拉的操作則會將遠端的資料複製到本地端資料庫。需要注意的是,沒有任何一個資料庫具有較高的權威性,兩個資料庫也許都會有些本地端的記錄還不會出現在另一端,任何的 DVCS 系統都有一個關鍵性功能,就是讓資料庫可以清楚傳達本地端所擁有的記錄(以及它所需要的記錄),而 Git 與 Mercurial 兩者都是透過 SHA1 雜湊值來檢驗資料(檔案、目錄結構、版本異動等)。

DVCS 讓開發者在工作流程上有更多的彈性,他們可以用傳統版本控制系統的習慣進行操作,也就是透過一個集中、具有權威的資料庫讓開發者進行同步;而對於比較大的專案,它也可以提供具有階層關係的資料庫,只要每個資料庫的維護者允許來自下層開發者的異動以及將這些異動提交給上層。 DVCS 還允許開發者彼此間分享工作成果,例如兩個開發同樣功能的開發者可以在相同的分支上進行開發,但是兩者之間成果的分享不需要透過一個權威性的伺服器;當他們完成了開發,就可以將成果推到公開的資料庫,讓更多人使用。

因為沒有集中的資料庫,所以不會有所謂的主從架構,當談論到兩個資料庫時,一般是指本地端與遠端,而不是伺服端與用戶端的關係。不過在 Google Code 實作的概念中,在 Google 的資料庫還是會被當作伺服端,而使用者的資料庫會被稱為用戶端。

功能比較

事實上, Git 與 Mercurial 有許多相仿之處,因此在這裡不會提供兩者都有的冗長功能清單,這個部份希望點出兩者間顯著的差異。

Git 的優點

* 用戶端儲存管理, Git 與 Mercurial 都允許使用者選擇從其他資料庫拉回分支,這提供了一個前端結構來減少本地端儲存的異動記錄。除此之外, Git 允許捨棄較早拉回的分支, Git 還允許從本地端資料庫將舊有的版本異動刪除(同時仍然會保留這些分支的最新版本資料)。而在 Mercurial ,如果一個分支是儲存在本地端資料庫,所有版本異動(從最初提交的版本)都必須存在,除了建立一個新資料庫選擇性將分支推進資料庫外,沒有辦法刪除分支資料。雖然他們正在開發這個部份,但是還沒正式推出。

* 父階層的數量, Git 在合併時支援無限數量的父階層版本異動,而 Mercurial 只允許兩層。如果希望在 Mercurial 做到 N 階層合併,使用者必須執行 N-1 次的兩層合併,雖然一般合併 N 個父階層資料時會建議採用 Mercurial 的作法,但使用 Git 時使用者可以一次完成。

* 分支點變更(Rebasing), Git 提供一個 rebase 指令,可以在一個本地端分支修改分支點到一個較新的版本,例如某個人在開發一個產品的新功能,本地端分支也許已經從 1.0 版開始,而如果開發過程主要的產品線已經更新到 1.1 ,也許需要將 1.0->1.1 的異動拉回本地端功能開發中的版本,並且將分支點從 1.0 改為 1.1 。在其他系統中,會透過合併 1.1 的異動進入分支,合併也是從版本控制系統角度看來正確的事情,如果將焦點放在"過去狀態的重製能力"。不過如果焦點是 “製作一個簡潔的軟體改版記錄" ,分支點變更有時會比較好。 git-rebase 允許讓一個過去未連續的異動記錄能夠連貫,讓異動記錄可以簡潔些。正確的說,這個功能其實是將 1.0 版的所有異動個別提交到 1.1 版,分支點變更功能是安全的執行這些操作,並且刪除 1.0 版,因此不會讓樹狀結構變得混亂。

備註: Mercurial 在這份文件完成後已經有加入了分支點變更功能。

Mercurial 的優點

* 學習曲線,基於許多的事實, Git 跟 Mercurial 比起來有著比較陡峭的學習曲線。 Git 有比較多的指令與選項,這些功能的說明可能會讓新使用者備感威脅。 Mercurial 的文件對於新手來說相對完整與容易閱讀,Mercurial 的用詞與指令也比較接近 Subversion 與 CVS ,因此對於從那些系統轉移的人們來說會比較親切。

* 支援 Windows , Git 有著強大的 Linux 包袱,在 Windows 執行它的正式作法是透過 cygwin ,對於一個 Windows 使用者來說不是非常理想。一個使用 MinGw 改寫的 Git 漸漸受到歡迎,但是 Windows 在 Git 世界中仍然是一個次等公民。在有限的測試中, 使用 MinGW 改寫的版本看來提供了完整的功能,但是有點遲鈍。一些在  Linux 或 Mac OS X 幾乎是即使反應的操作,在 Windows 中可能需要十幾秒。 Mercurial 是使用 Python 開發,而且正式版本在 Windows 下執行順暢(在  Linux, Mac OS X 等系統也是)。

* 維護, Git 需要定期維護資料庫(例如 git-gc),而 Mercurial 不需要。不過需要注意的是, Mercurial 對於用戶端磁碟空間的管理也比較沒那麼複雜(可以參考上面關於用戶端儲存管理的說明)。

* 記錄是不容侵犯的, Git 非常強大,可以執行任何你想做的事情,不幸的是,這也意謂著 Git 也很容易遺失記錄。舉例來說, git-push –force 會讓遠端資料庫的版本異動消失;Mercurial 的資料庫結構比較像是不可變物件持續成長的集合,雖然在部份情況下 (像是 rebase) ,改寫記錄是有優點的,但這也很危險,可能會導致無法預期的結果。不過需要注意的是, Git 伺服器可以透過設定來避免遺失資料,所以 Mercurial 這個優點並不是那麼明顯。

其他差異

* 檔名更改/複製的追蹤, Git 並不會明確的追蹤檔名更改與複製,取而代之的是像 git-log 指令用來比對資料庫記錄中是否有同樣的檔案來推論檔名更改或複製。 Mercurial 以比較熟悉的形式,提供明確的檔名更改與複製指令,並且將這些操作儲存到檔案的記錄中。 兩種方式各有其優缺點,哪個比較好並沒有比較明確且普遍的答案。

* 架構, Git 原本是以 C 設計的大量 shell scripts 與 unix 指令,隨著時間推演,在指令間共用的函式庫已經開發完成,許多指令已經內建在主要的 git 執行檔。 Mercurial 大部分是用 Python 設計(少部份使用 C),包含一個外掛的應用程式介面,允許透過自行設計的 Python 模組加強 Mercurial 功能。

* 私有記錄,在 Git ,開發者操作的預設模式是使用自己本地端(與私有)的標籤、分支與版本異動,而且在公開後可以運用許多控制。而 Mercurial 強調另外一種方法,預設的推/拉行為會共享所有資訊,如果只想共享一部份就需要額外的步驟。這沒有列在任一系統的優點,因為兩者都支援另外一種操作。

* 分支命名空間,在 Git ,每個資料庫有自己的分支命名空間,使用者可以設定本地端分支名稱與遠端對應情形。在 Mercurial ,所有資料庫共用一個分支命名空間。

實作考量

資料儲存

Git 與 Mercurial 內部使用非常相近的資料:檔案版本異動與少量的後設資訊(父層資料、作者等),兩者都有代表整個專案提交的物件,這些物件也都有版本記錄。兩者都有記錄每次提交所有檔案的版本。在 Git 使用的是一個樹狀物件 (一個樹狀結構,包含目錄的樹狀物件與檔案版本參考的樹葉結點)。在 Mercurial ,使用一個物件清單(一個對應路徑名稱到檔案版本物件的清單)。除了物件清單與樹狀結構的差異外,兩者在物件的搜尋與走向都相當接近。

Git 直接在檔案系統使用一個儲存物件的集合 (透過 SHA1 雜湊索引) 並且將多個物件打包成更大的壓縮檔;而 Mercurial 使用一個改版記錄結構 (基本上是一個連續的改版差異,加上定期的完整版本備份)。在實作時都不會使用原本的儲存方式,物件都會儲存在 Bigtable 中,基於 Git 與 Mercurial 在基礎資料物件的相似情形,無論使用哪個應該花費的時間一致。

在資料儲存時的唯一主要差異是使用的語言,如果要重複運用大部分 Git/Mercurial 的程式碼, Git 的部份需要使用 C ,而 Mercurial 則是使用 Python (或也許是 C++ 與 SWIG 的結合)。

Mercurial 整合

Mercurial 在遠端資料庫的推拉操作提供基於 HTTP 不依賴狀態特性的良好支援,開發者花費了許多精神在減少用戶端與伺服器間往返檢查需要交換的資料,且一旦完成檢查,所有相關資料會集合起來一次大量傳輸,這符合了 Google 的架構,所以在用戶端不需要任何改變。

Git 整合

Git 包含了推向 HTTP 的功能 (與推向 WebDAV ),但是程式假設伺服器端對於 Git 沒有任何準備,它的設計是以 Apache 將 Git 資料庫當作靜態檔案的情況下,這個方式需要大量為了同步化的請求往返,不適合用在 Google Code 。

Git 也提供了一個自訂的、依賴狀態的協定,支援比較快速的資訊交換,但是不符合 Google 的架構,因為 Google 非常需要不依賴狀態的 HTTP 協定,因為已經在這個架構上投入了大量資源讓它穩定且有效率的執行。

備註: 在這份文件完成後 Git 社群已經開始有些改善 HTTP 支援的討論。

總結

基於實作上的差異, Mercurial 有著明顯的優勢,因為它對於 HTTP 傳輸協定的支援。

不過就功能性而言, Git 確實比較強大,但也相對意謂著使用上更加複雜。

12 關於 “[翻譯]Git 與 Mercurial 的分析” 的評論

  1. 引用通告: TortoiseHg 设置语言成中文 | 走走停停看看

  2. 引用通告: 在Google Code上用 Mercurial 取代 Subversion 管理你的项目 - Leeiio Chaos Made.

  3. 引用通告: 分布式版本控制系统——Mercurial « Beyond the Void

  4. 引用通告: 放弃SVN,选择DVCS | 淡笔留痕

  5. 引用通告: links for 2010-08-06 « Yesure

  6. 引用通告: 学习hg(Mercurial)版本控制 | 落落

  7. 引用通告: 淡笔留痕 » 放弃SVN,选择DVCS

  8. 引用通告: 「SCM」最近可選擇的 GIT 公共服務 - NewBSD

發表迴響

你的電子郵件位址並不會被公開。 必要欄位標記為 *


9 − 2 =

你可以使用這些 HTML 標籤與屬性: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>