总结了一下网上的资源:
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进行比较。
2.如果你不想更新一个大目录树的一部分,你可以利用sticky tag.
二. Branches
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 版本上的。使用分支标签从分支合并所有改变或使用两个静态标签作为合并端点合并都会在合并中将企图的修改传播开。