蔣鑫:為什麼 Git 比 SVN 好

發表於2013-03-24

來源:蔣鑫

在版本控制系統的選型上,是選擇Git還是SVN?

對於開源專案來說這不算問題。使用Git極大地提高了開發效率、擴大了開源專案的參與度、 增強了版本控制系統的安全性,選擇Git早已是大勢所趨。

但對於企業使用者來說這個決心不太好下。部分原因是出於對Git的誤解,部分原因是尚不瞭解 Git到底能給專案管理帶來什麼好處。希望本文能對您專案的版本控制系統選型提供幫助。

 

對SVN的迷信和對Git的誤解

 

誤解1:SVN只能檢出(checkout)一個版本(revision)的程式碼,而Git卻可以脫庫!

這個誤解是如此普遍,簡直成了SVN在企業市場中封殺Git的尚方寶劍。其實稍微思考一下 這個謠言就很難傳播。既然SVN能夠讀取授權訪問的檔案的每一個版本,那麼就能夠重組這些版本, 進而實現對版本庫的完整複製。即SVN也可以脫庫。

蔣鑫:為什麼 Git 比 SVN 好

SVN脫庫的工具SVN本身就提供: svnsync 。這個工具主要用於SVN的版本庫映象。 例如將版本庫http://host.name/svn/repo 脫庫到本地的 dump 目錄,命令如下:

如果使用 git-svn 則為SVN“脫庫”更簡便。

有人認為SVN可以對目錄授權,從而阻止對整個版本庫進行脫庫操作。 下面就來看看SVN的授權究竟是否可靠。

 

誤解2:SVN能對目錄進行精細授權,而Git太不安全

SVN的目錄授權對管理員來說是災難,管理負擔相當重,在分支或里程碑眾多的時候很難作對。 這是因為SVN的分支和里程碑(tags)本身就是一個目錄(使用目錄拷貝實現的)。

例如管理員為名為demo的SVN版本庫授權。一個並不太複雜的主線(/trunk)授權如下:

如果專案建立了維護分支 /branches/1.x ,若和 /trunk 授權相同,則需要將上述授權在 /branches/1.x 下重建。需要在授權檔案中再新增如下授權指令:

如果版本庫的分支和里程碑越來越多,配置的工作量相當可觀,稍有不慎不是授權檔案格式破壞導致SVN無法工作, 就是造成開放授權。

我曾經寫過SVN路徑授權的補丁,並寫了一款SVN版本庫管理的開源軟體 (參見 《pySvnManager手冊》 ), 但想完美解決這個問題很難。我的一個設想是在SVN對分支和里程碑授權檢查時預設使用 /trunk 的授權,但這樣的實現要求使用SVN嚴格遵循約定俗成的三個頂級目錄的規範。

Git對於寫操作可以精細到目錄和分支級別(使用Gitolite作為伺服器), 但作為分散式版本庫控制系統,在設計上只能實現版本庫量子化的讀授權。 即某使用者對整個版本庫要麼都能讀,要麼對整個版本庫都不能讀。

那麼如何控制Git版本庫的讀授權呢?實際上Git可以通過子模組來實現細粒度的讀授權。 即在專案需要精細授權的場合,將版本庫拆分為多個Git版本庫進行單獨授權, 再使用子模組將多個版本庫整合為一個。這個操作並不複雜,而且有助於實現專案的模組化。

 

誤解3:Git能隨意改變歷史提交,這對於版本控制來說是不合適的

Git對歷史提交的修改只對本地提交有意義。本地提交就像是和共享版本庫間的緩衝。 在未將本地提交推送到遠端共享版本庫之前,開發者可以後悔。可以對不完整的提交說明進行補充, 可以移除錯誤的提交,可以壓縮合並提交等。Git對提交歷史靈活的操作是Git獨有的功能, 是提交稽核的必備工具。

對於已經推送到遠端共享伺服器的提交,Git就不能再像本地一樣隨意更改了。 因為推送到共享版本庫的提交一旦被其他程式設計師獲取,便擴散出去, 如覆水難收,難掩眾人悠悠之口。所以Git更改歷史提交只對本地有效,是安全的。

