原文:http://www.cnblogs.com/gnuhpc/archive/2012/01/13/2321450.html
作者:gnuhpc
出處:http://www.cnblogs.com/gnuhpc/
本文綜合修改自網上幾篇Blog和自己手頭的資料,原始出處均不詳,如有版權問題請及時與我聯系並提供原始文字鏈接。這里以Windows下客戶端和服務器進行舉例,Linux有對應,原理相同。
一、基本知識:
1.為什么要使用SVN?
· 程序員編寫程序的過程中,每個程序都會生成很多不同的版本.
· 這就需要程序員能有效的管理代碼,在需要的時候可以迅速,准確取出相應的版本
· 任何需要管理頻繁信息改變的地方都需要它,這就是Subversion的舞台
2. Subversion是什么?
· Sub Version(簡稱SVN)是版本管理工具
· Subversion是一個自由/開源版本控制系統
· 一組文件存放在中心版本庫, 記錄每一次文件和目錄的修改
· Subversion可以通過網絡訪問它的版本庫
· 任意數量的客戶端可以連接到版本庫,讀寫這些文件.
· 通過寫,別人可以看到這些信息,通過讀數據,可以看到別人的修改
3.Subversion的特性有哪些?
· 版本化的目錄:Subversion實現了一個可以跟蹤目錄樹更改的“虛擬”版本化文件系統
· 真實的版本歷史:可以新增一個具有干凈歷史的文件
· 原子提交:可以讓用戶構建一個要提交修改的邏輯塊,防止部分修改提交到版本庫
· 版本化的元數據:每一個文件或目錄都有一套屬性—鍵和它們的值
· 可選的網絡層:在版本庫訪問方面有一個抽象概念,利於人們去實現新的網絡機制
· 一致的數據操作:文件是建立在二進制文件區別算法基礎上的
· 有效率的分支和標簽:建立分支與標簽時只是拷貝整個工程,使用了一種類似於硬鏈接的機制
· 可修改性:由一系列良好的共享C庫實現,具有定義良好的API
4.Subversion的原理是什么?
鎖定-解鎖
Subversion主要采用拷貝-修改-合並模型,配合鎖定-解鎖模型管理數據的共享
5.Subversion的基本工作流程是什么?
二、SVN服務器的搭建與配置:
1.啟動:安裝好VisualSVN Server后,運行VisualSVN Server Manger,下面是啟動界面:
2.添加一個代碼庫【Repository】:如下圖:
按上圖所示,創建新的代碼庫,在下圖所示的文本框中輸入代碼庫名稱:
注意:上圖中的CheckBox如果選中,則在代碼庫StartKit下面會創建 trunk、branches、tags三個子目錄;不選中,則只創建空的代碼庫StartKit。
點擊OK按鈕,代碼庫就創建成功了。
3.安全性設置:
在左側的Users上點擊右鍵:
輸入上面的信息,點擊OK,我們就創建一個用戶了。按照上面的過程,分別添加用戶 Developer1、tester1、manager1,好了,我們開始添加這些用戶到我們剛才創建的項目里:
點擊上圖中的"Add..."按鈕,在下圖中選擇我們剛才添加的用戶,點擊OK按鈕:
說明:大家可能注意到了下圖中的Groups,是的,你也可以先創建組,把用戶添加到各個組中,然后對組進行授權,操作比較簡單,在此略過。
按照下圖所示,分別對用戶【或組】進行授權:
點擊"確定"按鈕,上面的用戶就具有了訪問代碼庫的不同權限。
二、SVN客戶端的使用方法——TortoiseSVN的基本使用方法
1.導入源代碼到SVN服務器
假如我們要把項目StartKit的源代碼簽入到SVN Server上的代碼庫中里,首先右鍵點擊StartKit文件夾,這時候的右鍵菜單如下圖所示:
點擊Import,彈出下面的窗體,其中http://zt.net.henu.edu.cn/ 是服務器名,svn是代碼倉庫的根目錄,StartKit是我們在SVN Server上建立的一個代碼庫:
說明:左下角的CheckBox,在第一次簽入源代碼時沒有用,但是,在以后你提交代碼的時候是非常有用的。
點擊OK按鈕,會彈出下面的窗體,要求輸入憑據:
在上面的窗體中輸入用戶名和密碼,點擊OK按鈕:
如上圖所示,好了,源代碼已經成功導入SVN服務器了。這時候團隊成員就可以從SVN服務器上的導出源代碼到自己的機器了。
2遷出源代碼到本機
就是從版本庫中取出某個目錄的拷貝到本機上某個目錄的操作,叫做CheckOut,這個操作是工作的基礎。
在本機創建文件夾,右鍵點擊Checkout,彈出如下圖的窗體:
在上圖中URL of Repository:下的文本框中輸入svn server中的代碼庫的地址,其他默認,點擊OK按鈕,就開始遷出源代碼了。
說明:上圖中的Checkout Depth,有4個選項,分別是遷出全部、只簽出下一級子目錄和文件、只導出文件、只簽出空項目,默認的是第一項。上面的例子中,我們也可以使用web的方式訪問代碼庫,在瀏覽器中輸入http://zt.net.henu.edu.cn/svn/StartKit/
這時候也會彈出對話框,要求輸入用戶名和密碼,通過驗證后即可瀏覽代碼庫中的內容。
打開目錄,可以看到如下圖的文件夾結構:
一旦你對文件或文件夾做了任何修改,那么文件或文件夾的顯示圖片機會發生變化。下圖中我修改了其中的二個文件:
看一下不同狀態所對應的圖片:
3.提交修改過的文件到SVN服務器
例如,修改了位於Model文件中的二個文件ImageInfo.cs和NewsInfo.cs
注意:提交源代碼到服務器時,一定確保本機的代碼是最新版本,否則可能提交失敗,或者造成版本沖突。
在Model文件夾上點擊右鍵或在Model文件下的空白處點擊右鍵,點擊SVN Commit…彈出下面的窗體:
點擊OK按鈕后,彈出如下圖的窗體:
commit的功能不僅僅是上傳,他會和服務器上面的文件進行對比,假如你更新了某個文件而服務器上面也有人更新了這個文件,並且是在你checkout之后做的更新,那么它會嘗試將你的更新和他人的更新進行融合(merge),假如自動 merge不成功,那么報告conflict,你必須自己來手動merge,也就是把你的更新和別人的更新無沖突的寫在一起。commit的時候,最好填寫Log信息,這樣保證別人可以看到你的更新究竟做了寫什么。這就相當於上傳文件並且說明自己做了那些修改,多人合作的時候log非常重要。
4.添加新文件到SVN服務器
假設我們在Model文件下添加一個新的類文件UserInfo.cs,在文件UserInfo.cs上點擊右鍵,點擊TortoiseSVN=>>Add,彈出如下圖的窗體:
選中UserInfo.cs文件,點擊OK按鈕,這樣並沒有將這個文件提交到SVN服務器,只是將這個文件標記為源代碼庫庫中的文件,並將其狀態置為修改狀態。之后,我們要再SVN Commit這個文件一次,才可以將其真正提交到SVN服務器上的代碼庫中。添加文件夾的步驟也是一樣的。
5.更新本機代碼與SVN服務器上最新的版本一致
這個也很簡單,只要在需要更新的文件夾上點擊右鍵或在該文件下的空白處點擊右鍵,點擊SVN Update,就可以了。一般在提交修改之前,必須運行一下update操作來合並別人作出的新更改。
注意:更新操作可能會因為版本沖突而失敗,這是可以使用合並【Merge】或其他方法解決;也可能因為鎖定【Get Lock】而失敗,這是需要先解鎖【Release Lock】。 如果本地的代碼已經被修改,和commit一樣會先進行merge,不成功的話就會報告conflict 。另外需要注意的是,假如別人刪除了某個文件,那么更新之后你在本地的也會被刪除。
6.重命名文件或文件夾,並將修改提交到SVN服務器
只要在需要重命名的文件或文件夾上點擊右鍵,點擊TortiseSVN=>Rename…,在彈出的窗體中輸入新名稱,點擊OK按鈕,就可以了。此方法也不是直接重命名,而是將該文件或文件夾的名稱標記為重命名后名稱,也需要我們使用SVN Commit提交到SVN服務器后才真正重命名。
7.刪除文件或文件夾,並將修改提交到SVN服務器
最簡單就是,你直接刪除文件或文件夾,然后使用SVN Commit提交更新到SVN服務器。另外一種方法是在你要刪除的文件或文件夾上點擊右鍵=>>TortoiseSVN=>> Delete刪除,此方法也不是直接刪除,而是將該文件或文件夾的狀態置為刪除,也需要我們使用SVN Commit提交到SVN服務器后才真正刪除。
8. 如何在同一個在一個工程的各個分支或者主干之間切換
使用tortoise SVN—>switch ,在URL中輸入branch或trunk的url地址。
9.比較兩個版本之間的差別
· 如果你想看到你的本地副本有哪些更加,只用在資源管理器中右鍵菜單下選TortoiseSVN→ 比較差異。
· 如果你想查看主干程序(假如你在分支上開發)有哪些修改或者是某一分支(假如你在主干上開發)有哪些修改,你可以使用右鍵菜單。在你點擊文件的同時按住Shift鍵,然后選擇TortoiseSVN→ URL比較。在彈出的對話框中,將特別顯示將與你本地版本做比較的版本的URL地址。
10. 如何為一個SVN主工程建立分支或tag
分支的基本概念:開發的一條線獨立於另一條線,如果回顧歷史,可以發現兩條線分享共同的歷史,一個分支總是從一個備份開始的,從那里開始,發展自己獨有的歷史。
SVN分支的管理實際上就是把不同的分支用不同的文件保存,因此你在取得新版本的時候會發現,不同分支的最新文件也會被獲取下來。創建tag操作,相當於把當前的代碼版本復制一份到其他地方,然后以這個地方為出發點進行新的開發,與原來位置的版本互不干擾。
· 選擇你要產生分支的文件,點擊鼠標右鍵,選擇[分支/標記...]
· 在[至URL(T)]輸入框中將文件重命名為你的分支文件名,輸入便於區分的日志信息,點擊確認。
· 在SVN倉庫中會復制一個你所指定的文件,文件名稱就是你所命名的,但是在你的本地目錄上看不到新建的分支文件名,要使你的文件更新作用到你的分支上,你必須選擇文件,點擊鼠標右鍵,選擇[切換...],選擇你重命名的文件,點擊確定即可。這樣你的本地文件就和分支文件關聯上了,不要奇怪,這時本地目錄上看到的文件名仍然為舊的文件名。
11.沖突解決
當文件發生沖突時,SVN會額外創建3個不受版本控制的文件,同時被沖突文件如果能夠合並,會在被沖突文件內部留下沖突記錄。例如,沖突的文件為plugin.c,BASE版本是1458,HEAD為1459,會產生3個臨時文件plugin.c.mine,plugin.c.r1458,plugin.c.r1459,
解決思路:A. 手動修改被沖突文件 B. 放棄自己的更改。實際中,解決辦法很靈活,一般需要與他人商量
注意:由於這3個文件是在Update后才創建的,而Update之后,工作拷貝的BASE目錄已經變成更新后的版本了,所以放棄自己的更改會回到新版本。如果不是用Revert的方法解決沖突的話,由於那3個臨時文件留在那里,會使Subversion認為沖突沒有解決,所以要運行resolved告訴SVN沖突解決或者刪除臨時文件。
三、Linux下SVN客戶端的使用:
1.Checkout:
語法:checkout(co) URL[@REV]... [PATH]
可以指明Checkout的版本號,默認CheckOut操作是針對HEAD版本進行的,大多數情況下我們需要HEAD版本,但如果需要歷史版本,可以用-r(--revision)參數或者是用“@版本號”的形式
例:
· … -r 1452 會檢出1452版,如果存在的話
· … -r {“2007-05-05”} 會檢出最接近這個日期的版本
· …/trunk@1452 效果同第1個例子
遞歸與不遞歸,-N:不遞歸(僅針對頂層目錄),否則目錄遞歸(默認,常用)
· 例1:svn co svn://218.94.9.38/svnrepos/skizcorp/trunk 在當前目錄建立一個trunk目錄,里面是工作拷貝
· 例2:svn co svn://localhost/torm I:/PROJECTS/torm 會在I:/PROJECTS/目錄下創建torm目錄,里面存放工作拷貝
2.Update:
語法: update(up) [PATH...]
把版本庫的修改同步到本地的過程是Update。
· 例1:up 直接把工作拷貝更新到最新版(HEAD版)
· 例2:up -r 2007 更新到2007版
· 例3:up doc/design 只更新doc/design下的文件
-r和-N參數仍然有用
Update會修改被更新目錄的BASE版本號。某個文件的BASE版本是指存放在管理目錄.svn中的該文件拷貝的版本,Revert會使該文件回到BASE版本
做Update操作時,SVN會打印出受影響文件的狀態,有以下幾種:
· A Added
· D Deleted
· U Updated
· C Conflict
· G Merged
注意:若提示C,表示沖突,沖突可以用status命令加-u參數來預測
3.Revert:
Revert是指放棄對某個文件的修改,把該文件的內容回復和BASE版本相同,也就是,把該文件的狀態回復到未修改狀態
語法:revert 文件/路徑
例子:
· 例1 revert abc.c 丟棄對abc.c的所有修改
· 例2 revert src/edu/nju/pojo 放棄對此目錄下所有文件的修改
四、注意事項:
1.實際上,從你把源代碼遷簽入SVN服務器開始,每一個版本的數據和文件,就算是你已經刪除了的,也都可以隨時遷出。
2.向SVN服務器提交源代碼的時候,一定不要提交bin、obj 等文件夾,否則會很麻煩。但是web項目的bin目錄除外,但是web項目的bin目錄中的引用其他項目而生成的dll不需要提交。
3.對於第三方庫或程序集,不要簡單從他們的安裝位置引用,而是在你的解決方案下,添加一個Library的目錄,把需要的程序集或者庫文件復制到這里,然后從Library目錄引用。
4.關於checkout和export的區別,當你要發布或編譯的時候,最好采用export,它不會引入svn的附加文件,這樣文件結構顯得比較干凈。而當你需要修改和提交的時候,用checkout,它會在你本地建立一個工作區,Checkout到某處的代碼,將會被 TortoiseSVN監視,里面的文件可以享受各種SVN的服務。
5.假如你需要給帶有綠色對勾文件改名或者移動它的位置,請不要使用windows的功能,右鍵點擊它們,TortoiseSVN都有相應的操作。想象這些文件已經不在是你本地的東西,你的一舉一動都必須讓Tortoise知道:
· 把一個文件加入SVN版本控制,用add命令
· 從版本控制中移除,用delete(rm, remove)命令
· 移動或者重命名,用move(rename)命令
· 拷貝,用copy命令
· 創建目錄,用mkdir命令
· ……
6.假如修改了某個文件但是你后悔了,可以右鍵點擊它選擇Revert,它將變回上次checkout時候的情況,或者Revert整個工程到任意一個從前的版本。
7.使用Commit時注意: 如有多個文件需要同時提交,同時文件在不同的目錄下,必須找到這些文件的最上層目錄上點擊 Commit,TortoiseSVN會搜索被點擊目錄以及該目錄下所有的文件,並將修改變動的文件羅列在列表中。 仔細查看列表中的文件,確定哪些文件時需要更新的,如果不需要更新某個已經變化了的文件,只需要在該文件上點擊右鍵,選擇還原操作;如遇到文件沖突(沖突:要提交的文件已被其他人改動並提交到版本庫中)要啟用解決沖突功能。
8.對於branches、tags、trunk這三個目錄,並不是subversion必需的,而是被總結的一種良好的團隊開發習慣,其使用方法為:
· 開發者提交所有的新特性到主干。 每日的修改提交到/trunk:新特性,bug修正和其他。
· 這個主干被拷貝到“發布”分支。 當小組認為軟件已經做好發布的准備(如,版本1.0)然后/trunk會被拷貝到/branches/1.0。
· 項目組繼續並行工作,一個小組開始對分支進行嚴酷的測試,同時另一個小組在/trunk繼續新的工作(如,准備2.0),如果一個bug在任何一個位置被發現,錯誤修正需要來回運送。然而這個過程有時候也會結束,例如分支已經為發布前的最終測試“停滯”了。
· 分支已經作了標簽並且發布,當測試結束,/branches/1.0作為引用快照已經拷貝到/tags/1.0.0,這個標簽被打包發布給客戶。
· 分支多次維護。當繼續在/trunk上為版本2.0工作,bug修正繼續從/trunk運送到/branches/1.0,如果積累了足夠的 bug修正,管理部門決定發布1.0.1版本:拷貝/branches/1.0到/tags/1.0.1,標簽被打包發布。
· 一般建立最初的repository時,就建好這三個目錄,把所有代碼放入/trunk中,如:要將project1目錄下的代碼導入 repository,project1的結構就是:project1/branches,project1/tags,project1 /trunk,project1/trunk/food.c,project1/trunk/egg.pc……,然后將project1目錄導入 repository,建立最初的資料庫。然后export回project1,作為本地工作目錄。
9.檢驗修改:
· 通過status命令可以檢查工作拷貝的狀態
· 通過diff命令可以檢查更改的內容
10. 關於SVN的開發模式(轉載)
Subversion有一個很標准的目錄結構,是這樣的。
比如項目是proj,svn地址為svn://proj/,那么標准的svn布局是
svn://proj/ | +-trunk +-branches +-tags
這是一個標准的布局,trunk為主開發目錄,branches為分支開發目錄,tags為tag存檔目錄(不允許修改)。但是具體這幾個目錄應該如何使用,svn並沒有明確的規范,更多的還是用戶自己的習慣。
對於這幾個開發目錄,一般的使用方法有兩種。我更多的是從軟件產品的角度出發(比如freebsd),因為互聯網的開發模式是完全不一樣的。
第一種方法,使用trunk作為主要的開發目錄。
一般的,我們的所有的開發都是基於trunk進行開發,當一個版本/release開發告一段落(開發、測試、文檔、制作安裝程序、打包等)結束后,代碼處於凍結狀態(人為規定,可以通過hook來進行管理)。此時應該基於當前凍結的代碼庫,打tag。當下一個版本/階段的開發任務開始,繼續在trunk進行開發。
此時,如果發現了上一個已發行版本(Released Version)有一些bug,或者一些很急迫的功能要求,而正在開發的版本(Developing Version)無法滿足時間要求,這時候就需要在上一個版本上進行修改了。應該基於發行版對應的tag,做相應的分支(branch)進行開發。
例如,剛剛發布1.0,正在開發2.0,此時要在1.0的基礎上進行bug修正。
按照時間的順序
1. 1.0開發完畢,代碼凍結
2. 基於已經凍結的trunk,為release1.0打tag
此時的目錄結構為
svn://proj/
+trunk/ (freeze)
+branches/
+tags/
+tag_release_1.0 (copy from trunk)
3. 2.0開始開發,trunk此時為2.0的開發版
4. 發現1.0有bug,需要修改,基於1.0的tag做branch
此時的目錄結構為
svn://proj/
+trunk/ ( dev 2.0 )
+branches/
+dev_1.0_bugfix (copy from tag/release_1.0)
+tags/
+release_1.0 (copy from trunk)
5. 在1.0 bugfix branch進行1.0 bugfix開發,在trunk進行2.0開發
6. 在1.0 bugfix 完成之后,基於dev_1.0_bugfix的branch做release等
7. 根據需要選擇性的把dev_1.0_bugfix這個分支merge回trunk(什么時候進行這步操作,要根據具體情況)
這是一種很標准的開發模式,很多的公司都是采用這種模式進行開發的。trunk永遠是開發的主要目錄。
第二種方法,在每一個release的branch中進行各自的開發,trunk只做發布使用。
這種開發模式當中,trunk是不承擔具體開發任務的,一個版本/階段的開發任務在開始的時候,根據已經release的版本做新的開發分支,並且基於這個分支進行開發。還是舉上面的例子,這里面的時序關系是。
1. 1.0開發,做dev1.0的branch
此時的目錄結構
svn://proj/
+trunk/ (不擔負開發任務 )
+branches/
+dev_1.0 (copy from trunk)
+tags/
2. 1.0開發完成,merge dev1.0到trunk
此時的目錄結構
svn://proj/
+trunk/ (merge from branch dev_1.0)
+branches/
+dev_1.0 (開發任務結束,freeze)
+tags/
3. 根據trunk做1.0的tag
此時的目錄結構
svn://proj/
+trunk/ (merge from branch dev_1.0)
+branches/
+dev_1.0 (開發任務結束,freeze)
+tags/
+tag_release_1.0 (copy from trunk)
4. 1.0開發,做dev2.0分支
此時的目錄結構
svn://proj/
+trunk/
+branches/
+dev_1.0 (開發任務結束,freeze)
+dev_2.0 (進行2.0開發)
+tags/
+tag_release_1.0 (copy from trunk)
5. 1.0有bug,直接在dev1.0的分支上修復
此時的目錄結構
svn://proj/
+trunk/
+branches/
+dev_1.0 (1.0bugfix)
+dev_2.0 (進行2.0開發)
+tags/
+tag_release_1.0 (copy from trunk)
6. 選擇性的進行代碼merge
這其實是一種分散式的開發,當各個部分相對獨立一些(功能性的),可以開多個dev的分支進行開發,這樣各人/組都不會相互影響。比如dev_2.0_search和dev_2.0_cache等。但是這樣merge起來就是一個很痛苦的事情。
這里要注意一下的,第六步進行選擇性的merge,是可以當2.0開發結束后一起把dev_1.0(bugfix用)和dev_2.0(新版本開發用)merge回trunk。或者先把dev_1.0 merge到dev_2.0,進行測試等之后再merge回trunk。
這兩種方法各有利弊,第一種方法是可以得到一個比較純的dev_2.0的開發分支,而第二種方法則更加的保險,因為要測試嘛。
以上呢,就是我說的兩種開發模式了,具體哪種好,並沒有定論。這里大致的說一下各自的優缺點
第一種開發模式(trunk進行主要開發,集中式):
優點:管理簡單
缺點:當開發的模塊比較多,開發人數/小團隊比較多的時候,很容易產生沖突而影響對方的開發。因為所有的改動都有可能觸碰對方的改動
第二重開發模式(分支進行主要開發,分散式):
優點:各自開發獨立,不容易相互影響。
缺點:管理復雜,merge的時候很麻煩,容易死人。
作者:gnuhpc
出處:http://www.cnblogs.com/gnuhpc/
除非另有聲明,本網站采用知識共享“署名 2.5 中國大陸”許可協議授權。