SVN中trunk,branches,tags用法詳解

Subversion有一個很標準的目錄結構,是這樣的。
比如項目是proj,svn地址爲svn://proj/,那麼標準的svn佈局是

svn://proj/|+-trunk+-branches+-tags
這是一個標準的佈局,trunk爲主開發目錄,branches爲分支開發目錄,tags爲tag存檔目錄(不允許修改)。但是具體這幾個目錄應該如何使用,svn並沒有明確的規範,更多的還是用戶自己的習慣。

對於這幾個開發目錄,一般的使用方法有兩種。我更多的是從軟件產品的角度出發(比如freebsd),因爲互聯網的開發模式是完全不一樣的。 1.第一種方法,使用trunk作爲主要的開發目錄
一般的,我們的所有的開發都是基於trunk進行開發,當一個版本/release開發告一段落(開發、測試、文檔、製作安裝程序、打包等)結束後,代碼處於凍結狀態(人爲規定,可以通過hook來進行管理)。此時應該基於當前凍結的代碼庫,打tag。當下一個版本/階段的開發任務開始,繼續在trunk進行開發。
此時,如果發現了上一個已發行版本(Released Version)有一些bug,或者一些很急迫的功能要求,而正在開發的版本(Developing Version)無法滿足時間要求,這時候就需要在上一個版本上進行修改了。應該基於發行版對應的tag,做相應的分支(branch)進行開發。
例如,剛剛發佈1.0,正在開發2.0,此時要在1.0的基礎上進行bug修正。
按照時間的順序

1.0開發完畢,代碼凍結 
基於已經凍結的trunk,爲release1.0打tag
此時的目錄結構爲
svn://proj/
+trunk/ (freeze)
+branches/
+tags/
+tag_release_1.0 (copy from trunk) 
2.0開始開發,trunk此時爲2.0的開發版 
發現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) 
在1.0 bugfix branch進行1.0 bugfix開發,在trunk進行2.0開發 
在1.0 bugfix 完成之後,基於dev_1.0_bugfix的branch做release等 
根據需要選擇性的把dev_1.0_bugfix這個分支merge回trunk(什麼時候進行這步操作,要根據具體情況) 
這是一種很標準的開發模式,很多的公司都是採用這種模式進行開發的。trunk永遠是開發的主要目錄。

2.第二種方法,在每一個release的branch中進行各自的開發,trunk只做發佈使用。
這種開發模式當中,trunk是不承擔具體開發任務的,一個版本/階段的開發任務在開始的時候,根據已經release的版本做新的開發分支,並且基於這個分支進行開發。還是舉上面的例子,這裏面的時序關係是:

1.0開發,做dev1.0的branch
此時的目錄結構
svn://proj/
+trunk/ (不擔負開發任務 )
+branches/
+dev_1.0 (copy from trunk)
+tags/ 
1.0開發完成,merge dev1.0到trunk
此時的目錄結構
svn://proj/
+trunk/ (merge from branch dev_1.0)
+branches/
+dev_1.0 (開發任務結束,freeze)
+tags/ 
根據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) 
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) 

1.0有bug,直接在dev1.0的分支上修復

==========================================================================

在SVN中Branch/tag在一個功能選項中,在使用中也往往產生混淆。

在實現上,branch和tag,對於svn都是使用copy實現的,所以他們在默認的權限上和一般的目錄沒有區別。至於何時用tag,何時用branch,完全由人主觀的根據規範和需要來選擇,而不是強制的(比如cvs)。

一般情況下,
tag,是用來做一個milestone的,不管是不是release,都是一個可用的版本。這裏,應該是隻讀的。更多的是一個顯示用的,給人一個可讀(readable)的標記。
branch,是用來做並行開發的,這裏的並行是指和trunk進行比較。

比如,3.0開發完成,這個時候要做一個tag,tag_release_3_0,然後基於這個tag做release,比如安裝程序等。trunk進入 3.1的開發,但是3.0發現了bug,那麼就需要基於tag_release_3_0做一個branch,branch_bugfix_3_0,基於這 個branch進行bugfix,等到bugfix結束,做一個tag,tag_release_3_0_1,然後,根據需要決定 branch_bugfix_3_0是否併入trunk。