相比之下,SVN本地工作區和集中式版本庫之間沒有緩衝,一旦發現提交了錯誤內容, 或寫了錯誤的提交說明,則無法更改,除非SVN管理員介入。 SVN也允許配置為可修改歷史提交說明,但是一旦管理員放開此功能, 歷史提交的提交說明有可能被批量、惡意更改,並且無法恢復。

 

誤解4:SVN對中文支援更好,Git庫中的中文目錄和檔名會出現亂碼

我也曾經這麼認為,並在《Git權威指南》第3章中用了大量篇幅介紹中文支援的注意事項。 並推薦使用Cygwin作為首選客戶端,以避免GBK字符集為跨平臺開發的版本庫引入亂碼。

一個好訊息是Windows下最常用的Git客戶端 msysGit 也支援Unicode了。 使用最新版本(1.7.10)的 msysGit 無需設定任何Git配置變數, 版本庫中的中文檔名、目錄名、提交說明都使用Unicode編碼。 配合使用Unicode版的TortoiseGit(最新的1.7.9.0版本已是Unicode版), Windows使用者就不再為跨平臺開發的字符集問題而傷腦筋了。

 

誤解5:SVN的認證方式比Git豐富,比如可以實現LDAP認證

我為客戶配置的Git支援HTTP、SSH協議,和Gitweb。其中HTTP協議、Gitweb都使用LDAP認證, 實現統一的口令管理。並且無論是HTTP協議、SSH協議,還是Gitweb都使用同一套Gitolite授權。

 

誤解6:SVN更易上手,更易管理;而Git太難和太靈活了,不適合團隊?

如果想把配置管理做好,無論是 SVN 還是 Git 都不容易,否則 《SVN Book》 以及我寫 《Git權威指南》 也不會有那麼厚了。

 

覺得SVN更簡單的,看看下面的錯誤你有沒有犯?

● 很多公司的SVN版本庫沒有遵照約定俗成的三個頂級目錄。

● 如何配置SVN悲觀鎖,以便更好地對二進位制檔案編輯進行協同。

● 維護合併追蹤的 svn:mergeinfo 屬性,以便能夠正確的分支合併。還要防止無此功能的客戶端對其的破壞。

● SVN如何正確的反刪除,直接新增刪除的檔案是不對的。

● 如何使用 svn:eol-style 屬性,以便正確處理跨平臺開發時的檔案換行符問題。

● SVN管理員如何對版本庫進行整理,如撤出不當提交、修改錯誤的提交說明。

● 版本庫的安全性問題,如何做好版本庫的備份。

SVN對分支當做路徑來授權,造成管理的負擔(參見 前面的描述 ), 因此使用SVN實現靈活的特性分支開發、可靠的釋出控制(維護分支凍結)很難。

企業應用Git的困惑之一是如何裁剪出適合自己的工作流。實際上Git本身已經給出範例:

理解Git的應用模型並選用合適的伺服器端軟體(如 Gitolite),可以定製出適合自己的工作流。 例如下表就是在企業中使用Git版本控制系統的典型角色劃分:

系統管理員 配置管理員 釋出工程師 整合工程師 模組負責人 開發工程師
(SYSadm) (SCMadm) (RELeng) (INTegrator) (MODmaster) (DEV)
建立版本庫
版本庫授權
版本庫改名 ?
刪除版本庫 ?
建立Tag
刪除Tag
建立一級分支
為分支授權
向 maint 分支強推
向 master 分支強推
向 maint 分支寫入
向 master 分支寫入
建立個人專有分支
建立個人專有版本庫
為個人專有版本庫授權

再來談談Git的使用,實際上Git的設計模型非常簡單,理解了其設計思想,就可以很容易地掌握 git resetgit checkoutgit rebasegit pushgit pull 等命令。

 

誤解7:程式設計師不喜歡命令列

誰說Git沒有好的圖形工具?SVN 有 TortoriseSVN,Git 同樣有 TortoiseGit。 只不過Git的命令列太好用,使得圖形操作顯得笨拙。

至於Windows用做開發環境是否還有前途,看看火熱的iOS、Android開發、和優雅的 MacBook 就知道了。

 

Git能做到,而SVN難以做到的事情

Git分支功能最為強大,分支管理能力讓SVN望塵莫及

