Subversion(簡寫為SVN)作為開源社區貢獻的新一代版本控制系統,已經得到越來越廣泛的使用。我用過CVS(Concurent Version System,SVN的前身)和微軟的VSS(Visual SourceSafe),相比之下,SVN具有更強大的功能和更簡單的操作特性。
網上已有一些文章介紹SVN的安裝和使用,不過我在第一次配置時仍然遇到了幾個問題。這裡,我按照自己的思路來進行講解,以期對那些初次使用SVN並且對一些問題存在疑問的朋友有所協助。
1. SVN簡介
光說SVN好,那SVN究竟有什麼優點呢。在SVN的手冊裡有著詳細的說明,下面簡單介紹幾個重要方面:
1) 基於目錄的版本控制
傳統的CVS或VSS都是基於單個檔案進資料列版本設定的,這實際上滿足不了實際需求,因為在實際應用中,我們都希望按照項目或者工程進行管理,例如假設我們想要取出某個記錄點的整個專案檔,那麼基於檔案的版本控制系統就存在弊端,只能單個單個檔案的處理。而SVN則能很方便的做到這一點,你可以隨意的取出任何一個檔案、任何一個目錄的任何一個曆史版本。
SVN還允許對檔案和目錄進行增加、刪除以及複製和重新命名等操作,這些都會被記錄到曆史資訊中,實現真正的版本控制功能。
2) 原子提交
SVN裡的每次操作都是原子的,要麼全部成功,要麼全部失敗。假設你要提交多個檔案,如果有一個存在衝突,那麼其它修改都不會被提交。
3) 高效的分支(branching)與標籤(tagging)功能
先說標籤功能,通俗的講,標籤就是某個時間點的快照(snapshot),我們可以在項目進行到一些重要的裡程碑之時為之建立標籤,這樣可以方便以後隨時取出這些曆史版本。我想你會有一個疑問:SVN不是本身就有隨意取出任何一個曆史版本的功能嗎。是的,標籤的作用主要是為了給這些特定的曆史版本取一個友好的名字,以方便使用和維護。
分支則是用於建立多個並行的工作線,比如,當我們的一個項目需要為某個使用者提供一些特殊的功能時,那麼就可以為之建立一個分支,這樣能夠保正大部分代碼的共用,也使得整個項目變得容易維護和管理。
SVN對於分支和標籤的實現都是一樣的,並且採用了與Unix/Linux永久連結(Hard-Link)類似的機制,即是說,當我們建立分支或標籤時,SVN並不會立即為之建立一份拷貝,而是建立一個連結,只有當這些檔案以後被修改時才會真正產生一份副本。這種“緩式拷貝”方法是一種常見的最佳化方法,能夠有效節約空間。
那分支和標籤又有什麼不同呢。不同之處僅僅在於其“約定成俗”的含義,標籤意味著你不會再對其進行修改,而分支意味著你會對它進行開發。
4) 多種訪問方式
SVN提供了一個抽象的網路訪問層,可以通過不同的協議來對其進行訪問。首先,SVN提供了自訂的svn協議訪問方式,通過形如svn://host/repository的URL就能使用。再有,SVN還提供了與Apache Web伺服器相整合的功能,這樣,我們就可以通過http://host/repository的方式來訪問SVN了。
5) 對二進位檔案的支援
CVS雖然對二進位檔案也有支援,但實現得並不完善,你或許遇到過文字檔裡有中文字元而被認為是二進位檔案的事情,SVN則提供了對二進位檔案全面的支援,使得非文字檔也能跟文字檔一樣進行良好的版本控制。
6) Windows下與資源管理員整合的用戶端:TortoiseSVN
SVN本身只提供命令列的操作方式,TortoiseSVN是第三方開發的圖形化介面,它的出現使Windows下的版本管理變得非常方便。不過,由於是嵌入到資源管理員中,它可能會影響系統的速度——微乎其微,你可以自己評測一下。
7) 平台無關
SVN秉承了開源軟體的一貫優點,無論是Windows還是Linux平台,都可以相互訪問SVN伺服器。
如果你過去是VSS使用者,那麼這裡還要提一點,與VSS相比,SVN還有一個理念不一樣,VSS將版本衝突控制放在操作之前,你要操作某個項目必須先執行CheckOut以進行鎖定、防止他人同時修改。SVN提供了同樣的Lock功能,但通常情況下,我們只需各自獨立的進行修改而無需鎖定項目,如果有衝突在提交的時候再做處理,也就是說,SVN是將衝突控制放在操作之後、提交之時。也許你會覺得VSS更合理,但實際情況卻相反,因為在我們的實際使用中經常發生有人將整個項目CheckOut後忘了CheckIn,或者未選擇Recursive忘了將子目錄中的檔案CheckIn,這就讓其他人無法修改,於是不得不人為的通知其本人,非常麻煩。
2. SVN伺服器搭建
本節是針對管理員寫的,普通使用者可以跳過本節。我這裡只以Windows上的安裝為例,Linux上可按類似方式進行(有些配置參數會存在差別,具體參考說明手冊)。
1) 安裝SVN伺服器
a. 下載
SVN的官方網站為http://subversion.tigris.org/,當前最新版本為1.4.2。Windows下的二進位安裝包分為兩種,一種是以setup結尾的安裝檔案,另一種是普通的壓縮包檔案,setup檔案會自動註冊一些資訊,比如環境變數以及服務等,這些都是可以自己手動實現的。在我寫這篇文章時,官方網站上就只有普通二進位檔案,估計setup檔案稍晚些時候會出來。特別注意,下載時要詳細閱讀注意事項,看清與之配套的軟體的版本號碼,避免出現問題。
我選擇的版本為svn-win32-1.4.2.zip
b. 安裝
將svn-win32-1.4.2.zip解壓縮到安裝目錄下,我選擇的是C:/Program Files/Subversion,如果是setup檔案,直接運行安裝檔案即可。對於壓縮包,我們可以將bin路徑添加到系統內容變數中,以方便操作。可以看到,bin目錄下主要有如下幾個檔案: svnadmin:倉庫管理工具,包括建立、修複和備份等操作。
svnlook:倉庫查看工具,包括資訊、日誌和鎖定狀態等內容,不會造成倉庫的改動。
svnserve:svn服務程式,允許通過svn網路通訊協定來訪問倉庫。
svn:SVN用戶端,用於訪問倉庫,對項目進行版本管理。
svnversion:用戶端工具,用於查看本地拷貝的修訂資訊。
c. 建立倉庫(Repository)
SVN是以倉庫為版本控制單位的,一個SVN伺服器可以管理多個倉庫,每個倉庫擁有獨立的修訂編號(REVISION),倉庫中的任何一次更新都會帶來修訂編號的遞增。你可以根據需要選擇建立一個或者多個倉庫,這裡,我以建立多個倉庫為例子,假設我們將倉庫都放到D:/SVN_REPOS目錄下,下面的命令將會在該目錄下建立一個Test倉庫: svnadmin create D:/SVN_REPOS/Test 如果建立成功,D:/SVN_REPOS/下將會多一個Test目錄。
2) 搭建svnserve訪問方式
svn和http是兩種並列的訪問方式,你可以選擇其中一種,也可以都採用。
a. 註冊服務
為了讓SVN服務程式每次開機後自動運行,我們需要將其註冊為服務。在控制台中執行如下命令: sc create svnservice binPath= "/"C:/Program Files/Subversion/bin/svnserve.exe/" --service -r D:/SVN_REPOS" start= auto 注意,上述命令均在一行中。sc.exe是Windows 2000以後系統內建的一個工具,2000下沒有,可以從XP上拷過來。svnservice為服務名稱,後面的參數格式有嚴格要求,等號前面沒有空格而後面有。binPath本身帶有多個參數,因此用引號括起來,而由於路徑裡面又有空格,因此又加上了一層引號。 --service和-r均為svnserve.exe的參數,前者要求它作為服務運行,後者指明了倉庫的根路徑(多倉庫為倉庫的父目錄)。
帶安裝包的SVN會自動註冊服務,這時我們可能需要修改-r參數,命令如下: sc config svnservice binPath= "/"C:/Program Files/Subversion/bin/svnserve.exe/" --service -r D:/SVN_REPOS"
b. 訪問
註冊完後,通過運行sc start svnservice或者服務管理員(service.msc)啟動服務。
接下來,我們就可以通過下面的命令來測試系統是否工作正常: svn info svn://localhost/Test
如果正確的顯示出倉庫的相關資訊,那麼就大功告成了,否則請檢查服務的參數是否配置正確,比如,如果未在服務參數中指定正確的-r值,就會得到如下錯誤: No repository found in 'svn://localhost/Test'
如果安裝了TortoiseSVN,則可以直接在瀏覽器中輸入svn://localhost/Test,這樣會調出TortoiseSVN的Repos-Browser。到此,你就可以通過TortoiseSVN來匯入工程進行版本管理了(參見後文)。
c. 許可權配置
在進行許可權配置前,所有的使用者都能進行任何操作,在很多情況下是不允許的。在建立倉庫時,倉庫目錄下都會產生好幾個檔案夾,其中conf裡面儲存的是配置資訊,包括三個檔案: authz:存取權限配置
passwd:使用者名稱和密碼配置
svnserve.conf:基本配置資訊
先配置svnserve.conf,將裡面幾項配置前的注釋去掉,最後的內容如下: [general]
anon-access = read
auth-access = write
password-db = passwd
authz-db = authz
這些參數的含義檔案裡都有詳細說明,其中,anon-access和auth-access分別是對匿名使用者以及認證使用者的存取控制,password-db指明使用者密碼檔案路徑,authz-db指明許可權設定檔路徑。另外還有一個參數realm用於指明倉庫所屬的認證域,預設情況下每個倉庫位於不同的域(每個倉庫有一個唯一的uuid),因此我們可以不設定該項,除非多個倉庫需要共用同一份passwd配置。
passwd檔案的配置很簡單,格式如下(等號前面為使用者名稱,後面為密碼): [users]
harry = 123
sally = 123
guest = 123
authz則可以建立使用者組並精確配置某個使用者或使用者組對某個檔案或目錄的存取權限,下面是一個例子: [groups]
harry_and_sally = harry,sally
[/]
* = r
[/project1]
* =
harry = rw
sally = r
[/project1/foo]
sally =
[/project2]
@harry_and_sally = rw
guest = r
檔案內容其實很簡單易懂,groups用於定義使用者組,後面便是對資源的具體存取控制,/表示倉庫根目錄,*表示所有使用者,使用者組前面需加上@符號,r表示可讀,w表示可寫,等號右邊為空白則表示沒有許可權。注意對於目錄結構,當使用者訪問某個資源時,SVN會先看有沒有直接針對該資源的存取控制,如果沒有找到,則會繼承上一級目錄的存取權限,如此遞推。
再提一點,當我們有多個倉庫時,我們會發現這些倉庫的使用者帳號在大多數情況下都是相同的,因此,我們可以將passwd檔案放到公用的地方,然後將所有倉庫的password-db配置都指向該檔案。相應的,authz-db也可以共用一個檔案,不過需要在配置具體的存取控制時指明所屬的倉庫,如下: [/]
* = r
[repos1:/project1]
* = r
harry = rw
[repos2:/project1]
* = r
sally = rw 上述配置表明,所有人對所有倉庫的根目錄都有讀許可權,但只有harry對倉庫repos1裡的project1有讀寫權限,只有sally對倉庫repos2裡的project1有讀寫權限。
3) 搭建HTTP訪問方式
SVN可以通過Apache實現Web訪問方式,但這不是必需的,除非你有此需求。
a) 下載
Apache的官方網站為http://www.apache.org/,注意不要使用最新的2.2.x,而要選擇2.0.x,這一點在SVN官方網站上有特別說明,當初我就沒有注意到這一點,而導致Apache2.2啟動時無法載入SVN的模組,出現“perhaps this is not an Apache module DSO”錯誤。
我下載的版本為apache_2.0.59-win32-x86-no_ssl.msi
b) 安裝和註冊
執行Apache安裝程式。由於2.0的版本不會自動註冊為服務,因此我們需要手工處理。運行cmd.exe,進入apache安裝目錄下的bin檔案夾,執行如下命令即可: apache -k install
更多的命令可以通過apache help查看。
註冊完後,就可以通過系統托盤裡的Apache Monitor來啟動服務。如果80連接埠未被佔用,那麼伺服器應正常啟動,通過http://127.0.0.1就能看到Apache的測試頁面。
c) 配置
Apache是通過conf目錄中的httpd.conf檔案進行配置的,比如,預設的監聽連接埠為80,在檔案中搜尋Listen 80,將80改成你所需的其它連接埠即可。配置完後必須重起Apache才會生效。更多關於Apache的配置說明請參見其協助手冊或google之。下面網站為協助手冊的中文版本。
為了讓Apache支援SVN,比如增加一些配置項,一個典型的配置如下:
# 載入mod_dav模組,它是對WebDAV(Web-based Distributed Authoring and Versioning)協議的支援,由Apache內建
LoadModule dav_module modules/mod_dav.so
# 載入mod_dav_svn模組,它與mod_dav通訊,使Apache支援SVN,它位於SVN的bin目錄下。
LoadModule dav_svn_module "D:/Program Files/Subversion/bin/mod_dav_svn.so"
# 載入mod_authz_svn模組,用於進行許可權管理
LoadModule authz_svn_module "D:/Program Files/Subversion/bin/mod_authz_svn.so"
# 配置SVN的訪問路徑以及相關相關參數
<Location /svn/> # 通過http://HOST/svn/訪問SVN伺服器
DAV svn # 必需
SVNParentPath D:/SVN_REPOS # 說明D:/SVN_REPOS下的所有目錄均為倉庫
SVNListParentPath on # 在網頁中列出D:/SVN_REPOS下的所有倉庫
AuthType Basic # 基本的使用者名稱密碼驗證方式
AuthName "SVN REPOS" # 認證名稱,作提示用
AuthUserFile D:/SVN_REPOS/users # 使用者名稱密碼檔案
AuthzSVNAccessFile D:/SVN_REPOS/authz # 許可權控制檔案
Require valid-user # 只有通過認證才能訪問網頁
</Location>
# 重新導向處理,用於將http://HOST/svn地址重新導向為http://HOST/svn/
RedirectMatch ^(/svn)$ $1/
下面對幾個重要的地方作以說明:
i. 網上很多文章提到將mod_dav_svn.so和mod_authz_svn.so兩個檔案直接拷貝到Apache的modules目錄下,當初我按照這種方法做時結果在一台Windows 2000 Server上無法啟動Apache服務,為此折騰了半天。後來才明白,這些模組檔案其實就是一些動態連結程式庫,它需要依賴SVN的bin目錄下的其它幾個dll檔案(可以把尾碼改為dll,然後通過VC帶的depends查看其依賴關係),因此如果沒有設定環境變數,那麼Apache載入這些模組時就會失敗,當然也可以把所有依賴檔案(主要是libdb43.dll )拷貝過去。實際上,我們只需要通過絕對路徑來引用這些模組即可,這樣SVN升級後也不用再次拷貝。
ii. URL的訪問路徑為/svn/而不是/svn,因為後者可能有問題,導致通過http://HOST/svn訪問出現如下錯誤資訊
iii. SVNParentPath用於有多個倉庫的情況,如果只有單個倉庫,可以直接用SVNPath指明倉庫路徑。
iv. AuthUserFile指明使用者名稱密碼檔案,但它與前面提到的SVN倉庫下的passwd檔案不是同一個檔案,AuthUserFile是Apache的認證檔案格式,二者的區別主要是使用者名稱和密碼的分割符不同,passwd是等號,這裡的users是冒號,當初我就是把它們當成一個檔案而造成用戶端無法訪問(為什麼SVN不把passwd的格式定義成和AuthUserFile的一樣呢。這樣二者可以共用一個檔案)。如果要對密碼加密,那麼users檔案需通過Apache附帶的htpasswd工具產生,實際上我們也可直接採用明文方式。
v. 許可權控制檔案AuthzSVNAccessFile與前面SVN裡的authz一樣,因此可以共用。
4) 其它管理功能
a. 備份
b. 修複
3. SVN用戶端使用
本節針對用戶端使用者,主要介紹一些常用的操作方法。
1) 用戶端安裝
用戶端可以採用命令列方式,也可以採用TortoiseSVN圖形化方式,個人認為還是後者方便些。
TortoiseSVN從http://tortoisesvn.tigris.org/上擷取,注意版本應與伺服器保持一致。如果是命令列方式的話,那麼從http://subversion.tigris.org/下載一個SVN二進位包就行了,此處不多講。
TortoiseSVN屬於圖形化的用戶端軟體,其實前面的SVN安裝包裡已經含有用戶端程式,只不過是命令列方式的,你可以根據需要選擇是否安裝。TortoiseSVN的官方網站為http://tortoisesvn.tigris.org/,同樣,注意選擇與SVN伺服器配套的版本。
我這裡使用的版本為TortoiseSVN-1.4.0.7501-win32-svn-1.4.0.msi
安裝完後,會提示重起機器,實際上不用重起就能直接使用,只不過重起後會更新SVN檔案表徵圖的顯示。下圖是SVN工作區的右鍵菜單內容:
2) 主要操作
TortoiseSVN使用起來很簡單,所有操作都通過右鍵菜單來完成。命令內容也很直觀,而且有非常詳細的協助手冊,這裡只簡單的介紹一下。
a) 匯入項目(Import)
首先要把需要進行版本管理的工程(目錄)整理好,去掉不必要的檔案,比如編譯器產生的臨時檔案。然後在最上層檔案夾上單擊右鍵,選擇“TortoiseSVN -> Import...”,輸入要存放的SVN伺服器路徑,確認即可。這樣就將本地的項目匯入到了伺服器上。
命令列:svn import [PATH] URL
b) 檢出項目(Checkout)
項目初次匯入成功後,剛才本地的內容就沒有用了,我們需要建立一個新的工作區,重新從SVN伺服器下載受控的專案檔,執行“TortoiseSVN -> Checkout...”,選擇或者輸入項目的URL,確認即可,以後的工作都應在這個工作區裡進行。
預設是擷取項目的最新版本(HEAD),如果要擷取曆史版本,指定相應的修訂編號(Revision)即可。
命令列:svn checkout URL[@REV]... [PATH]
c) 更新與提交(Update and Commit)
他人修改了項目,我們需要從伺服器下載最新版本,這通過“SVN Update”右鍵菜單實現。
命令列:svn update [PATH...]
如果是自己本地作了修改,則應及時將修改更新到伺服器上去,這通過“SVN Commit...”實現。一個好的習慣是每次提交都應註明修改內容,以方便日後查證。
命令列:svn commit [PATH...]
d) 增加和刪除檔案(Add and Delete)
如果我們要向一個受控項目中添加新檔案或檔案夾,只需在目標上執行“TortoiseSVN -> Add”操作。注意,這裡只是本地添加,要提交到伺服器,還必須執行Commit才行。
命令列:svn add PATH...
同樣,要刪除受控檔案或檔案夾只需執行“TortoiseSVN -> Delete”操作。
命令列:svn delete PATH/URL...
TortoiseSVN還提供了一個重新命名操作“TortoiseSVN -> Rename”,這其實是添加和刪除的組合。
e) 撤銷操作(Revert)
有時候,我們可能進行了錯誤的修改或者增加和刪除,只要未進行提交,我們都可以通過“TortoiseSVN -> Revert”命令來撤銷本地的所有更改。
命令列:svn revert PATH...
f) 查看資訊
SVN提供了幾種資訊查看方式,其中Show log用於顯示每次版本變更的日誌資訊,Repo-brower是倉庫瀏覽器,類似於資源管理員,Revision graph則以圖形化的方式讓我們很直觀的看到版本的變更情況,尤其是對於分支和標籤管理很有協助。
3) 其它操作
a) 衝突解決(Resolved)
如果我們本地進行了修改,而別人又把他的修改提交到了伺服器上,這時我們執行Update就可能出現衝突(Conflict)。Resolved的作用不是解決衝突,它不進行任何合并,而是忽略掉他人的修改,允許我們將自己的版本提交到伺服器上。
簡單的說,Revent是撤銷本地修改,而Resolved是保留本地修改。
b) 清除異常狀態(Cleanup)
如果在執行某個命令的時候出現異常,比如伺服器突然掛了,本地的工作區就會處於一種異常狀態,通過Cleanup能夠清除這種狀態,使工作區不受到影響。
c) 鎖定(Get lock)和解鎖(Release lock)
衝突都是由於不同的開發人員同時修改了同一份檔案造成的,因此,為了避免這種情況,我們可以強行鎖定自己要修改的內容,這樣其他人在我們解鎖前就無法提交其修改。
d) 分支和標籤(Branch/tag)
本文最開始就有說明,分支的目的是為了建立並行的工作線,標籤的作用是為了儲存項目某個版本的快照。二者在實現上卻是一樣的,都是通過Branch/tag命令執行。
e) 匯出(Export)
為了實現版本管理,SVN會在工作區的每個目錄下都產生一個隱藏的.svn檔案夾,而我們有時卻希望得到一個乾淨的沒有.svn檔案夾的項目結構,比如發布軟體時,這種情況下就可以使用Export功能。
f) 重新導向(Relocate)
有時候,SVN伺服器的IP地址可能會發生變動,如果遇到這種情況,我們每個人的本地工作區都要重新下載嗎。不用,只需通過Relocate重新設定一下本地工作區所對應的伺服器位址就可以。
g) 補丁管理(patch)
不要被patch的名稱迷惑,實際上它不屬於SVN版本管理的範疇。這裡所謂的patch是指那些對項目沒有寫入權限(Commit)的人所作的修改,通過“TortoiseSVN -> Create Patch”產生,然後他們採用電子郵件等方式將patch發給專案系統管理員,由管理員執行“TortoiseSVN -> Apply Patch”並確認修改內容後再進行提交。該功能主要用於開源項目的管理。
4. 常見問題集
1). Repository應採用何種目錄組織圖。