猶豫 Mercurial 或 Git 嗎?選 Git 就對了!

Mercurial (Hg) 和 Git 都是很有名也很好用的分散式版本控制系統 (DVCS),兩者各有特色,也各有一定的支持者和社群。筆者認為,絕大多數情況下,Git 會是比較明智的選擇。以下簡單分析:

1. Git 對檔名的跨平台支援較好

Mercurial 是記錄檔名的原始編碼,如果 Windows (Big 5) 上的 Hg 版本庫內含中文檔名,到 Linux (UTF-8) 或 Windows (GB2312) 上就會變成亂碼;反之,在 Linux 上的 Hg 版本庫如有中文檔名,拿到 Windows 上也會變成亂碼。

Git 則沒有這個問題,Git 版本庫中所有檔案名稱都是統一使用 UTF-8 編碼。Linux 平台上的 Git 自然是 UTF-8 編碼,而 Windows 平台的移植如 Git for Windows 等等也都會自動在進出 Git 版本庫時把檔名轉成 UTF-8 編碼。

雖說大部分程式專案不會用到中文檔名,不過 VCS 並不總是只用在寫程式,有時也用於網頁或文件管理;即使是程式專案,也可能會需要儲存中文檔名的文件備查,此時檔名不跨平台就悲劇了。如果專案有可能在不同作業系統上跑,如果希望不同作業系統的慣用者都能輕易參與開發,如果常從網路上 fork 他人專案來參考,檔名編碼相容性都是值得考慮的問題。

您絕對可以在不同專案使用不同的版本控制系統,然而若只打算使用一種,強烈建議一開始就選擇相容性最大的系統,以絕後患,除非您非常確定您的整個使用生涯能完全排除上述可能性。

如有 Big5 編碼檔名的 Hg 版本庫想轉移到 UTF-8 編碼,可以用 hg convert 轉換整個版本庫的檔名編碼,然而這代價是重寫整個版本庫,編碼轉換後也無法和原來使用 Big5 編碼的系統共享。

2. Git 的內部儲存架構較好

版本庫要儲存很多資料,雖然它們都藏在那毫不起眼的 .hg 或 .git 中,但我們總有搬移、複製、備份的機會,它們在硬碟中以什麼方式保存,也是很重要的。

Hg 是為每個檔案建立一個增量壓縮(delta compression)檔,把該物件的所有相關版本存放在裡面;Git 的方法較複雜,它為每個檔案建立快照,並根據內容算出獨一無二的 hash 檔名儲存,因此,同樣內容的檔案一定會對應到同一個 hash 物件檔 。假設我有個 foo 檔案,第 2 版改了第 1 版 10% 的行數,Hg 是把第一版加上那 10% 的差異儲存到對應的檔案(.hg/store/data/foo.i),Git 則是把第一版和第二版分別儲存成兩個不同的物件檔(比如 .git/objects/0a/a2840a607b10a956db83dd0b6ee486de4d8a08)。

乍看之下似乎 Hg 比較有效率?但相對而言,如果我把 foo 複製到 foo2,Hg 將會儲存 foo.i 和 foo2.i 兩個檔案,而 Git 仍然只儲存一個檔案。更驚人的是,Hg 即使只是把 foo 更名為 foo2,版本庫也得複製檔案而多佔一倍空間!

