1. 程式人生 > >cvs tag與branch區別總結

cvs tag與branch區別總結

總結了一下網上的資源:

branch“分支”指不同需求或功能差異很大的同一系統的不同產品線,每一個新的產品線都可以演化成新的產品,branch一般在產生新的產品線的時候建立。
tag“標記”經過QA人員測試之後的,確認達到要求時才建立的類似歷史記錄的標記,tag是記錄版本歷史的里程碑,tag是不可修改的。

我們checkout時指定版本的branch,可以取出該分支的最新的程式碼,進行修改之後,可以commit回cvs中去。
我們checkout時指定版本的tag,可以取出建立該標記時刻的程式碼,從該tag中取出的程式碼是反映歷史的、不可修改的。

一個系統可以包含多個tag和branch,tag只能屬於某個branch,一個branch可以包含多個tag。

預設的branch是Main,分支Main最新程式碼的tag是預設的Head標籤。新的branch可以建立新的自定義名稱,新的tag可以建立新的自定義名稱。


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

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


    CVS (Concurrent Version Control System) 是一個能讓很多程式開發者同時做軟體開發的非常強大工具。對於它可能大部分軟體工程師都應該有所接觸,起碼也是對這個名字如雷貫耳了。CVS的基本命令和使用,網上已經有了很多的教程,我就不再羅嗦。本文想介紹的,可以說是CVS的精華,同時又是對初學者來說很難理解和掌握的(包括當時我也花了很多精力去學習)的兩個功能:tag和branch。 一、 tag  1.指示你正工作在那個branch上。(因為每個branch都有一個tag.
 2.如果你不想更新一個大目錄樹的一部分,你可以利用sticky tag.     1.1 revision number(修訂號)        要理解tag,首先要介紹一下revision number(修訂號)。在CVS中每個檔案的版本都有一唯一的 revision number。修訂號的形式一般是這樣的:`1.1',`1.2',`1.3.2.2' 甚至是 `1.3.2.2.4.5'。一個修訂號總有偶數個用句號分隔的十進位制數。按照預設,檔案第一個修訂號是 1.1。每個新的修訂號的最右邊的數會比它的上一個修訂號的最右邊的數大 1。下圖顯示了一些修訂號,較新的版本在右邊。             +-----+    +-----+    +-----+    +-----+    +-----+             ! 1.1 ! ----! 1.2 !----! 1.3 !----! 1.4  !----! 1.5 !             +-----+    +-----+    +-----+    +-----+    +-----+      其實,對於大多數 cvs 使用者來說,不需要考慮修訂號;他們只要知道 cvs 已經自動地加上了類似 1.1,1.2 之類的修訂號就可以了。        1.2 tag (標籤)     由於每個檔案都有自己的修訂號,每次提交該檔案一次,它的修訂號就會就會增加。這樣就會產生一個問題:對於軟體的某一個發行版,原始檔的修訂號可能都不一樣。例如:      ci.c            5.21      co.c            5.9      ident.c         5.3      rcs.c           5.12      rcsbase.h       5.11      rcsdiff.c       5.10      rcsedit.c       5.11      rcsfcmp.c       5.9      rcsgen.c        5.10      rcslex.c        5.11      rcsmap.c        5.2      rcsutil.c       5.10     因此,要checkout某一個特定的發行版的所有原始碼的時候,如果是要根據修訂號來的話,是異常繁瑣和難以跟蹤的。這個時候,就要用到CVS提供的很炫的一個功能了:tag(標籤)。        標籤可以用來標記多個檔案的一組修訂號,你可以想象標籤以檔名為橫軸,以版本號為縱軸繪製了一個曲線圖(或者也可以想象成在一個由檔名和版本號組成的矩陣裡面繪製的曲線)。         在過去的某個時候帶 * 的版本號已被標記上標籤。你可以把標籤想象成一條經過所有被標記的檔案的曲線。當你抓住線就得到所有標籤標記的版本了。也可以通過另一種方式來看待這一點:把被同一個標籤標記的所有版本號經過的曲線拉直, 然後直直地看過去。     1.3 tag命令的用法                                                                      下面的例子說明了怎樣給一個檔案新增標籤。命令必須在模組的工作目錄中發出。也就是說,你應該在 backend.c 檔案所在的目錄中發出該命令。      $ cvs tag rel-0-4 backend.c      T backend.c      $ cvs status -v backend.c      ===================================================================      File: backend.c         Status: Up-to-date          Version:            1.4     Tue Dec 1 14:39:01 1992          RCS Version:        1.4     /u/cvsroot/yoyodyne/tc/backend.c,v          Sticky Tag:         (none)          Sticky Date:        (none)          Sticky Options:     (none)          Existing Tags:              rel-0-4                     (revision: 1.4)     很少對單個孤立檔案新增標籤。一種更常見的用法是在產品開發週期中的各個里程碑任務完成後對一個模組的所有檔案新增標籤,比如在發行版完成的時候。      $ cvs tag rel-1-0 .      cvs tag: Tagging .     T Makefile      T backend.c      T driver.c      T frontend.c      T parser.c     (當把一個目錄作為 cvs 的一個引數的時候,該命令不僅對該目錄下的所有檔案執行操作,而且也會遞迴地對該目錄下的所有子目錄中的檔案執行操作。)            如果要檢出一個模組的某個版本,可以使用checkout -r命令。在 checkout 命令中使用 `-r' 標誌可以檢出一個模組某個版本。下面的命令可以很容易地取出模組 `tc' 1.0 發行版的所有原始檔:      $ cvs checkout -r rel-1-0 tc         1.4 什麼時候使用tag         tag的功能就像是給你的工程的某個時刻建立了一個快照。添加了tag後,不論你最原始檔做了任何修改,只要發現你的修改發生了錯誤,或者是如果有人宣稱在某個版本里有個 bug,但你在當前工作的副本中是找不到那個 bug,都可以根據tag重新rollback回去,或checkout出那個快照。         tag給開發人員帶了這樣的便利,因此在任何重要的開發階段,都應該打上tag。         一般性的,在下面的情況都應該考慮給你的工程簡歷一份快照(tag):         完成了某個重要的功能         在每一個milestone         在去掉某個存在功能之前         在測試開始之前         在你對原始檔做重大修改之前         新建分支(branch,下文會詳細談到)的時候         很並分支之前        當然了,這些都是一般性的建議。其實我感覺是隻要你覺得做的修改可能會有副作用的時候,就應該打上tag。

二. Branches

命令為cvs tag 加上-b選項

cvs 允許你把修改隔離在各自的開發線上,這就是分支(branch)。當你改變一個分支中的檔案時,這些更改不會出現在開發主幹(main trunk)和其它分支中。

在這之後你可以使用 merge 把這些變更從一個分支移動到另一個分支(或主幹)。合併首先使用 cvs update -j 命令,將這些變更合併到工作目錄。然後你可以提交這個版本,這樣也可以將這些變更作用於其它的分支。

下面的操作描述約定都以目錄為操作物件。

1. 建立一個分支

使用 tag -b 去建立一個分支;例如,假定你現在有一個工作副本:

 $ cvs tag -b NLP23_BRANCH

這將基於工作副本的當前版本分離出一個分支,並分配 NLP23_BRANCH 名字給該分支。

有一點對理解分支很重要,分支是在 CVS 倉庫中建立,而非在工作副本中建立。正如上面的例子,基於當前版本建立一個分支不會自動把當前的工作副本切換到新的分支上。

$ cvs tag -b -r  rs_1-0-0-0_PD_BL_MAIN  NLP23_BRANCH

這個命令的結果是建立了一個命名為 ` NLP23_BRANCH ' 的新版本分支,它是基於標記為 `rs_1-0-0-0_PD_BL_MAIN' 的基線版本。

2. 檢出與更新分支

你可以通過兩種方式恢復分支:重新從倉庫檢出一份或是從現有的工作副本切換過去。

為了從倉庫檢出一個分支,使用 checkout 命令並帶上 -r 標誌,後面是這個分支的標籤(branchtag)名:

 $ cvs checkout -r NLP23_BRANCH ps/se/rs/


或者如果你已有了一個工作副本,你可以使用 update -r 命令切轉到這個分支: 

  $ cvs update -r NLP23_BRANCH ps/se/rs/


或者使用另一個等效的命令: 

 $ cd ps/se/rs/
  $ cvs update -r NLP23_BRANCH

這對工作副本為主幹程式碼或是其它分支都是有效的 – 上面的命令將把它切換到指名的分支。同 update 命令相類似,update -r 合併你所做的任何改變,通知你出現的衝突。

一旦你的工作副本已經轉向一個特定的分支,它將一直保持在這個分支內,除非你又做了其它的操作。這意味著從這個工作副本提交的變更將加到這個分支的新版本中,而不影響到主幹版本和其它分支。

想看一個工作副本是基於哪一個分支,可以使用 status 命令。在它們輸出中查詢一個 Sticky tag 的域(參閱 Sticky tags) – 那就是 cvs 告訴你當前工作檔案分支號的方式:

     $ cvs status -v rs.h
     ===================================================================
     File: rs.h          Status: Up-to-date

     Version:            1.7     Sat Dec  5 18:25:54 1992
     RCS Version:        1.7    /u/cvsroot/yoyodyne/ps/se/rs/rs.h,v
         Sticky Tag:         NLP23_BRANCH (branch: 1.7.2)
         Sticky Date:        (none)
         Sticky Options:     (none)

         Existing Tags:
             NLP23_BRANCH             (branch: 1.7.2)
             rs_1-0-0-0_PD_BL         (revision: 1.7)

3. 合併一整個分支

你可以把另一個分支上的修改合併到你的工作副本,只要在 update 子命令中加 -j tagname 的標誌。

-j 的意思是“join”。

Consider this revision tree:

    +-----+    +-----+    +-----+    +-----+
     ! 1.1 !----! 1.2 !----! 1.3 !----! 1.4 !      <- The main trunk
     +-----+    +-----+    +-----+    +-----+
                     !
                     !
                     !   +---------+    +---------+
  Branch NLP23_BRANCH -> +---! 1.2.2.1 !----! 1.2.2.2 !
                         +---------+    +---------+
                                              !
                                        rs_1-6-0-0_PD_BL


分支NLP23_BRANCH 的最後版本的tag是rs_1-6-0-0_PD_BL。下面的例子假定模組 ps/se/rs/ 只包含一個檔案 rs.h。 

$ cvs checkout ps/se/rs/        # Retrieve the latest revision, 1.4

$ cvs update -j NLP23_BRANCH     # Merge all changes made on the branch,
                          # i.e. the changes between revision 1.2
                          # and 1.2.2.2, into your working copy
                          # of the file.

$ cvs commit -m "Included NLP23_BRANCH" # Create revision 1.5.

請注意,此操作是把分支上得變化,也就是分支得起點(revision 1.2)版本和分支得終點(revision 1.2.2.2)版本的差異,合併到你的工作副本中,不是將分支得終點(revision 1.2.2.2)版本的所有內容合併到你的工作副本中。

在合併時可能會發生衝突。如果這種情況發生,你應該在提交新版本之前解決它。

cvs合併命令只是工具支援,但不能保證合併後的程式邏輯上的正確性,合併後必須人工從邏輯上確認合併結果。

合併命令執行完後,強烈建議使用 cvs diff 命令檢查合併結果和合入版本(及-j tag中tag指示的版本)的差別,以確保物理合並的完整性。

4. 在檔案新增和刪除的情況下?

如果你在合併時做的改變涉及到新增或刪除一些檔案,update -j 將反映這些變化。

例如:

     cvs update -A
     touch a b c
     cvs add a b c ; cvs ci -m "added" a b c
     cvs tag -b branchtag
     cvs update -r branchtag
     touch d ; cvs add d
     rm a ; cvs rm a
     cvs ci -m "added d, removed a"
     cvs update -A
     cvs update -jbranchtag

在執行這些命令且 cvs commit一完成之後,檔案 a 將被刪除,而檔案 d 將被加入到主分支。

注意使用 update -j tagname 也許行但結果可能不是你想要的。

注意,當用靜態標籤(-j tagname)而不是動態標籤(-j branchname)從一個分支合併改變時,cvs 一般不會刪除檔案,因為 cvs 不會自動給 dead 版本新增靜態標籤。除非靜態標籤是手工新增到 dead 版本上的。使用分支標籤從分支合併所有改變或使用兩個靜態標籤作為合併端點合併都會在合併中將企圖的修改傳播開。