CVS 使用实例
2009-06-05
高宏伟
于哈尔滨市通达街291号
CVS 相信大家已经很熟悉了。本文的目的是想通过一个实例让大家对CVS的用法有一个大致的了解。如果大家在使用过程中有什么问题,可以用QQ或E-Mail与我联系。我的QQ:21807822 E-Mail是dukejoe@163.com。那么我们就闲话少说直入正题吧。我这篇文章基于的环境如下,在阅读本文之前,建议读者至少要熟悉Linux的安装和基本的配置。
操作系统 | RedHat Enterprise Linux 4 (Update 4) |
安装过程注意 |
|
准备两台计算机 | 一台用于安装RedHat Enterprise Linux4 |
首先可以从http://www.nongnu.org/cvs/ 这里下载cvs,或者直接点击这个链接下载cvs-1-11-22.zip (Windows版本二进制文件) cvs-1.11.23.tar.bz2(Linux x86 版本源代码)
安装cvs需要使用root权限。经典的从源代码安装如下:
[root@joerhel4 cvs-1.11.23]# ./configure [root@joerhel4 cvs-1.11.23]# make [root@joerhel4 cvs-1.11.23]# make install |
make install之后,进入/etc/xinetd.d目录,新建一个cvsserver文件,文件内容如下:
service cvspserver { flags = REUSE socket_type = stream wait = no user = root server = /usr/bin/cvs server_args = -f --allow-root=/home/cvs/cvsroot pserver log_on_failure += USERID disable = no } |
cvsserver文件保存后,重启xinetd。命令为
/etc/rc.d/init.d/xinetd restart |
现在我们可以检查一下cvs server是否启动。命令为
[root@joerhel4 xinetd.d]# netstat -lnp|grep 2401 tcp 0 0 0.0.0.0:2401 0.0.0.0:* LISTEN 12394/xinetd [root@joerhel4 xinetd.d]# netstat -l | grep cvs tcp 0 0 *:cvspserver *:* LISTEN [root@joerhel4 xinetd.d]# |
至此CVS的Server端已经安装并成功启动了。下一步我们在Windows上安装一下客户端,CVS的客户端比较常用的是WinCVS和TortoiseCVS。他们都是图形方式的,又直观又方便。所以我也就不多介绍了。很多朋友一般是在使用CVS命令行时遇到问题了。所以下面我就着重介绍一下CVS命令行的使用。刚才高宏伟和大家说过,我们下载了cvs-1-11-22.zip。我们在C盘新建一个cvs目录,把cvs-1-11-22.zip中的cvs.exe解压到这个目录下。然后在“我的电脑”-->“属性”-->“高级”-->“环境变量”的PATH里,加入C:/CVS。然后关闭cmd,再重新打开一个cmd,这时输入cvs,屏幕应该有如下反应,就说明安装正常了。
C:/>cvs Usage: cvs [cvs-options] command [command-options-and-arguments] where cvs-options are -q, -n, etc. (specify --help-options for a list of options) where command is add, admin, etc. (specify --help-commands for a list of commands or --help-synonyms for a list of command synonyms) where command-options-and-arguments depend on the specific command (specify -H followed by a command name for command-specific help) Specify --help to receive this message The Concurrent Versions System (CVS) is a tool for version control. For CVS updates and additional information, see the CVS home page at http://www.cvshome.org/ or the CVSNT home page at http://www.cvsnt.org/ C:/> |
在使用cvs之前,要使用init来RedHat Enterprise Linux 4上创建仓库。以本文为例,我们在/home/cvs目录下建立一个cvsroot目录做为仓库。使用命令cvs -d /home/cvs/cvsroot init 。命令执行后应该在/home/cvs/cvsroot目录下自动新建一个CVSROOT目录,这就说明仓库创建成功了。
在Windows XP的客户端上,我们现在新建一个目录src,假定是我们项目中使用的源代码目录。在目录中我们建立makefile,test1.cpp 两个文件,假定是我们使用的源代码。以我的本机为例就是:D:/working/QA/prj_test1/src,读者如果是和本文一步一步操作下来的话,那最好目录也保持一致,以免产生错误。使用命令行之前,我们先设置一下环境变量CVSROOT,设置CVSROOT的好处就是不需要每次都输入这么一长串的字符。而如果你要想使用其它的CVSROOT时,还可以使用cvs的-d 选项来覆盖。使用cvs的第一件事就是登录login。现在让我们看一下如何登录到刚才我们设置好的仓库上。
D:/working/QA/prj_test1/src>set CVSROOT=:pserver:cvs@192.168.148.129/home/cvs/cvsroot D:/working/QA/prj_test1/src>cvs login Logging in to :pserver:cvs@192.168.148.129:2401/home/cvs/cvsroot CVS password: D:/working/QA/prj_test1/src> |
其中pserver是指我们当前使用的协议,cvs是cvs的登录用户名,192.168.148.129是cvs server的IP地址,/home/cvs/cvsroot是我们刚才创建的仓库路径。
当我们开始做一个项目之前,首先要把他import到我们的cvs server中。cvs提供了几种可能。
- 从无到有,即然是一个新的项目,那可能在建立cvs之初,我们还没有什么像样的源代码需要import到仓库中。
- 很多实际的工作中,我们会发现,当我们开始import新项目时,我们总是已经有一部的源代码。这时我们可以直接把现有的代码import到仓库中。
- 从其它的系统中把项目导入到现在的工程中。这种可能就超出了本文的范围,如果读者有兴趣可以与我联系,我们再共同的深入探讨这个问题。QQ:21807822 e-mail:dukejoe@163.com
好,现在我们cd到D:/working/QA/prj_test1/src目录下,把我们的源代码import到仓库中,命令如下:
D:/working/QA/prj_test1/src>set CVSROOT=:pserver:cvs@192.168.148.129/home/cvs/cvsroot D:/working/QA/prj_test1/src>cvs login Logging in to :pserver:cvs@192.168.148.129:2401/home/cvs/cvsroot CVS password: D:/working/QA/prj_test1/src>cvs import -m "import source by gaohw" src gaohw_vendor gaohw_release N src/makefile N src/test1.cpp No conflicts created by this import D:/working/QA/prj_test1/src> |
-m 是日志消息
src 是仓库(repository) 下的一个目录名。它也可以是一个路径。我们用这个名称来标识不同的源代码集合。
gaohw_vendor 是整个分支的标签。
gaohw_release 是用来识别每次import的,这个要求名称之前从来没有使用过。
import就相当于单位又来了一个新项目。立项之后我们就可以开始软件开发工作了。平时开发时我们最常使用的是update和commit两个命令。比如项目组工作一天后,在下班时会使用commit把当天的工作成果提交到cvs上,第二天早上,测试组会从 cvs上把头一天的源代码使用update命令更新到本地,开始测试。这就是一个比较简单而且很理想的工作流程(当然实际开发中要比这个复杂得多)。
D:/working/QA/prj_test1/src_checkout/src>cvs commit -m "修改1 by 高宏伟" cvs commit: Examining . Checking in test1.cpp; /home/cvs/cvsroot/src/test1.cpp,v <-- test1.cpp new revision: 1.2; previous revision: 1.1 done D:/working/QA/prj_test1/src_checkout/src> |
注意:我开了两个cmd就好像项目组有两个人A和B,先都checkout,然后其中A修改test1.cpp,并commit。在B的目录中执行update,效果如下,我们可以看到B目录中的test1.cpp被更新到最新状态和A的文件是相同的了,这样项目组成员就可以协调步调,保持一致。
D:/working/QA/prj_test1/src_checkout/src>cvs update -P -d -C cvs update: Updating . P test1.cpp D:/working/QA/prj_test1/src_checkout/src> |
现在我们已经import了一些源代码,也有多个人checkout,并在上面做了一些工作,经过不同的人update和commit几次之后,我们可能想看一下,现在源代码的各种情况。那我们应该使用什么命令呢?在这里我们可以使用cvs log 命令来查看文件的日志信息
D:/working/QA/prj_test1/src>cvs log test1.cpp RCS file: /home/cvs/cvsroot/src/test1.cpp,v Working file: test1.cpp head: 1.3 branch: locks: strict access list: symbolic names: gaohw_release: 1.1.1.1 gaohw_vendor: 1.1.1 keyword substitution: kv total revisions: 4; selected revisions: 4 description: ---------------------------- revision 1.3 date: 2009/06/04 07:06:30; author: cvs; state: Exp; lines: +1 -0 修改2 ---------------------------- revision 1.2 date: 2009/06/04 07:00:18; author: cvs; state: Exp; lines: +0 -5 修改1 by 高宏伟 ---------------------------- revision 1.1 date: 2009/06/04 06:29:33; author: cvs; state: Exp; branches: 1.1.1; Initial revision ---------------------------- revision 1.1.1.1 date: 2009/06/04 06:29:33; author: cvs; state: Exp; lines: +0 -0 import source by gaohw ============================================================================= D:/working/QA/prj_test1/src> |
通过log命令的输出,我们就可以看到现在test1.cpp文件的所有日志信息。
在CVS中,版本号的问题也是大家普通比较关心的。我们通过上面log的日志输出,可以看到有类似1.1.1,这样的版本号。所以我们很自然的想到,在我们开发过程中,如果版本号要从1.x变成2.0时,我们是不是也要让CVS里的这个版本号和项目中的版本号进行统一。CVS的官方是这样给我们建议的,CVS中的版本号只做为CVS内部使用,项目中如果要使用版本号,比如发布2.0或其它里程碑,应该尽量使用tag命令,而不是非要强求CVS里显示的版本号统一。官方的这个建议,我个人认为最好还是遵循,毕竟不要自找麻烦嘛,是吧?好了,那我们看一下如何使用tag命令
D:/working/QA/prj_test1>set CVSROOT=:pserver:cvs@192.168.148.129/home/cvs/cvsroot D:/working/QA/prj_test1>cvs login Logging in to :pserver:cvs@192.168.148.129:2401/home/cvs/cvsroot CVS password: D:/working/QA/prj_test1>cvs tag gaohw_release_1_0 src cvs tag: Tagging src T src/makefile T src/test1.cpp D:/working/QA/prj_test1>cvs log cvs log: Logging src RCS file: /home/cvs/cvsroot/src/makefile,v Working file: src/makefile head: 1.1 branch: 1.1.1 locks: strict access list: symbolic names: gaohw_release_1_0: 1.1.1.1 gaohw_release: 1.1.1.1 gaohw_vendor: 1.1.1 keyword substitution: kv total revisions: 2; selected revisions: 2 description: ---------------------------- revision 1.1 date: 2009/06/04 06:29:33; author: cvs; state: Exp; branches: 1.1.1; Initial revision ---------------------------- revision 1.1.1.1 date: 2009/06/04 06:29:33; author: cvs; state: Exp; lines: +0 -0 import source by gaohw ============================================================================= RCS file: /home/cvs/cvsroot/src/test1.cpp,v Working file: src/test1.cpp head: 1.3 branch: locks: strict access list: symbolic names: gaohw_release_1_0: 1.3 gaohw_release: 1.1.1.1 gaohw_vendor: 1.1.1 keyword substitution: kv total revisions: 4; selected revisions: 4 description: ---------------------------- revision 1.3 date: 2009/06/04 07:06:30; author: cvs; state: Exp; lines: +1 -0 修改2 ---------------------------- revision 1.2 date: 2009/06/04 07:00:18; author: cvs; state: Exp; lines: +0 -5 修改1 by 高宏伟 ---------------------------- revision 1.1 date: 2009/06/04 06:29:33; author: cvs; state: Exp; branches: 1.1.1; Initial revision ---------------------------- revision 1.1.1.1 date: 2009/06/04 06:29:33; author: cvs; state: Exp; lines: +0 -0 import source by gaohw ============================================================================= D:/working/QA/prj_test1/src>cvs status -v test1.cpp =================================================================== File: test1.cpp Status: Up-to-date Working revision: 1.3 Repository revision: 1.3 /home/cvs/cvsroot/src/test1.cpp,v Sticky Tag: (none) Sticky Date: (none) Sticky Options: (none) Existing Tags: gaohw_1_0_patches (branch: 1.3.2) gaohw_release_1_1 (revision: 1.3) gaohw_release_1_0 (revision: 1.3) gaohw_release (revision: 1.1.1.1) gaohw_vendor (branch: 1.1.1) D:/working/QA/prj_test1/src> |
当我们要发布产品的1.0时,我们就创建一个名为gaohw_release_1_0的tag,这样。项目组的其它成员再需要使用release 1.0 时,就可以直接checkout gaohw_release_1_0 这个标签,就可以把1.0正式版导出。以此类推,我们要建立里程碑1.5时,就可以再创建一个gaohw_release_1_5,需要使用哪个版本,就以tag名为标准导出。而使用log命令,我们可以在symbolic names这个项目中看到目前已经创建的tag,也就是我们当前使用的各个里程碑。
D:/working/QA/prj_test1>cvs tag -d abc123 src cvs tag: Untagging src D src/makefile D src/test1.cpp D:/working/QA/prj_test1> |
使用cvs tag的 -d 我们可以删除一个错误的tag。有人可能要问了,那如果我不是要删除,只要要重命名一下,那我应该怎么做。其实重命令tag在CVS中,就是创建一个新的tag,然后再删除一个旧的tag。请看下面的实例:
D:/working/QA/prj_test1>cvs tag gaohw_release_1_0_joe src cvs tag: Tagging src T src/makefile T src/test1.cpp D:/working/QA/prj_test1>cvs rtag -r gaohw_release_1_0_joe gaohw_release_1_1 src cvs rtag: Tagging src D:/working/QA/prj_test1>cvs rtag -d gaohw_release_1_0_joe src cvs rtag: Untagging src D:/working/QA/prj_test1> |
这其中我们使用了rtag,rtag和tag的区别是tag要使用本地的工作目录中的副本,而rtag是使用远端仓库中的工作目录。比如最开始我们新建tag时,可能使用的是本地最新的副本,所以我使用了tag,但是后来我是要修改一个tag名,那我根本没必要把这个tag下的所有文件都下载到本地,再new,delelet,我只要对仓库中的tag直接new,delete就可以了。
下面我们要说的一个CVS功能是,创建分支(Branch)。有时我们会遇到这样的情况。项目组正在为4.0做着紧张的开发,突然用户反馈说,3.0版本有问题,而且已经反映到老总那里,老总要求立刻为用户解,项目组先是在现有的代码中找到了BUG,并加以修正,可以现在的4.0还没有稳定,不能发布给用户,这时最好的办法是先checkout出3.0,然后在这个基础上创建分支Branch,3.1,以3.1版本为基础修改BUG,然后以3.0的分支为一个版本发布给用户,解决用户的燃眉之急,倒过手来,我们再在发布4.0时同步修改掉这个BUG。这样即不会搞乱我们现有的4.0的开发任务,又会让用户比较满意。
D:/working/QA/prj_test1> cvs rtag -b -r gaohw_release_3_0 gaohw_release_3_0_patches src cvs rtag: Tagging src D:/working/QA/prj_test1/patches>cvs checkout -r gaohw_release_3_0_patches src cvs checkout: Updating src U src/makefile U src/test1.cpp D:/working/QA/prj_test1/patches> |
至此,我们基本上完成了CVS的大部分常用功能。CVS更多的东西,我们可以参考http://www.nongnu.org/cvs/ 同时,再好的工具也有不能完全的事情,技术是在发展的,但从一个时间点上来看,技术总是有一定的局限性,很多事情除了使用CVS,更多的应该是配合一种管理的理念和工作的经验,才可以使工作更加的高效。非常感谢大家能用这么您宝贵的时间来阅读本文。如果还有什么问题,请大家与我联系QQ:21807822,e-mail: dukejoe@163.com 转载请注明出处为http://blog.donews.com/dukejoe/archive/2009/06/05/1509086.aspx,并保留作者姓名和本句话,谢谢合作