Git 會定期打包資料庫,把多個物件檔打包成數量較少的壓縮檔(.git/objects/pack/*),其打包策略也是增量壓縮,但 Git 會透過一些演算法偵測內容相近的物件檔以優化壓縮比。舉例來說有個 bar 檔案的第 2 版本從第 1 版刪了 90% 的行數,第 3 版再加回 89% 內容,若是 Hg 會打包了 100% + 90% + 89% = 279%,而 Git 可能會按第 1 版 → 第 3 版 → 第 2 版的順序儲存,只打包了 100% + 1% + 89% = 190%,此時 Git 就勝出了。由於對 Git 而言一切都是物件,甚至可以採用諸如 A 檔第 x 版 → B 檔第 y 版 → C 檔第 z 版 → ……之類的增量壓縮策略,因此 Git 的壓縮效率更好。

有人拿真實專案測試過,顯示一般情況來說,壓縮打包以後,Git 版本庫容量上是較精省的。

除了容量小以外,如果我們的專案有 100,000 個檔案,Hg 版本庫內部就至少要有 100,000 個對應的物件檔;而 Git 打包後可以把檔案數縮減為數十個。另外,非 ASCII 檔名在 Hg 內部會轉碼儲存,比如 Big5 的「中文檔案.txt」會儲存成「~a4~a4~a4~e5~c0~c9~ae~d7.txt.i」,除了不美觀,也比較容易因檔名過長造成作業系統處理上的問題。

此外,由於 Git 版本庫的物件檔只建立、刪除而不改寫的特性,Git 在同一磁碟區建立 local clone 時可透過 hard link 共用檔案,這可以省下將近一半的空間。

簡而言之,Git 的版本庫體積小、檔案少、檔名好看、可 hard link clone、沒有更名即是複製的問題,是不是比較和藹可親呢?

3. Git 功能比較強

Git 的版本分支非常輕量,對整個系統負擔極小。Hg 的分支則寫死在 commit 中,難以事後靈活更動。

Git 會把本地和遠端的分支放在不同的命名空間 (namespace),這讓我們可以清楚區分自己和他人的東西,我們可以一方面廣開 local branch,一方面又和 remote 和平共處。Hg 則所有分支共用同一命名空間,自己和他人的開發線容易混成一團、難以區分。

Git 改寫歷史的威力超強,比如互動式衍合 (rebase -i) 就是傲視群雄的絕招之一,而且大多數圖形界面都有支援,這使得 Git GUI 往往就比 Hg GUI 好用。雖然有些人不贊成重寫歷史,不過功能強可備而不用、功能弱卻不能在需要時有所發揮。況且在本地端開發時,重寫歷史的確經常可以讓版本庫變得更簡潔明瞭。除了 rebase 以外,Git 在命令列的 filter-branch 指令也是殺手級的強大功能。

除此之外,Git 還有像 git subtreegit notesgit replace 之類在特定場合威力無窮的強大功能,這些都是 Hg 原生及官方擴充套件沒有提供的。

4. 西瓜偎大邊

基於某些歷史因素,大部分開放原始碼的版本庫是以 Git 發布,大部分程式高手講的都是 Git,Git 的資源和社群也比 Hg 大很多,比如那萬惡的 GitHub。使用版本控制系統很重要的一點是與人交流,如果大家都用 Git,我們用 Hg 會多上很多交流障礙。用 Hg 工作效率比 Git 高很多就算了,如果沒有,何必自找麻煩呢?

小結

本人早期有好幾個專案重度使用 Hg 記錄(版本庫僅自用未公開),有 Linux 的也有 Windows 的,後來基於以上考量逐漸轉換到 Git,目前 Hg 幾乎是棄用狀態。

Hg 在 Windows 平台「相容性」佳,如果版本庫很大,TortoiseGit 確實比 TortoiseHg 更容易感受到停頓與延遲,但這點差距隨著 Git 跨平台移植的進步正持續縮小,相較之下 Hg 的檔名編碼問題反而是跨平台開發的一大罩門。Hg 確實還有許多優點如容易上手、本地版本編號、指令簡潔明瞭、文件簡單清楚、容易製作擴充套件等。不過考量到跨平台相容性、儲存效率、功能、社群等重大因素,無論是用 Windows 或 Linux、用圖形界面或指令界面,長遠來講筆者以為用 Git 還是比較明智的選擇。

(2017/12/17 二版)

留言

  1. 很详细的讲解,将git与hg的特色都细心的做了比较。受教了

    回覆刪除

張貼留言

1.本格歡迎任何留言,只有廣告和垃圾留言會刪。
2.希望您盡量留下代稱,以方便大家討論、回覆。
3.如果您打算長篇大論,建議在您自己的部落格貼文,然後留下連結和摘要。

這個網誌中的熱門文章

Windows 批次檔令人崩潰的特殊字元處理

為什麼 Mercurial 沒有比 Git 更好

中文與英文的比較

用 git replace 改善 Git 本地版本庫的開發線圖