Git可以很容易地對比兩個分支,知道一個分支中哪些提交尚未合併到另一分支,反之亦然。

● 檢視當前分支比other分支多了哪些提交:

● 檢視other分支比當前分支多了哪些提交:

我不認為SVN的分支是真正的分支,因為分支最基本的提交隔離SVN就沒能實現。 在SVN中一次提交可以同時更改主線(/trunk)和分支中的內容, 所以判斷一個分支中哪些提交未合併到另外的分支,完全不能對SVN抱有希望。

 

Git可以實現更好的釋出控制

針對同一個專案,Git可以設定不同層級的版本庫(多版本庫), 或者通過不同的分支(多分支)實現對釋出的控制。

● 設定只有釋出管理員才有許可權推送的版本庫或者分支,用於穩定釋出版本的維護。

● 設定只有專案經理、模組管理員才有權推送的版本庫或者分支,用用於整合測試。

 

隔離開發,提交稽核

如何對團隊中的新成員的開發進行稽核呢?在Git伺服器上可以實現使用者自建分支和自建版本庫的功能, 這樣團隊中的新成員既能將本地提交推送到伺服器以對工作進行備份, 又能夠方便團隊中的其他成員對自己的提交進行稽核。

稽核新成員提交時,從其個人版本庫或個人分支獲取(fetch)提交,從提交說明、程式碼規範、編譯測試 等多方面對提交逐一稽核。稽核通過執行 git merge 命令合併到開發主線中。

 

對合並更好的支援,更少的衝突,更好的衝突解決

因為Git基於對內容的追蹤而非對檔名追蹤,所以遇到一方或雙方對檔名更改時, Git能夠很好進行自動合併或提供工具輔助合併。而SVN遇到同樣問題時會產生樹衝突, 解決起來很麻煩。

Git的基於DAG(有向非環圖)的設計比SVN的線性提交提供更好的合併追蹤, 避免不必要的衝突,提高工作效率。這是開發者選擇Git、拋棄SVN的重要理由。

 

保證已修復Bug不再重現

以為建立完畢里程碑標籤(tag)便完成軟體版本的釋出是有風險的, 往往會由於之前的版本(維護版本)中的一些 Hotfix 提交沒有合併到最新版本而造成已修復問題在新版本中重現。

Git分支和合並追蹤可以解決這個問題。例如用 maint 分支跟蹤最新的發行版, 當確定里程碑tag v1.6.4 為最新發行版時,在 maint 分支執行如下命令以切換到最新發行版:

如果合併成功,代表發行版 v1.6.4 包含了所有前一個發行版的提交。 反之說明前一個發行版某個或某些Hotfix提交尚未合併到最新發行版中。

 

版本庫的安全性

SVN版本庫安全性很差,是管理員頭痛的問題。

● SVN版本庫伺服器端歷史資料被篡改,或者硬碟故障導致歷史資料被篡改時, 客戶端很難發現。管理員的備份也會被汙染。

● SVN作為集中式版本控制系統,存在單點故障的風險。備份版本庫的任務非常繁重。

Git在這方面完勝SVN。首先Git是分散式版本控制系統,每個使用者都相當於一份備份, 管理員無需為資料備份而擔心。再有Git中包括提交、檔案內容等都通過SHA1雜湊保證資料的完整性, 任何惡意篡改歷史資料都會被及時發現從而被挫敗。

 

更多的十條喜歡Git的理由

更多的十條喜歡Git的理由,參見 《Git權威指南》 第11-21頁。

● 異地協同工作

● 現場版本控制

● 重寫提交說明

● 無盡的後悔藥

● 更好用的提交列表

● 更好的差異比較

● 工作進度儲存

● 作為SVN前端實現移動辦公

● 無處不在的分頁器

● 快

 

什麼情況推薦使用SVN

SVN具有的悲觀鎖的功能,能夠實現一個使用者在編輯時對檔案進行鎖定,阻止多人同時編輯 一個檔案。這一悲觀鎖的功能是 Git 所不具備的。對於以二進位制檔案 (Word文件、PPT演示稿) 為主的版本庫,為避免多人同時編輯造成合並上的困難, 建議使用SVN做版本控制。

 

相關文章