3.在管理中的相关技术
3.1 在管理源文件的一种技术叫"关键字替换".在每次执行"cvs commit"操作后源文件的某些关键字会被替换为可用的词
$AUTHOR$ 用户名
$Data$ 登记时的时间
$Header$ 标准的首部,包含RCS的完整路径名,日期,作者
$Id$ 除RCS文件名不完整外与$Header$同.
$Log$ 包含RCS的完整路径名,版本号,日期,作者和在提交时提供的日志信息.
$RCSfile$ 包含RCS的文件名,不包括路径名
$Revision$ 分配的版本号
$Source$ RCS文件的完整名
$State$ 分配的版本的状态,由 cvs admin -s 分配.
例: 在cvs commit之前,main.c里有
static char *rcsid="$Id$";
执行cvs commit后
main.c的改行变为:
static char *rcsid="$Id: main.c,v 1.2 1999/04/29 15:10:14 trimblef Exp$";
当然,这里只是一个演示.在实际的程序开发中,这种技术有非常有用的作用,在此不多赘述.有兴趣的朋友可参考相关书籍.
3.2 创建分支可以使用户对一些文件使用命令commit进行修改时不会影响主干. 创建分支应首先为拟作修改的那些文件创建一个标签(tag).
标签是赋于一个文件或一组文件的符号.在源代码的生命周期里,组成一组模块的文件被赋于相同的标签.在工作目录中执行
~usr/teat/$cvs tag release-1-0
标签创建后, 就可以为其创建一个分支:
~usr/teat/$cvs rtag -b -r release-1-0 release-1-0-path print
-b :创建分支
-r release-1-0 :指定存在的标签
releas-1-0-patch:分支
print: 模块名
使用cvs update -j 选项可以将分支上的改变与本地文件拷贝合并.
~usr/teat/$cvs update -j release-1-0 print.c
对源文件作必要修改后, 可以用cvs release 删除本地工作拷贝
并通知其他开发者这个模块不再使用.
~use/$cvs release -d test
3.3 冲突解决
在有多个用户对同一个文件进行修改时,如果修改了其中的相同部分,而修改后的内容如果有不同的话,出现冲突是不可避免的。
例如在CVS 文件仓库中有一个文件 test.c ,它的版本是 1.4, 用户A 先检出该文件进行修改,而稍后有用户B 检出该文件进行修改,并提前提交成 1.5,这样在用户A再提交时就会出现冲突,这时CVS会提示需要手工解决。
例如,文件仓库中的版本1.4:内容为:
#include
main()
{
int i;
for(i = 0; i < 100; i++)
printf(“Count: %d
”, i);
}
用户B 1.5:
#include
main()
{
int i;
for(i = 0; i < 10; i++)
printf(“Count: %d
”, i);
printf(“Over
”);
}
用户A :
#include
main()
{
int i;
for(i = 0; i < 50; i++)
printf(“Count: %d
”, i);
return;
}
提交时会提示有冲突,这样需要手工编辑,这时如果用户A运行了$cvs update 之后,再编辑test.c, 会看到test.c 的内容是这样的:
#include
main()
{
int i;
<<<<<<< test.c
for(i = 0; i < 50; i++)
=======
for(i = 0; i < 10; i++)
>>>>>>> 1.5
printf("Count: %d
", i);
<<<<<<< test.c
return;
=======
printf("Over
");
>>>>>>> 1.5
}
这样就需要,根据任务的不同,来手工修改,这是比较麻烦的,所以在真正的协作开发中,很少,对同一个文件给与,很多人相同的提交权限.
3.4 文件版本管理
版本管理系统,最重要的莫过于对文件版本的管理,系统默认的版本升级使用的版本号是一定的.如果由于特殊需要,要自己定义出文件的版本号时,你可以用一下命令:
cvs log [-lR][-r rev][-d date][-w login][files…]
其中,参数的意义如下:
-l 不处理子目录
-R 对子目录做同样处理
-r 指定版本号
-d 指定时间
-w 指定登录名
使用下面的命令可以参看当前模块的版本号或指定文件的所有历史版本信息。
cvs annotate [-lR][-r rev|-D date] files
其中,参数的意义如下:
-l 不处理子目录
-R 对子目录做同样处理
-r 指定版本号
使用下面的命令可以参看指定文件(检出之后)的所有修改信息。
$cvs annotate cvstest/c/test.c
输出依次为:版本 修改人 修改时间 源代码
1.1 (tang 18-Jan-00): #include
1.1 (tang 18-Jan-00): #include
1.1 (tang 18-Jan-00):
1.1 (tang 18-Jan-00): main()
1.1 (tang 18-Jan-00): {
1.1 (tang 18-Jan-00): int i = 0 ;
1.1 (tang 18-Jan-00):
1.1 (tang 18-Jan-00): for(i = 0; i < 20; i++)
1.1 (tang 18-Jan-00): printf("Count: %d
", i);
1.1 (tang 18-Jan-00):
1.3 (tang 18-Jan-00): printf("222222
");
1.4 (tang 18-Jan-00): printf("333333
");
1.1 (tang 18-Jan-00): }
使用下面的命令可以生成相对于一个指定主版本的分支版本:
cvs rtag –b –r rev_root rev_branch file_name
其中,参数的意义如下:
-b 指定生成一个分支版本
-r 指定该分支的主干节点版本号
rev_root 主干版本号
rev_branch 分支版本号
file_name 指定文件,使用“.”表示当前目录下所有文件
使用下面的命令可以生成一个对应版本号的分支版本,由于CVS 版本号是用数字表示的,而且在同一个模块下不同文件的版本完全可能是不同的,所以使用标识会更方便。
例:
$cvs rtag –b –r 1.2 tlb-1 SOURCE
以后要访问该分支版本,可以使用“-r” 选项
$cvs checkout –r tlb-1 SOURCE
从当前检出的版本切换到一个分支版本:
$cvs update –r tlb-1 SOURCE
使用下面的命令可以看版本信息:
cvs status [–vlR] files
其中,参数的意义如下:
-v 显示所有信息
-l 不显示子目录信息
-R 显示子目录信息
命令:cvs update –j rev module 把当前所做的修改与指定版本的文件进行合并。
如:主干 1.1 1.2 1.3 1.4 1.5 1.6 ↓
分支tlb-1 1.2.2.1 1.2.2.2 1.2.2.3
如果要合并分支tlb-1上的版本:
$cvs update –j 1.2.2.3 –j tlb-1 test.c
其中1.2.2.3可以通过tag命令生成一个容易记忆的标识。
如果要合并分支tlb-1到主干上1.2 :
$cvs update –j tlb-1 test.c
如果要合并主干上的不同版本(注意顺序很重要,同时在指定版本之间的所有修改将被丢弃):
$cvs update –j 1.5 –j 1.2 test.c
如果在不同版本之间模块的文件有增减,则可以:
$cvs update –A
$cvs updata –jbranch_name
四、命令集
在本章的例子中,介绍了很多,命令的详细用法,其大多数是以应用的角度,来分析的.实际上.cvs 拥有,大量的命令.如gcc 一样cvs 常用的命令也不是很多,在本节中,我们列出了一些常用的命令.力图不和以上各节中介绍的相重复.当然,限于时间和水平,在此也不可能列出cvs 所有的命令.有兴趣的朋友.可以,参考,cvs的说明文档,与linux 的man文档,详细学习,也可来此做出指导
1.检出源文件
cvs checkout [-r rev][-D date][-d dir][-j merg1] [-j merg2] modules
其中,参数的意义如下:
-r 检出指定版本的模块
-D 检出指定日期的模块
-d 检出指定目录而不是模块
-j 合并当前版本和指定版本
使用下面的命令会检出刚才生成的模块,并在当前目录下生成与文件仓库中完全一样的目录结构:
usr$ cvs checkout project
usr$ cvs checkout project/src/main
cvs checkout的详细用法见cvs -H checkout的输出.
2.CVS commit 命令 在对文件的修改完成后,用cvs commit提交到仓库.
cvs commit -m "Update by xxxxx" project
cvs commit -m "Update main.c" main.c
提交完成后,当前的版本号会更新,如原来为1.1,现为1.2. 这两个版本都在仓库的主干(maintrunk)上.
-m选项可以记录有关提交的注释.如果没有指定-m选项,在环境变量CVSEDITOR中指定的编辑器被调用(vi是缺省的),提示键入文本,修改记录注释.
3.删除、增加、重命名文件和目录
cvs add [-k kflags][-m message] files...
其中,参数的意义如下:
-k 指定以后该文件的缺省检出目录
-m 对文件的描述
上述命令会加入一个新的文件到文件仓库里,但直到使用了提交命令它才会真正更新文件仓库。
cvs remove [options] files
上述命令会从文件仓库中删除文件,但也要到提交之后才有作用。
例1:增加文件
$cvs checkout SOURCE
$cd cvstest/c
$touch test.c
$cvs add test.c
$cvs commit –m “add test.c”
例2:删除文件
$cvs checkout SOURCE
$cd cvstest/c
$rm test.c
$cvs remove test.c
使用 –f 选项能上面两步合做一步。
$cvs remove –f test.c
如果在提交之前想恢复刚才删除的文件,可以如下:
$cvs add test.c
如果只执行了第一步删除(rm),则可以用下面的方法恢复:
$cvs update test.c
对于重命名的文件,可以先删除再添加。
对于目录的修改(重命名),可能需要修改cvs 管理文件,一般应该遵循以下步骤:假设tom正在修改文件的一部分,现想合并更新自己的本地拷贝(checkout)和另一个人所做的修改(已经放在仓库里),可用
~usr/test/$cvs update
确认所有有关的修改都已经提交;
进入文件仓库中要修改的模块目录,对相应的目录进行修改(重命名或删除)
$cd $CVSROOT/modules
$mv old_dir new_dir
如果有必要,修改管理文件,比如modules 文件,如果要删除目录,则应该先对目录中每个文件都进行了删除(包括使用cvs remove )处理之后再执行上面的第2步。
4.提交源文件
cvs commit [-Rl][-m mesg] files
-R 连子目录一起提交
-l 只提交本地目录(不提交子目录)
-m 注释信息
在检出源文件之后,在工作目录中对源文件进行的所有修改都必须在提交之后才能使文件仓库中的源文件起作用,并且新的文件才能够被分配一个新的版本号。
5.释放工作目录
cvs release –d SOURCE
这个命令会删除工作目录 cvstest/c (建议在提交了修改的模块后执行这一步), 它比使用 rm –rf cvstest 要好。
在此介绍了,使用cvs 服务器进行.并行开发中常用的.命令.希望能起一个抛砖引玉的作用
五、小结
本章,介绍了一些版本控制的知识.与几种办控制系统.并从易用的角度,讲述了在linux机器上,构架cvs服务器的过程,与cvs 简单的使用方法
cvs 也可以说是一种网络应用程序.它的功能在于,他能提供在并行的条件下,对多用户同时开发,便利,安全的源码.管理模式.个人认为,cvs的出现是自由的linux的必然产物.
他也会在linux这片热土下,得到更有前途的发展.
本章,旨在易于入手.对于cvs复杂的应用,管理过程.笔者也不是很熟悉.这需要在实际的应用中,积累经验.学习提高.
如果对这部分,有什么见解.欢迎来信指导