對於svn還要注意的一點,就是它是全局版本號,其實這個就是一個tag的標記,所以我們經常可以看到,什麼什麼release,基於xxx項目的 2xxxx版本。就是這個意思了。但是,它還明確的給出一個tag的概念,就是因爲這個更加的可讀,畢竟記住tag_release_1_0要比記住一個 很大的版本號容易的多。


branches:分枝
當多個人合作,可能有這樣的情況出現:John突然有個想法,跟原先的設計不太一致,可能是功能的添加或者日誌格式的改進等等,總而言之,這個想法可能需 要花一段時間來完成,而這個過程中,John的一些操作可能會影響Sally的工作,John從現有的狀態單獨出一個project的話,又不能及時得到 Sally對已有代碼做的修正,而且獨立出來的話,John的嘗試成功時,跟原來的合併也存在困難。這時最好的實踐方法是使用branches。 John建立一個自己的branch,然後在裡面實驗,必要的時候從Sally的trunk裏取得更新,或者將自己的階段成果彙集到trunk中。
(svn copy SourceURL/trunk DestinationURL/branchName -m "Creating a private branch of xxxx/trunk." )

 

trunk:主幹
主幹,一般來說就是開發的主要呆的地方,

tag:
在經過了一段時間的開發後,項目到達了一個里程碑階段,你可能想記錄這一階段的代碼的狀態,那麼你就需要給代碼打上標籤。
(svn cp file:///svnroot/mojavescripts/trunk file:///svnroot/mojavescripts/tags/mirrorutils_rel_0_0_1
-m "taged mirrorutils_rel_0_0_1")

另有一說,無所謂誰對誰錯。

trunk:表示開發時版本存放的目錄,即在開發階段的代碼都提交到該目錄上。

branches:表示發布的版本存放的目錄,即項目上線時發布的穩定版本存放在該目錄中。

tags:表示標籤存放的目錄。
在這需要說明下分三個目錄的原因,如果項目分為一期、二期、三期等,那麼一期上線時的穩定版本就應該在一期完成時將代碼copy到branches上,這 樣二期開發的代碼就對一期的代碼沒有影響,如新增的模塊就不會部署到生產環境上。而branches上的穩定的版本就是發布到生產環境上的代碼,如果用戶 使用的過程中發現有bug,則只要在branches上修改該bug,修改完bug後再編譯branches上最新的代碼發布到生產環境即可。tags的 作用是將在branches上修改的bug的代碼合併到trunk上時創建個版本標識,以後branches上修改的bug代碼再合併到trunk上時就 從tags的version到branches最新的version合併到trunk,以保證前期修改的bug代碼不會再合併。

-------------------------------------------------------------------------------------------

一直以來用svn只是當作cvs,也從來沒有仔細看過文檔,直到今天用到,纔去翻看svn book文檔,慚愧

需求一:
有一個客戶想對產品做定製,但是我們並不想修改原有的svn中trunk的代碼。

方法:
用svn建立一個新的branches,從這個branche做為一個新的起點來開發
svn copy svn://server/trunk svn://server/branches/ep -m "init ep"
Tip:
如果你的svn中以前沒有branches這個的目錄,只有trunk這個,你可以用
svn mkdir branches
新建個目錄

需求二:
產品開發已經基本完成,並且通過很嚴格的測試,這時候我們就想發布給客戶使用,發布我們的1.0版本
svn copy svn://server/trunk svn://server/tags/release-1.0 -m "1.0 released"

咦,這個和branches有什麼區別,好像啥區別也沒有?

是的,branches和tags是一樣的,都是目錄,只是我們不會對這個release-1.0的tag做修改了,不再提交了,如果提交那麼就是branches

需求三:
有一天,突然在trunk下的core中發現一個致命的bug,那麼所有的branches一定也一樣了,該怎麼辦?

svn -r 148:149 merge svn://server/trunk branches/ep
其中148和149是兩次修改的版本號。


======================================================================

——簡單的對比

