一、 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。
2. Branches
2.1 Creating a Branch
Branches can be added to the repository tree in order to allow different development paths to be tried, or to add parallel development of code to different base versions. To create a branch, you can use
cvs tag //需要check out 模块做为当前工作目录
or
cvs rtag //不需要工作目录, 直接远程操作建立branch.
with the -b option.
Do not be fooled! Even though the same commands can be used to create , branches are completely different than tags.
2.1.1 rtag
To create a branch from the main trunk of my_module at the revision that was last committed, use the command
cvs rtag -b Branchname my_module
To create a branch from a tagged revision of my_module, use the command
cvs rtag -r Tagname -b Branchname my_module
Both commands immediately create a branch in the repository without requiring a cvs commit to enact. You do not need to be in a checked-out working directory to do this.
2.1.2 tag
If you are in a working directory, you can create a new branch in the branch or trunk from which you checked out your working directory (not including the changes you've made to your working directory since the last commit) by using the command
Like rtag, the change is immediate, and does not wait for a commit command.
Your working directory remains on the old branch, at a point after the branch you just created. To move your working directory to the new branch, use the command
When you are finished making changes to your working directory, save it as the next revision on the new branch with
2.1.3 Both rtag and tag
Note that both rtag and tag work directly on the repository and take effect immediately without a commit command. Rtag takes effect at the specified place (the end of the main trunk by default), while tag takes effect at the place where the working directory was checked out or last committed.
2.2 Checking Out a Branch to Work On
To check out the latest revision of a branch to work on, use the command
cvs checkout -r Branchname my_module
When you do a cvs commit, the changes are merged in on the branch from which they were checked out.
2.3 General
Note that branch names refer to the latest revision of the branch they are on, not the state they were in when the branch was created.
A tag provides a means to name a certain revision of the code, or take a "snapshot" of it at a certain point in time. This tag only applies a named handle to the code at that point in time, it does not create a new branch of code.
3.1 Creating a Tag
In order to name the current end of the main trunk of a module, use the command
cvs rtag Tagname my_module
In order to name the current end of a branch of a module, use the command
cvs rtag -r Branchname Tagname my_module
Otherwise, to name the code that your working directory was checked out from (without the changes you made to your working directory since the last commit), use the command
3.2 Using a Tagged version of code
You can check out tagged versions of code with the command
cvs checkout -r Tagname my_module
This creates a working directory with the code as it was when the tag was created. While branch names refer to the latest code at the end of a branch (and as such, are dynamic), tag names refer to the static version of code that existed upon the tag's creation. As a result, you cannot commit changes back into the tree at the tagged place that you checked them out from.
If desired, a new branch can be created at the place the tag was applied, then changes can be committed into the new branch as follows:
cvs rtag -r Tagname NewBranchname my_module
cvs update -r NewBranchname
Finish changes to the working directory, then
cvs commit
To access this version of the code again later (along with any changes that were made by others since you last accessed it), use
cvs checkout -r NewBranchname my_module
4. Merging branches
4.1 Using Update
cvs update -j TagOrBranch1 -j TagOrBranch2 my_module
The above command will locate the differences between TagOrBranch1 and TagOrBranch2. Of the lines that are different between them, the lines in TagOrBranch2 will be patched, or merged, into the sources in your working directory.
An annoying problem that I have not yet solved is that new files that appear in TagOrBranch2 but not in TagOrBranch1 do not get created by the merge. The only thing I know of to get these files into the new version is to checkout TagOrBranch2, copy the files into the merged working directory, and do
4.2 Using Checkout
cvs checkout -j TagOrBranch1 -j TagOrBranch2 my_module
The above command will locate the differences between TagOrBranch1 and TagOrBranch2. Of the lines that are different between them, the lines in TagOrBranch2 will be patched, or merged, into the latest revision on the main trunk of my_module.
In order to have these differences merged into a different branch, and then have that branch checked out, use
cvs checkout -r BranchToMergeTo -j TagOrBranch1 -j TagOrBranch2 my_module
Like update, file that were created between TagOrBranch1 and TagOrBranch2 do not get created automatically.
cvs中的branch和tag辨析
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可以创建新的自定义名称。
不知不觉工作已经超过一年多了。在这其中参加了公司很多项目的开发与实施,频繁的使用着CVS这一工具。这篇文章就是想记录一下自己对CVS的一点使用心得,希望可以给刚刚接触这个工具的后来者一点帮助。同时也是抛砖引玉,可以在与大家交流的过程中提高自我。
CVS (Concurrent Version Control System) 是一个能让很多程式开发者同时做软体开发的非常强大工具。对于它可能大部分软件工程师都应该有所接触,起码也是对这个名字如雷贯耳了。CVS的基本命令和使用,网上已经有了很多的教程,我就不再罗嗦。本文想介绍的,可以说是CVS的精华,同时又是对初学者来说很难理解和掌握的(包括当时我也花了很多精力去学习)的两个功能:tag和branch。