SVN的工作機制在某種程度上就像一顆正在生長的樹:

  • 一棵有樹幹和許多分支的樹
  • 分支從樹幹生長出來,並且細的分支從相對較粗的樹幹中長出
  • 一棵樹可以只有樹幹沒有分支(但是這種情況不會持續很久,隨着樹的成長,肯定會有分支啦,^^
  • 一顆沒有樹幹但是有很多分支的樹看起來更像是地板上的一捆樹枝
  • 如果樹幹患病了,最終分支也會受到影響,然後整棵樹就會死亡
  • 如果分支患病了,你可以剪掉它,然後其他分支還會生長出來的哦!
  • 如果分支生長太快了,對於樹幹它可能會非常沉重,最後整棵樹會垮塌掉
  • 當你感覺你的樹、樹幹或者是分支看起來很漂亮的時候,你可以給它照張相,這樣就就可以記得它在那時是多麼的贊。

——Trunk

Trunk是放置穩定代碼的主要環境,就好像一個汽車工廠,負責將成品的汽車零件組裝在一起。

以下內容將告訴你如何使用SVN trunk

  • 除非你必須處理一些容易且能迅速解決的BUG,或者你必須添加一些無關邏輯的文件(比如媒體文件:圖像,視頻,CSS等等),否則永遠不要在trunk直接做開發
  • 不要因爲特殊的需求而去對先前的版本做太大的改變,如何相關的情況都意味着需要建立一個branch(如下所述)
  • 不要提交一些可能破壞trunk的內容,例如從branch合併
  • 如果你在某些時候偶然間破壞了trunkbring some cake the next day (“with great responsibilities come… huge cakes”)

——Branches

一個branch就是從一個SVN倉庫中的子樹所作的一份普通拷貝。通常情況它的工作類似與UNIX系統上的符號鏈接,但是你一旦在一個SVN branch裏修改了一些文件,並且這些被修改的文件從拷貝過來的源文件獨立發展,就不能這麼認爲了。當一個branch完成了,並且認爲它足夠穩定的時候,它必須合併回它原來的拷貝的地方,也就是說:如果原來是從trunk中拷貝的,就應該回到trunk去,或者合併回它原來拷貝的父級branch

以下內容將告訴你如何使用SVN branches

  • 如果你需要修改你的應用程序,或者爲它開發一個新的特性,請從trunk中創建一個新的branch,然後基於這個新的分支進行開發
  • 除非是因爲必須從一個branch中創建一個新的子branch,否則新的branch必須從trunk創建
  • 當你創建了一個新branch,你應當立即切換過去。如果你沒有這麼做,那你爲什麼要在最初的地方創建這個分支呢?

——Tags

從表面上看,SVN branchesSVN tags沒有什麼差別,但是從概念上來說,它們有許多差別。其實一個SVN tags就是上文所述的爲這棵樹照張相:一個trunk或者一個branch修訂版的命名快照。

以下內容將告訴你如何使用SVN tags

  • 作爲一個開發者,永遠不要切換至、取出,或者向一個SVN tag提交任何內容:一個tag好比某種照片,並不是實實在在的東西,tags只可讀,不可寫。
  • 在特殊或者需要特別注意的環境中,如:生產環境(production)、?(staging)、測試環境(testing)等等,只能從一個修復過的(fixedtagcheckoutupdate,永遠不要commit至一個tag
  • 對於上述提及到的環境,可以創建如下的tags“production”“staging”“testing”等等。你也可以根據軟件版本、項目的成熟程度來命名tag“1.0.3″“stable”“latest”等等。
  • trunk已經穩定,並且可以對外發布,也要相應地重新創建tags,然後再更新相關的環境(production, staging, etc

——工作流樣例

假設你必須添加了一個特性至一個項目,且這個項目是受版本控制的,你差不多需要完成如下幾個步驟:

  1. 使用SVN checkout或者SVN switch從這個項目的trunk獲得一個新的工作拷貝(branch
  2. 使用SVN切換至新的branch
  3. 完成新特性的開發(當然,要做足夠的測試,包括在開始編碼前)
  4. 一旦這個特性完成並且穩定(已提交),並經過你的同事們確認,切換至trunk
  5. 合併你的分支至你的工作拷貝(trunk),並且解決一系列的衝突
  6. 重新檢查合併後的代碼
  7. 如果可能的話,麻煩你的同事對你所編寫、更改的代碼進行一次複查(review
  8. 提交合並後的工作拷貝至trunk
  9. 如果某些部署需要特殊的環境(生成環境等等),請更新相關的tag至你剛剛提交到trunk的修訂版本
  10. 使用SVN update部署至相關環境

發佈了20 篇原創文章 · 獲贊 4 · 訪問量 3萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章