2007年6月4日星期一

How to use CVS

用CVS来管理自己的程序

cvs服务器端配置/客户端使用
本文在redhat ES2.0 上测试通过)

安装cvs的rpm包后,服务器和客户端就都安装了,首先配置服务器端:

1.查看是否安装cvs
rpm -qa | grep cvs
一般安装在/usr/bin/cvs,如果未安装,到www.cvshome.org下载一个最新的rpm安装即可

2.建立cvs用户组,便于管理cvs用户
groupadd cvs

3.建立cvsroot用户,属于cvs组(组名必须为cvs),根目录为/home/cvsroot,不许登陆
useradd -g cvs -s /sbin/nologin cvsroot

4.改变/home/cvsroot的目录属性
chmod 775 /home/cvsroot

5.初始化cvs源代码库,此操作生成目录/home/cvsroot/CVSROOT,其下为一些初始化文件
cvs -d /home/cvsroot init

6.创建可以登陆cvs服务的用户及密码,需要创建文件passwd
vi /home/cvsroot/CVSROOT/passwd
文件内容如下:
weiqiong:xxxxxx:cvsroot
chenxu:xxxxxx:cvsroot
此文件的意思是weiqiong和chenxu两个用户可以登陆cvs服务器,登陆后其权限为用户cvsroot的权限
注意:cvs用户和服务器用户是可以不一样的

7.xxxxxx为密码,由以下文件生成:
vi /home/cvsroot/passwdgen.pl
文件内容:
#!/usr/bin/perl
srand (time());
my $randletter = "(int (rand (26)) + (int (rand (1) + .5)
% 2 ? 65 : 97))";
my $salt = sprintf ("%c%c", eval $randletter, eval $randletter);

my $plaintext = shift;
my $crypttext = crypt ($plaintext, $salt);
print "${crypttext}
";

8.如果需要密码为:123456,则敲入:
passwdgen.pl "123456"
回车即可得到加密密码,用其替换passwd文件中的xxxxxx

9.加入cvs服务(一般的redhat上缺省就有cvs服务,所以不用加)
vi /etc/services
cvspserver 2401/tcp #pserver cvs service
cvspserver 2401/udp #pserver cvs service

10.一般cvs服务由inted来唤起,因此需要改动inetd提供的服务,如果你的redhat使用的是inetd方式,
则在文件/etc/inetd.conf中加入如下的内容:
cvspserver stream tcp nowait root /usr/bin/cvs cvs --allow-root=/home/cvsroot
pserver

redhat7.3以上使用的是xinetd方式,所以在xinetd.d目录下添加需要启动的服务:
cd /etc/xinetd.d
vi cvspserver
文件内容:
service cvspserver
{
disable = no
flags = REUSE
socket_type = stream
wait = no
user = root
server = /usr/bin/cvs
server_args = -f --allow-root=/home/cvsroot pserver
log_on_failure += USERID
}
11.重新启动inetd或者xinetd:
/etc/rc.d/init.d/xinetd restart

12.检查cvspserver服务是否已经启动
netstat -l |grep cvspserver
应该有如下结果:
tcp 0 0 *:cvspserver *:* LISTEN

---------------------------------------------
以上是服务器端配置,下面是客户端使用。为简便,本例中就在本机上使用,但下列步骤适用于任何cvs客户机。
1.设置系统环境变量(设cvs服务器IP为192.168.0.2,本例中为本机IP)
设置CVSROOT环境变量:
修改~/.bash_profile,加入一行
export CVSROOT=:pserver:weiqiong@192.168.0.2:/home/cvsroot
然后运行命令 . ~/.bash_profile。

2.使用:
cvs login
敲入命令回车后提示输入weiqiong的密码,你按照自己设置的密码输入,如果没有什么错误信息出现就是成功了。

3.导入旧的工程:
假定工程在/root/old/proj1/目录中,则
cd /root/old/proj1
cvs import -m "new project proj1" proj1 vendortag
releasetag
回车,系统会提示工程建立完毕。

4.从cvs服务器上导出cvs工程:
假定要将工程放在/root/new/目录下,则
cd /root/new
cvs co proj1
回车,系统会提示工程顺利导出,出现目录/root/new/proj1,里面的文件就是你要修改的文件。

5.提交文件:
修改/root/new/proj1/a.c后,需要提交修改
cd /root/new/proj1
cvs ci -m "comments here" a.c
回车,系统会提示文件顺利提交。

6.取回新版本文件:
如果自己的/root/new/proj1/a.c取回后,没有修改,但是服务器端的a.c被他人修改了,则需要更新本地拷贝
cd /root/new/proj1
cvs update a.c
回车,系统会提示文件顺利更新。

7.查看文件当前状态:
cd /root/new/proj1
cvs status a.c
回车,系统会显示文件的当前状态。

8.比较文件的新旧版本变化:
如果要比较1.2版和1.3版的区别:
cd /root/new/proj1
cvs diff -r1.2 -r1.3 a.c
回车,系统会显示文件的区别。
如果要比较1.2版和当前版本的区别:
cd /root/new/proj1
cvs diff -r1.2 a.c
回车,系统会显示文件的区别。

9.查看文件被修改的记录:
cd /root/new/proj1
cvs log a.c
回车,系统会显示所有提交过程中-m选项所提交的文字。

10.注意:
cvs服务器上的用户(本文中是cvsroot用户)必须是cvs组的才能用,如果还是报repository找不到,在客户端用户的home目录下touch文件.cvspass,文件是空的,但是当你login一次服务器后自动就有内容了。

CVS服务器快速指南
简介

  CVS 是 Concurrent Version System(并行版本系统)的缩写,用于版本管理.如果大家曾经参与过多人协作开发的项目,大家肯定有这样的痛苦经历:由于多个人同时修改同一个文件,自己辛辛苦苦修改的程序被别人彻底删除了.另外,如果你的软件/程序已经发布了三个版本,而这时候用户需要你修改第二个版本的东西,也许你会因为只保留了最新版本而痛哭流涕。还有就是你对程序做了一些修改,但是修改很少,你只想给远方的同事发一个两个版本之间的差别文件,这样可以免于邮箱不够大,网速太慢之类的问题.为了解决类似这样的问题,以及诸如生成补丁文件,历史版本修改等,一帮黑客(褒义)在原先 Unix 体系里很成熟的 SCCS 和 RCS 的基础上,开发了 CVS。(SCCS:Source Code Control System,RCS:Revision Control System)。

  CVS 的基本工作思路是这样的:在一台服务器上建立一个仓库,仓库里可以存放许多不同项目的源程序。由仓库管理员统一管理这些源程序.这样,就好象只有一个人在修改文件一样.避免了冲突.每个用户在使用仓库之前,首先要把仓库里的项目文件下载到本地。用户做的任何修改首先都是在本地进行,然后用 cvs 命令进行提交,由 cvs 仓库管理员统一 修改.这样就可以做到跟踪文件变化,冲突控制等等。

  由于 CVS 是典型的 C/S 结构的软件,因此它也分成服务器端和客户端两部分。不过大多数CVS 软件都把它们合二为一了。我们这里就分别从服务器和客户端的角度讨论cvs的使用。
Cvs服务器安装

  首先确保系统安装有cvs:

[root@mail xinetd.d]# rpm -qa|grep cvs
cvs-1.11.1p1-3

  如果命令输出类似于上面的输出则说明系统已经安装有cvs,否则就需要从安装光盘中安装cvs的rpm包。

一 创建CVS属主用户:

# useradd -d /cvsroot cvs
# chmod 771 /cv sroot

二、建立CVS仓库(初始化cvs)

# su cvs
$ cvs -d /cvsroot init
$exit
#

三、启动cvs服务器

  在/etc/xinetd.d/目录下创建文件cvspserver,内容如下:

# default: on
# description: The cvs server sessions;

service cvspserver
{
socket_type = stream
wait = no
user = root
server = /usr/bin/cvs
server_args = -f --allow-root=/cvsroot pserver
log_on_failure += USERID
only_from = 192.168.0.0/24
}

  其中only_from是用来限制访问的,可以根据实际情况不要或者修改。

  修改该文件权限:

# chmod 644 cvspserver

  然后重新启动xinetd:

# /etc/rc.d/init.d/xined restart

  然后察看cvs服务器是否已经运行:

[root@mail xinetd.d]# netstat -lnp|grep 2401
tcp 0 0 0.0.0.0:2401 0.0.0.0:* LISTEN 7866/xinetd

  则说明cvs服务器已经运行。

四、创建用来访问cvs的用户

  前面创建的cvs用户是cvs仓库管理用户,而为了让用户访问则还需要一个访问用户:

# useradd cvspub
# usemod -G cvs cvspub

  这里添加了一个用户cvspub,并且将该用户添加到cvs组中。

五、管理cvs服务器

  管理 cvs 服务器.服务器可以用了,现在大家最关心的就是如何管理服务器,比如,我想让一些人有读和/或写 CVS 仓库的权限,但是不想给它系统权限怎么办呢?不难,cvs初始化结束以后,在管理员用户(这里是cvs用户)的主目录里有一个 CVSROOT 目录,这个目录里有三个配置文件:passwd, readers, writers。我们可以通过设置这三个文件来配置 CVS 服务器,下面分别介绍这几个文件的作用:

  passwd:cvs 用户的用户列表文件,它的格式很象 shadow 文件:

{cvs 用户名}:[加密的口令]:[等效系统用户名]

  如果你希望一个用户只是 cvs 用户,而不是系统用户,那么你就要设置这个文件,刚刚安装完之后这个文件可能不存在,你需要以cvs管理员身份(su cvs)用户手工创建,当然要按照上面格式;

  第二个字段是该用户的加密口令,就是用 crypt (3) 加密的,你可以自己写一个程序来做加密,也可以用两个偷懒的方法:先创建一个系统用户,名字和 cvs 用户一样,口令就是准备给它的 cvs 用户口令,创建完之后从 /etc/shadow 把该用户第二个字段拷贝过来,然后再把这个用户删除.这个方法对付数量少的用户比较方便,人一多就不合适了,而且还有冲突条件(race condition)的安全隐患,还要 root 权限,实在不怎么样,不过权益之计而已;另外一个方法就是利用apche的htpasswd命令创建passwd用户,添加用户只需要htpasswd passwd username即可添加用户到passwd文件中,不过需要在文件中对应行的最后添加一个':'冒号和对应的等效系统用户名;最好的就是自己编写一个程序了来生成这个passwd文件了。

  第三个字段就是等效系统用户名,实际上就是赋与一个 cvs 用户一个等效的系统用户的权限,看下面的例子你就明白它的功能了。

  readers:有 cvs 读权限的用户列表文件,就是一个一维列表。在这个文件中的用户对 cvs
只有读权限。

  writers:有 cvs 写权限的用户的列表文件,和 readers 一样,是一个一维列表。在这个文件中的用户对 cvs 有写权限。

  上面三个文件在缺省安装的时候可能都不存在,需要我们自己创建,好吧,现在还是让我们用一个例子来教学吧.假设我们有下面几个用户需要使用 cvs:


cvsuser1, cvsuser2, henry, betty, anonymous

  其中 laser 和 gumpwu 是系统用户,而henry, betty, anonymous 我们都不想给系统用户权限,并且 betty 和 anonymous 都是只读用户,而且 anonymous 更是连口令都没有。

  然后编辑 cvs 管理员家目录里 CVSROOT/passwd 文件,加入下面几行:

laser:$xxefajfka;faffa33:cvspub
gumpwu:$ajfaal;323r0ofeeanv:cvspub
henry:$fajkdpaieje:cvspub
betty:fjkal;ffjieinfn/:cvspub
anonymous::cvspub

  注意:上面的第二个字段(分隔符为 :)是密文口令,你要用程序或者用我的土办法生成。

  编辑 readers 文件,加入下面几行:

anonymous
betty

  编辑 writer 文件,加入下面几行:

laser
gumpwu
henry

  这样就 ok 了,你再用几个用户分别登陆测试,就会发现一切都 ok 了。这里面的原理和说明我想就不多说了,其实很简单,和系统管理用户的概念是一样的。

六、建立新的CVS项目

  一般我们都已经有一个或多个项目了,这样我们可以用下面步骤生成一个新的CVS项目。

  将一个工程文件置于CVs中进行版本控制,在CVS 术语中称作导入(import)。从名字上就可以看出,在导入前需要为此作些准备工作。

  输入操作的基本要求是有个'干净'的目录结构。'干净'的意思是不需要版本控制的文件都被移走了(如编译生成的文件,备份文件等等)。如果工程已经开始一段时间了,这就显得很重要。在目录中也许有些是不打算将其置于版本控制下的文件,但是又想将他们放在这里,这种情况下,你要在输入之前将它们移走,然后再移回来。

  注意的是CVS 认为空目录是不存在的。如果想增加一个既不包含文件又不包含子目录的目录,需要在其下创建一个哑文件。建议你创建一个名为 README.txt 的文件,其内容为对目录的简要说明。

  进入到已有项目的目录,比如叫 cvstest:

$cd cvstest

  运行命令将项目文件导入到cvs仓库中:

$cvs import -m 'this is a cvstest project' cvstest v_0_0_1 start

  说明:import 是cvs的命令之一,表示向cvs仓库输入项目文件.

  -m参数后面的字串是描述文本,对项目进行描述,如果不加 -m 参数,那么cvs会自动运行一个编辑器(一般是vi,但是可以通过修改环境变量EDITOR来改成你喜欢用的编辑器)让你输入信息,

  cvstest 是项目名称(实际上是仓库名,在CVS服务器上会存储在以这个名字命名的仓库里)

  v_0_0_1是这个分支的总标记.没啥用(或曰不常用)

  start 是每次 import 标识文件的输入层次的标记,没啥用。

  这样我们就建立了一个CVS仓库了,然后,我们可以把这个测试项目的文件删除,试验如何从仓库获取文件这会在后面的客户端文章进行说明。

  该文章借鉴了何伟平先生的很多内容,在此表示感谢!

发一个修正以后的CVS服务器配置步骤
今天配置CVS服务器得时候,才突然发现一个问题,在本论坛精华区里面的CVS服务器配置过程有一个错误!!居然没有人发现?!

重新写一下CVS服务器的配置过程:


* 检查 /etc/services
首先键入 vi /etc/services
然后键入 /cvspserver
如果找到的行前面并没有#,那么就不用修改了,否则去掉行首的#

* 在 /etc/xinetd.d 目录下创建一个文件,随便命名,比如 cvs
vi /etc/xinetd.d/cvs
在其中添上
引用:

service cvspserver
{
socket_type = stream
wait = no
user = root
env = HOME=
server = /usr/bin/cvs
# 以下配置选项是错误的,错误之处用红色标记
# server-tags = --allow-root=/home/cvsroot pserver
server_args = --allow-root=/home/cvsroot pserver
}


* 保存以后创建一个名为 cvs 的组和一个名为 cvsroot 的用户
groupadd cvs
useradd -g cvs -s /sbin/nologin cvsroot

* 然后
vi /etc/profile
在其中添上
export CVSROOT = /home/cvsroot

* 重启 xinetd:
/etc/init.d/xinetd restart

* 初始化CVS仓库
cvs -d /home/cvsroot init

这样CVS就可以用了



如果不修改以上的错误,就会在cvs login的时候出现:cvs [login aborted]: unrecognized auth response from localhost: Usage: cvs [cvs-options] command [command-options-and-arguments] 这样的错误提示。

使用提示:
* 添加仓库: 进入到你的源码目录
cd /your/sources/path
然后执行
cvs export SOURCE_DIR_NAME Author Version
其中的SOURCE_DIR_NAME 就是你的工程在 CVSROOT 目录中保存的目录名, Author 为工程作者, Version 为你的工程发行版本号,必须以字母开头

* 添加匿名只读用户:
useradd -g cvs -M -s /sbin/nologin anonymous
chmod 644 /home/cvsroot/CVSROOT/passwd
echo "anonymous::anonymous" >> /home/cvsroot/CVSROOT/passwd
chmod 444 /home/cvsroot/CVSROOT/passwd
echo "anonymous" >> /home/cvsroot/CVSROOT/readers
chmod 444 /home/cvsroot/readers

* 防止CVSROOT被下载:
chmod 644 /home/cvsroot/CVSROOT/modules
echo "CVSROOT -a" >> /home/cvsroot/CVSROOT/modules
chmod 444 /home/cvsroot/CVSROOT/modules

* 不使用 real system user 登陆:
chmod 644 $CVSROOT/CVSROOT/config
vi $CVSROOT/CVSROOT/config
将第二行的
#SystemAuth = no
去掉注释,即改为
SystemAuth = no



以上内容在RedHat ES 3 U2上测试通过

CVS 速成班
结合文档和一些网上资源,折腾了半天终于搞定了CVS,我写一点非常简单的"速成"
的教材.希望对大家有用. 

下面是我的步骤和做法. 

1,要求: 

root 权限; 
CVS软件,请找到相关的rpm,tgz,deb 等包装上,或者到

http://www.cvshome.org/CVS/Dev/code 
下载原程序编译安装,饫镂也蛔急附樯芩陌沧埃氩慰糃VS自身的文档安装.
我使用Slackware的tgz包,安装的命令是 
#installpkg cvs*.tgz 
其他包请参考对应包管理工具的命令. 
一定的系统资源,要有一定内存(32M就能工作得很好),要一定的磁盘空间,看
你的项目的大小和多少而定. 
2,架设CVS服务器: 
建立CVSROOT目录,因为这里涉及到用户对CVSROOT里的文件读写的权限问题,
所以比较简单的方法是建立一个组,然后再建立一个属于该组的帐户,而且以后有
读写权限的用户都要属于该组.假设我们建一个组cvs,用户名cvsroot.建组和用
户的命令如下 
#groupadd cvs 
#adduser cvsroot
生成的用户家目录在/home/cvsroot(根据自己的系统调整) 
用cvsroot用户登陆,修改 /home/cvsroot (CVSROOT)的权限,赋与同组人有读写
的权限: 
$chmod 771 . (或者770应该也可以) 
注意:这一部分工作是按照文档说明做的,是否一定需要这样没有试验,我
会在做试验后在以后版本的教程说得仔细一点.如果您有这方面的经验请提
供给我,谢谢. 
建立CVS仓库,(仍然是cvsroot用户),用下面命令: 
$cvs    -d /home/cvsroot init
以root身份登陆,修改/etc/inetd.conf 和 /etc/services,分别加入下面一行: 
在 /etc/inetd.conf 里加入: 
cvsserver    stream    tcp    nowait    root    /usr/bin/cvs    cvs --allow-root=/home/cvsroot pserver 
说明:上面的行是单独一整行,/usr/bin/cvs 应该是你的cvs版本的命令路径,
请根据自己的系统调整./home/cvsroot 是你建立的CVSROOT的路径,也请
根据上面建立目录的部分的内容做调整. 

在/etc/services里加入: 
cvsserver    2401/tcp 

说明:cvsserver是任意的名称,但是不能和已有的服务重名,也要和上面修
改/etc/inetd.conf那行的第一项一致.这里我用的是CVS的口令认证方式,
CVS还有其他认证方式,我没有做试验,如果您有经验,请补充,谢谢. 
 

添加可以使用CVS服务的用户到cvs组: 
以root身份修改/etc/group,把需要使用CVS的用户名加到cvs组里,比如我想
让用户laser和gumpwu能够使用CVS服务,那么修改以后的/etc/group应该有下
面这样一行: 
cvs:x:105:laser,gumpwu 
在你的系统上GID可能不是105,没有关系.主要是要把laser和gumpwu用逗号
分隔开写在最后一个冒号后面.当然,象RedHat等分发版有类似linuxconf这样
的工具的话,用工具做这件事会更简单些.
重起inetd使修改生效: 
#killall -HUP inetd
这样服务器就设置完成了.我们接着搞客户端. 
3,设置客户端,如果是Linux(或者其他*nix),客户端和服务器端的软件是一样的,如果是
Win,MAC等平台,请到http://www.loria.fr/cgi-bin/molli/wilma.cgi/rel 找相应的客户端软件,
这里我先说一下在Linux(*nix)里怎么做: 

设置环境变量CVSROOT: 
$export CVSROOT=:pserver:laser@the_server_name:

/home/cvsroot 
注意:这里的pserver是访问方式,我在上面设置的是口令认证,所以这里是
pserver,如果你的CVS服务器设置成别的访问模式,那么需要相应修改.
laser是可以使用 CVS服务器的用户名,这里可以根据你的设置修改,我在这
个版本设置的是直接使用系统用户的口令文件,也就是说laser必须是CVS服
务器上的合法用户,这里当然有安全问题,CVS可以设置成为拥有自己的用户,
我将在以后的版本里面增加这些内容,或者您也可以提供一些补充,或者直接
读CVS的文档.the_server_name是CVS服务器的名称或者IP地址,根据你的情
况填写,/home/cvsroot是你的CVS服务器的CVSROOT目录,根据你的CVS服务
器设置做修改或者询问管理员.你可以把这行放到你的shell的profile里
(.bash_profile,.profile等)这样就不用每次敲一长串命令了. 
 

登陆CVS服务器: 
$cvs login,这时候cvs会问你口令,请把你在CVS服务器上的口令敲进去,这里
是laser在CVS服务器上的系统用户的口令: 
 Passwd:xxxxxxxx 
成功登陆后将在你的家目录建立一个.cvspass文件,以后就不用输入口令了.
好,客户端设置完成,简单吧. 
现在服务器和客户端都设置好了,那么怎么用呢,我在这里写一个最简单的(估计也是最常用
的)命令介绍: 
首先,建立一个新的CVS项目,一般我们都已经有一些项目文件了,这样我们可以用下面步骤
生成一个新的CVS项目: 

进入到你的已有项目的目录,比如叫cvstest: 
$cd  cvstest
运行命令: 
$cvs import -m "this is a cvstest project" cvstest     v_0_0_1     start 
说明:import 是cvs的命令之一,表示向cvs仓库输入项目文件. 
              -m参数后面的字串是描述文本,随便写些有意义的东西,如果不加 -m 参
数,那么cvs会自动运行一个编辑器(一般是vi,但是可以通过修改环境变量
EDITOR来改成你喜欢用的编辑器.)让你输入信息, 
             cvstest 是项目名称(实际上是仓库名,在CVS服务器上会存储在以这个名字
命名的仓库里.) 
             v_0_0_1是这个分支的总标记.没啥用(或曰不常用.) 
             start 是每次 import 标识文件的输入层次的标记,没啥用.
这样我们就建立了一个CVS仓库了,然后,我们可以把这个测试项目的文件删除.试验一下如何
从仓库获取文件.这里我假设上面的所有客户端工作你都已经做过了. 
运行下面的命令: 
   $cvs checkout cvstest
从仓库中检索出cvstest项目的源文件. 
如果你已经做过一次checkout了,那么不需要重新checkout,只需要进入cvstest项目的目录,更新
一把就行了: 
$cd cvstest 
$cvs update
一下即可.又或者你不想直接更新,只是想看看有没有更新的东西,那么: 
$cvs status
这时后会打印出一长串状态报告(你可能需要用类似less这样的命令分页显示,或者定向到一个输
出文件里慢慢看.),对项目中的每个文件有一份状态报告,类似这样:

================================================ 
File: foo.c             Status: Up-to-date 
   Working revision:    1.1.1.1 'Some Date' 
   Repository revision: 1.2     /home/cvsroot/cvstest/foo.c,v 
   Sticky Tag:          (none) 
   Sticky Date:         (none) 
   Sticky Options:      (none) 

这里最重要的就是 Status 栏,这里总共可能有四种状态: 
Up-to-date:表明你要到的文件是最新的. 
Locally Modified:表明你曾经修改过该文件,但还没有提交,你的版本比仓库里的新. 
Needing Patch:表明有个哥们已经修改过该文件并且已经提交了!你的版本比仓库里的旧. 
Needs Merge:表明你曾经修改国该文件,但是偏偏有个不识相的也修改了这个文件,而且还提交
给仓库了! 

如果你只是想保持软件的同步的话(象我),那么上面的东西就足够用了.可是如果多人协作开发
项目的话,可就不是了这么简单了.当你参加项目,维护文件时,就需要更多命令,比如说你我都
是某nasdaq项目的开发人员: 

1,你对某个文件做了修改,比如说改了ceo.c,加了一行程序:printf("where can I find VC to cheat!"); 
改完之后你要把修改提交给仓库,用命令: 
$cvs commit -m "add a complain" ceo.c 
或者就是: 
$cvs commit -m "worry about money" 
让cvs帮你检查哪个文件需要提交. 

2,当我开始干活的时候,可能我先: 
$cvs status 
一把,这时候我会看到: 

=============================================== 
File: ceo.c             Status: Needing Patch 

   Working revision:    1.1.1.1 'Some Date' 
   Repository revision: 1.2     /home/cvsroot/nastaq/ceo.c,v 
   Sticky Tag:          (none) 
   Sticky Date:         (none) 
   Sticky Options:      (none) 

于是我知道有人改了ceo.c,于是我就: 
$cvs update ceo.c 
或者干脆: 
$cvs update 
把ceo.c这个文件更新为最新版本,然后再干活.然后提交. 

如果这天你修改了coo.c,加了一行 puts("how about another kind of bragging?"); 
并且提交了,但是这时候我已经 $cvs status 过了,就是说我不知道你的修改. 
而我加了一行printf("You must shamelessly and seems knowingness to act as a coo"); 
并且傻乎乎地提交: 
$cvs commit coo.c 
这时候,CVS会告诉我 
cvs commit: Examing . 
cvs server: Up-to-date check failed for 'coo.c' 
cvs [server aborted]: correct above error first! 

于是我知道有个狗屎在我修改文件的当口做了提交,于是我 
$cvs update 
这时cvs会报告: 
RCS file: /home/cvsroot/nasdaq/coo.c,v 
retrieving revision 1.1.1.1 
retrieving revision 1.2 
Merging differences between 1.1.1.1 and 1.2 into coo.c 
rcsmerge: warning: conflicts during merge 
cvs update: conflicts found in coo.c 
C coo.c 
告诉你coo.c有版本冲突,于是我编辑coo.c,这时一般文件里看起来象这样: 
  ... 
printf("You must shamelessly and seems knowingness to act as a coo"); 
<<<<<<< foo.c 
======= 
... 
  puts("how about another kind of bragging?"); 
>>>>>>> 1.2 
... 

于是我把上面改成: 
printf("You must shamelessly and seems knowingness to act as a coo"); 
puts("how about another kind of bragging?"); 
然后 
$cvs commit -m "merged" coo.c 
于是下回你再更新的时候就有新的补钉要打...如此往复,直到完成所有修改. 
不过这里有一些要注意的地方就是删除程序,如果你删掉一行对你可能没有用的程序 
puts("to be honest"); 而我不想删除(因为我有用),而我不知情地直接: 
$cvs update 
了,那么我的这行程序也完蛋了,所以这里我们要注意所有开发人员的协调,千万不要 
乱删东西,大不了用 
#if    0 
#endif 
宏定义对括起来.实在要删东西,那最好先标记一个版本: 
$cvs tag v_0_0_1 

然后你可以发布并删除你自己的工作目录里这个版本的文件(注意:不是删除仓库里的.): 

$cvs release -d nasdaq 

然后你再生成一个新分支: 

$cvs rtag -b -r v_0_0_1 v_0_0_1_1 nasdaq 

然后再建立v_0_0_1_1的分支 

$cvs checkout -r v_0_0_1_1 nasdaq 

编辑并修改这个分支的文件,这样的做法比较好. 

还有一些命令,比如要增加一个文件 garbage_china_concept_stocks_list: 

$cvs add garbage_china_concept_stocks_list 

然后还要: 

$cvs commit  garbage_china_concert_stocks_list 

看起来有点象数据库里的事务?的确是这样.CVS维护着一个本地的参考文件(在CVS/Entries里),
这样提交的时候就可以一次地把所有改变放到服务器端,这样也更安全. 
同样,如果想删除文件 bankrupted_web_site: 

$rm bankrupted_web_site 
$cvs remove bankrupted_web_site 
$cvs commit bankrupted_web_site 
  

好了,上面所有的东西,估计就是我们用cvs时80%情况下用的命令和内容,包括文件的更新,提
交,冲突的解决,分支的派生,增删文件等.实际上cvs的功能之强大,远远超出我在这里描述的
内容,我这个"速成"也就管不了太多了,希望随着时间的推移,我们能够更加有效地使用CVS.
也希望大家能够不断补充这篇文章,最后能够成为手册,而不仅仅是速成.当然,还要更多地参考
别的文档. 

参考资料: 
http://www.loria.fr/cgi-bin/molli/wilma.cgi/doc.865331095.html 
http://www.loria.fr/~molli/cvs/doc/cvs_toc.html 

CVS的常用命令速查手册

最后更新:2002-12-22 00:24:36

版权声明:可以任意转载,转载时请务必标明原始出处和作者信息

关键词:CVS CVSWeb CVSTrac WinCVS CVSROOT

内容摘要:

CVS是一个C/S系统,多个开发人员通过一个中心版本控制系统来记录文件版本,从而达到保证文件同步哪康摹9ぷ髂J饺缦拢?br />
CVS服务器(文件版本库)
/ |
(版 本 同 步)
/ |
开发者1 开发者2 开发者3

开发人员入门可以主要挑选2,6看就可以了,CVS的管理员则更需要懂的更多一些,最后还简单介绍了一些Windows下的cvs客户端使用,远程用户认证的选择,及与BUG跟踪系统等开发环境的集成问题。

1. CVS环境初始化:CVS环境的搭建 管理员
2. CVS的日常使用:日常开发中最常用的CVS命令, 开发人员 管理员
3. CVS的分支开发:项目按照不同进度和目标并发进行 管理员
4. CVS的用户认证:通过SSH的远程用户认证,安全,简单 管理员
5. CVSWEB:CVS的WEB访问界面大大提高代码版本比较的效率 管理员
6. CVS TAG:将$Header$加入代码注释中,方便开发过程的跟踪 开发人员
7. CVS vs VSS: CVS和Virsual SourceSafe的比较 开发人员 管理员
8. WinCVS: 通过SSH认证的WinCVS认证设置
9. CVS的小组协同开发:开发组级的开发环境搭建,通过CVSTrac实现web界面的CVS用户管理及集成的BUG跟踪和WIKI交流。

一个系统20%的功能往往能够满足80%的需求,CVS也不例外,以下是CVS最常用的功能,可能还不到它全部命令选项的20%,更多的功能在实际应用过程中体会,你想用多少就学多少,不时回头看看经常有意外的收获。


CVS环境初始化
============

环境设置:指定CVS库的路径CVSROOT
tcsh
setenv CVSROOT /path/to/cvsroot
bash
CVSROOT=/path/to/cvsroot ; export CVSROOT

后面还提到远程CVS服务器的设置:
CVSROOT=:ext:$USER@test.server.address#port:/path/to/cvsroot CVS_RSH=ssh; export CVSROOT CVS_RSH

初始化:CVS版本库的初始化。
cvs init

一个项目的首次导入
cvs import -m "write some comments here" project_name vendor_tag release_tag
执行后:会将所有源文件及目录导入到/path/to/cvsroot/project_name目录下
vender_tag: 开发商标记
release_tag: 版本发布标记

项目导出:将代码从CVS库里导出
cvs checkout project_name
cvs 将创建project_name目录,并将最新版本的源代码导出到相应目录中。这个checkout和Virvual SourceSafe中的check out不是一个概念,相对于Virvual SourceSafe的check out是cvs update, check in是cvs commit。

CVS的日常使用
=============

注意:第一次导出以后,就不是通过cvs checkout来同步文件了,而是要进入刚才cvs checkout project_name导出的project_name目录下进行具体文件的版本同步(添加,修改,删除)操作。

将文件同步到最新的版本
cvs update
不制定文件名,cvs将同步所有子目录下的文件,也可以制定某个文件名/目录进行同步
cvs update file_name
最好每天开始工作前或将自己的工作导入到CVS库里前都要做一次,并养成“先同步 后修改”的习惯,和Virvual SourceSafe不同,CVS里没有文件锁定的概念,所有的冲突是在commit之前解决,如果你修改过程中,有其他人修改并commit到了CVS库中,CVS会通知你文件冲突,并自动将冲突部分用
>>>>>>
content on cvs server
<<<<<<
content in your file
>>>>>>
标记出来,由你确认冲突内容的取舍。
版本冲突一般是在多个人修改一个文件造成的,但这种项目管理上的问题不应该指望由CVS来解决。

确认修改写入到CVS库里
cvs commit -m "write some comments here" file_name

注意:CVS的很多动作都是通过cvs commit进行最后确认并修改的,最好每次只修改一个文件。在确认的前,还需要用户填写修改注释,以帮助其他开发人员了解修改的原因。如果不用写-m "comments"而直接确认`cvs commit file_name` 的话,cvs会自动调用系统缺省的文字编辑器(一般是vi)要求你写入注释。
注释的质量很重要:所以不仅必须要写,而且必须写一些比较有意义的内容:以方便其他开发人员能够很好的理解
不好的注释,很难让其他的开发人员快速的理解:比如: -m "bug fixed" 甚至 -m ""
好的注释,甚至可以用中文: -m "在用户注册过程中加入了Email地址校验"

修改某个版本注释:每次只确认一个文件到CVS库里是一个很好的习惯,但难免有时候忘了指定文件名,把多个文件以同样注释commit到CVS库里了,以下命令可以允许你修改某个文件某个版本的注释:
cvs admin -m 1.3:"write some comments here" file_name

添加文件
创建好新文件后,比如:touch new_file
cvs add new_file
注意:对于图片,Word文档等非纯文本的项目,需要使用cvs add -b选项按2进制文件方式导入,否则有可能出现文件被破坏的情况
比如:
cvs add -b new_file.gif
cvs add -b readme.doc

然后确认修改并注释
cvs ci -m "write some comments here"

删除文件
将某个源文件物理删除后,比如:rm file_name
cvs rm file_name
然后确认修改并注释
cvs ci -m "write some comments here"
以上面前2步合并的方法为:
cvs rm -f file_name
cvs ci -m "why delete file"
注意:很多cvs命令都有缩写形式:commit=>ci; update=>up; checkout=>co/get; remove=>rm;

添加目录
cvs add dir_name

查看修改历史
cvs log file_name
cvs history file_name

查看当前文件不同版本的区别
cvs diff -r1.3 -r1.5 file_name
查看当前文件(可能已经修改了)和库中相应文件的区别
cvs diff file_name
cvs的web界面提供了更方便的定位文件修改和比较版本区别的方法,具体安装设置请看后面的cvsweb使用

正确的通过CVS恢复旧版本的方法:
如果用cvs update -r1.2 file.name
这个命令是给file.name加一个STICK TAG: "1.2" ,虽然你的本意只是想将它恢复到1.2版本
正确的恢复版本的方法是:cvs update -p -r1.2 file_name >file_name
如果不小心已经加成STICK TAG的话:用cvs update -A 解决

移动文件/文件重命名
cvs里没有cvs move或cvs rename,因为这两个操作是可以由先cvs remove old_file_name,然后cvs add new_file_name实现的。

删除/移动目录
最方便的方法是让管理员直接移动,删除CVSROOT里相应目录(因为CVS一个项目下的子目录都是独立的,移动到$CVSROOT目录下都可以作为新的独立项目:好比一颗树,其实砍下任意一枝都能独立存活),对目录进行了修改后,要求其开发人员重新导出项目cvs checkout project_name 或者用cvs update -dP同步。

项目发布导出不带CVS目录的源文件
做开发的时候你可能注意到了,每个开发目录下,CVS都创建了一个CVS/目录。里面有文件用于记录当前目录和CVS库之间的对应信息。但项目发布的时候你一般不希望把文件目录还带着含有CVS信息的CVS目录吧,这个一次性的导出过程使用cvs export命令,不过export只能针对一个TAG或者日期导出,比如:
cvs export -r release1 project_name
cvs export -D 20021023 project_name
cvs export -D now project_name

CVS Branch:项目多分支同步开发
=============================

确认版本里程碑:多个文件各自版本号不一样,项目到一定阶段,可以给所有文件统一指定一个阶段里程碑版本号,方便以后按照这个阶段里程碑版本号导出项目,同时也是项目的多个分支开发的基础。
cvs tag release_1_0

开始一个新的里程碑:
cvs commit -r 2 标记所有文件开始进入2.x的开发

注意:CVS里的revsion和软件包的发布版本可以没有直接的关系。但所有文件使用和发布版本一致的版本号比较有助于维护。

版本分支的建立
在开发项目的2.x版本的时候发现1.x有问题,但2.x又不敢用,则从先前标记的里程碑:release_1_0导出一个分支release_1_0_patch
cvs rtag -b -r release_1_0 release_1_0_patch proj_dir

一些人先在另外一个目录下导出release_1_0_patch这个分支:解决1.0中的紧急问题,
cvs checkout -r release_1_0_patch
而其他人员仍旧在项目的主干分支2.x上开发

在release_1_0_patch上修正错误后,标记一个1.0的错误修正版本号
cvs tag release_1_0_patch_1

如果2.0认为这些错误修改在2.0里也需要,也可以在2.0的开发目录下合并release_1_0_patch_1中的修改到当前代码中:
cvs update -j release_1_0_patch_1

CVS的远程认证:通过SSH远程访问CVS
================================

使用cvs本身基于pserver的远程认证很麻烦,需要定义服务器和用户组,用户名,设置密码等,
常见的登陆格式如下:
cvs -d :pserver:cvs_user_name@cvs.server.address:/path/to/cvsroot login
例子:
cvs -d :pserver:cvs@samba.org:/cvsroot login

不是很安全,因此一般是作为匿名只读CVS访问的方式。从安全考虑,通过系统本地帐号认证并通过SSH传输是比较好的办法,通过在客户机的/etc/profile里设置一下内容:
CVSROOT=:ext:$USER@cvs.server.address#port:/path/to/cvsroot CVS_RSH=ssh; export CVSROOT CVS_RSH
所有客户机所有本地用户都可以映射到CVS服务器相应同名帐号了。

比如:

CVS服务器是192.168.0.3,上面CVSROOT路径是/home/cvsroot,另外一台开发客户机是192.168.0.4,如果tom在2台机器上都有同名的帐号,那么从192.168.0.4上设置了:
export CVSROOT=:ext:tom@192.168.0.3:/home/cvsroot
export CVS_RSH=ssh
tom就可以直接在192.168.0.4上对192.168.0.3的cvsroot进行访问了(如果有权限的话)
cvs checkout project_name
cd project_name
cvs update
...
cvs commit

如果CVS所在服务器的SSH端口不在缺省的22,或者和客户端与CVS服务器端SSH缺省端口不一致,有时候设置了:
:ext:$USER@test.server.address#port:/path/to/cvsroot

仍然不行,比如有以下错误信息:
ssh: test.server.address#port: Name or service not known
cvs [checkout aborted]: end of file from server (consult above messages if any)

解决的方法是做一个脚本指定端口转向(不能使用alias,会出找不到文件错误):
创建一个/usr/bin/ssh_cvs文件:
#!/usr/bin/sh
/path/to/ssh -p 34567 "$@"
然后:chmod +x /usr/bin/ssh_cvs
并CVS_RSH=ssh_cvs; export CVS_RSH

注意:port是指相应服务器SSH的端口,不是cvs pserver的端口

CVSWEB:提高文件浏览效率
=======================

CVSWEB就是CVS的WEB界面,可以大大提高程序员定位修改的效率:
使用的样例可以看:http://www.freebsd.org/cgi/cvsweb.cgi

CVSWEB的下载:CVSWEB从最初的版本已经演化出很多功能界面更丰富的版本,这个是我个人感觉安装设置比较方便的:
http://www.spaghetti-code.de/software/linux/cvsweb/

下载解包:
tar zxf cvsweb.tgz
把配置文件cvsweb.conf放到安全的地方(比如和apache的配置放在同一个目录下),
修改:cvsweb.cgi让CGI找到配置文件:
$config = $ENV{'CVSWEB_CONFIG'} || '/path/to/apache/conf/cvsweb.conf';

转到/path/to/apache/conf下并修改cvsweb.conf:

1. 修改CVSROOT路径设置:
%CVSROOT = (
'Development' => '/path/to/cvsroot', #<==修改指向本地的CVSROOT
);
2. 缺省不显示已经删除的文档:
"hideattic" => "1",#<==缺省不显示已经删除的文档
3. 在配置文件cvsweb.conf中还可以定制页头的描述信息,你可以修改$long_intro成你需要的文字

CVSWEB可不能随便开放给所有用户,因此需要使用WEB用户认证:
先生成 passwd:
/path/to/apache/bin/htpasswd -c cvsweb.passwd user

修改httpd.conf: 增加

AuthName "CVS Authorization"
AuthType Basic
AuthUserFile /path/to/cvsweb.passwd
require valid-user


CVS TAGS: who? when?
====================

将$Id$ 加在程序文件开头的注释里是一个很好的习惯,cvs能够自动解释更新其中的内容成:file_name version time user_name 的格式,比如:cvs_card.txt,v 1.1 2002/04/05 04:24:12 chedong Exp,可以这些信息了解文件的最后修改人和修改时间

几个常用的缺省文件:
default.php
/*
* Copyright (c) 2002 Company Name.
* $Header$
*/

?>
====================================
Default.java: 注意文件头一般注释用 /* 开始 JAVADOC注释用 /** 开始的区别
/*
* Copyright (c) 2002 MyCompany Name.
* $Header$
*/

package com.mycompany;

import java.;

/**
* comments here
*/
public class Default {
/**
* Comments here
* @param
* @return
*/
public toString() {

}
}
====================================
default.pl:
#!/usr/bin/perl -w
# Copyright (c) 2002 Company Name.
# $Header$

# file comments here

use strict;


CVS vs VSS 
===========

CVS没有文件锁定模式,VSS在check out同时,同时记录了文件被导出者锁定。

CVS的update和commit, VSS是get_lastest_version和check in

对应VSS的check out/undo check out的CVS里是edit和unedit

在CVS中,标记自动更新功能缺省是打开的,这样也带来一个潜在的问题,就是不用-kb方式添加binary文件的话在cvs自动更新时可能会导致文件失效。

Virsual SourceSafe中这个功能称之为Keyword Explaination,缺省是关闭的,需要通过OPITION打开,并指定需要进行源文件关键词扫描的类型:*.txt,*.java,*.html...

对于Virsual SourceSafe和CVS都通用的TAG有:
$Header$
$Author$
$Date$
$Revision$

尽量使用通用的关键词保证代码在CVS和VSS都能方便的跟踪。

WinCVS
======

下载:
cvs Windows客户端:目前稳定版本为1.2
http://www.wincvs.org/
ssh Windows客户端
http://www.networksimplicity.com/openssh/

安装好以上2个软件以后:
WinCVS客户端的admin==>preference设置
1 在general选单里
设置CVSROOT: username@192.168.0.123:/home/cvsroot
设置Authorization: 选择SSH server

2 Port选单里
钩上:check for alternate rsh name
并设置ssh.exe的路径,缺省是装在 C:Program FilesNetworkSimplicitysshssh.exe

然后就可以使用WinCVS进行cvs操作了,所有操作都会跳出命令行窗口要求你输入服务器端的认证密码。

当然,如果你觉得这样很烦的话,还有一个办法就是生成一个没有密码的公钥/私钥对,并设置CVS使用基于公钥/私钥的SSH认证(在general选单里)。

可以选择的diff工具:examdiff
下载:
http://www.prestosoft.com/examdiff/examdiff.htm
还是在WinCVS菜单admin==>preference的WinCVS选单里
选上:Externel diff program
并设置diff工具的路径,比如:C:Program Filesed16iExamDiff.exe
在对文件进行版本diff时,第一次需要将窗口右下角的use externel diff选上。

基于CVS的小组开发环境搭建
========================

作为一个小组级的开发环境,版本控制系统和BUG跟踪系统等都涉及到用户认证部分。如何方便的将这些系统集成起来是一个非常有趣的事情,毕竟我们不能指望linux下有像Source Offsite那样集成度很高的版本控制/BUG跟踪集成系统。

我个人是很反对使用pserver模式的远程用户认证的,但如果大部分组员使用WINDOWS客户端进行开发的话,总体来说使用CVSROOT/passwd认证还是很难避免的,但CVS用户的管理比较麻烦。本来我打算自己用perl写一个管理界面的,直到我发现了CVSTrac, 一个基于WEB界面的BUG跟踪系统,它外挂在CVS系统上,而且就包括了WEB界面的CVSROOT/passwd文件的管理,甚至还集成了WIKIWIKI功能。

这里首先说一下CVS的pserver模式下的用户认证,CVS的用户认证服务是基于inetd中的:
cvspserver stream tcp nowait nobody /usr/bin/cvs cvs --allow-root=/home/cvsroot pserver
一般在2401端口

CVS用户数据库是基于CVSROOT/passwd文件,文件格式:
[username]:[crypt_password]:[mapping_system_user]
由于密码都用的是UNIX标准的CRYPT加密,这个passwd文件的格式基本上是apache的htpasswd格式的扩展(比APACHE的PASSWD文件多一个系统用户映射字段),所以这个文件最简单的方法可以用
apache/bin/htpasswd -b myname mypassword
创建。注意:通过htpasswd创建出来的文件会没有映射系统用户的字段
例如:
new:geBvosup/zKl2
setup:aISQuNAAoY3qw
test:hwEpz/BX.rEDU

映射系统用户的目的在于:你可以创建一个专门的CVS服务帐号,比如叫cvs,并将/home/cvsroot目录下的所有权限赋予这个用户,然后在passwd文件里创建不同的开发用户帐号,但开发用户帐号最后的文件读写权限都映射为cvs用户,避免了在SSH模式下多个开发用户新建文件后的对于其他用户的文件读写权限问题。

进一步的,你可以将用户分别映射到2组用户上,利用2个用户的权限设置,避免2个项目组的文件互相访问。
new:geBvosup/zKl2:proj1
setup:aISQuNAAoY3qw:proj2
test:hwEpz/BX.rEDU:proj1

CVSTrac很好的解决了CVSROOT/passwd的管理问题,而且包含了BUG跟踪报告系统和集成WIKIWIKI交流功能等,使用的CGI方式的安装,并且基于GNU Public License:

安装过程

1. 下载:http://www.cvstrac.org 解包,复制成/usr/bin/cvstrac
2. 在已经装好的CVS服务器上(假设CVS库已经使用cvs init初始化过在/home/cvsroot里),运行一下
cvstrac init /home/cvsroot myproj
运行后,/home/cvsroot里会有一个缺省的myproj.db库
3. 在apche/cgi-bin目录中创建如下脚本cvstrac:
#!/bin/sh
/usr/bin/cvstrac cgi /home/cvsroot
设置cvstrac可执行。
4. 从http://cvs.server.address/cgi-bin/cvstrac/myproj进入管理界面,缺省登录名:setup 密码 setup
5. 在inetd里加入cvspserver服务:
cvspserver stream tcp nowait nobody /usr/bin/cvs cvs --allow-root=/home/cvsroot pserver
注意:这里的用户设置成nobody目的是和apache的运行用户一致,并且必须让这个这个用户对/home/cvsroot/下的CVSROOT/passwd和cvstrac初始化生成的myproj.db有读写权限。

一般用户还可以从:
http://cvs.server.address/cgi-bin/cvstrac/myproj
修改登录密码,记录BUG报告等,更多使用细节可以在使用中慢慢了解。

对于前面提到的WinCVS改用passwd file on server side模式登录就可以了。

总结:

利用cvs + (WinCVS/cvsweb/cvstrac),构成了一个相对完善的跨平台工作组开发环境。

相关资源:

CVS HOME:
http://www.cvshome.org

CVS FAQ:
http://www.loria.fr/~molli/cvs-index.html

相关网站:
http://directory.google.com/Top/Computers
/Software/Configuration_Management/Tools/Concurrent_Versions_System/

CVS 免费书:
http://cvsbook.red-bean.com/

CVS 命令的速查卡片:
http://www.refcards.com/about/cvs.html

WinCVS:
http://www.wincvs.org

CVSTrac: A Web-Based Bug And Patch-Set Tracking System For CVS
http://www.cvstrac.org



CVS 使用简介
============
CVS 是RCS的前端工具,它是用于多用户并行开发的版本控制工具,它的最大特点是使用了“copy-modify-merge”机制而不是“lock- modify-unlock”。通过使用CVS生成一个存储文件的仓库(repository),存储在仓库中的每个目录叫做模块(module),在修改时将相应的模块检出到工作目录中(working directory)生成对应的目录,所有的修改都在工作目录中完成,修改完成后再提交到仓库中生成新的版本号,并加以保存。

1. CVS初始化
-------------
(1) 创建CVSROOT根目录
编辑有关的环境变量,加入CVSROOT的定义(比如在 /etc/bashrc 文件中加入下面两行):
CVSROOT=/usr/local/cvsroot
export CVSROOT

然后在相应位置开始创建CVSROOT
$cd /usr/local/
$mkdir cvsroot
$cvs –d /usr/local/cvsroot init

这时就会产生/usr/local/cvsroot/CVSROOT 目录,这下面放着有关CVS的配置文件。同时/usr/local/cvsroot/也作为文件仓库存放所有的文件。
(2) 创建开发项目
如果从头开始一个新的项目,就需要创建一个单独的目录,并把所有要使用的文件做一个有效的组织。而如果在开始使用源文件的目录之前就有了,则只需进入该目录就行了。
$cd /work/tang
$ls cvstest
. .. c/
$cd cvstest
然后,就可以输入源文件目录:
$cvs import –m “Create Source Dir” cvstest/c tang cvstest

这样会生成 $CVSROOT/cvstest/c 目录。 其中 -m 用来指定注释信息,如果后面在命令行不指定注释信息,则会启动缺省编辑器(vi)要求输入注释信息。 tang, cvstest分别标识了厂商和发行标识。

注意,使用import命令会把当前目录下的所有文件和目录(包括子目录)引入到文件仓库中指定模块(目录)下。

2. 命令简介
-------------
(1) 检出源文件
cvs checkout [-r rev][-D date][-d dir][-j merg1] [-j merg2] modules

-r 检出指定版本的模块
-D 检出指定日期的模块
-d 检出指定目录而不是模块
-j 合并当前版本和指定版本

使用下面的命令会检出刚才生成的模块,并在当前目录下生成与文件仓库中完全一样的目录结构:
$cvs checkout cvstest/c

对于目录结构比较复杂的模块可以在 $CVSROOT/CVSROOT/modules中加以指定:

1) $cvs checkout CVSROOT/modules
2) 在modules文件中加入下面一行:
SOURCE cvstest/c
3) 然后执行:
$cvs commit –m “Add SOURCE”

以后就可以使用下面的命令在当前路径下生成 cvstest/c 目录
$cvs checkout SOURCE

在当前路径下生成的这个目录就被称为工作目录,对源文件的所有修改都应该在这个目录下完成,而绝对不允许去改动在 文件仓库中$CVSROOT 目录下的文件。
(2) 删除、增加、重命名文件和目录
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 管理文件,一般应该遵循以下步骤:
1) 确认所有有关的修改都已经提交;
2) 进入文件仓库中要修改的模块目录,对相应的目录进行修改(重命名或删除)
$cd $CVSROOT/modules
$mv old_dir new_dir
3) 如果有必要,修改管理文件,比如modules 文件
如果要删除目录,则应该先对目录中每个文件都进行了删除(包括使用cvs remove )处理之后再执行上面的第2步。
(3) 提交源文件
cvs commit [-Rl][-m mesg] files

-R 连子目录一起提交
-l 只提交本地目录(不提交子目录)
-m 注释信息

在检出源文件之后,在工作目录中对源文件进行的所有修改都必须在提交之后才能对文件仓库中的源文件起作用,并且新的文件才能够被分配一个新的版本号。
(4) 释放工作目录
cvs release –d SOURCE

这个命令会删除工作目录 cvstest/c (建议在提交了修改的模块后执行这一步), 它比使用 rm –rf cvstest 要好。

3. 多用户开发
---------------
在多用户的情况下,如果不同用户修改的是同一个文件的不同部分,则使用下面的命令就能进行版本合并(把检出的文件与当前的最新版本合并):
$cvs update
(1) 冲突解决
在有多个用户对同一个文件进行修改时,如果修改了其中的相同部分,而修改后的内容如果有不同的话,出现冲突是不可避免的。如果在CVS 文件仓库中有一个文件 test.c ,它的版本是 1.4, 用户A 先检出该文件进行修改,而稍后有用户B 检出该文件进行修改,并提前提交成 1.5, 而在用户A再提交时就会出现冲突(如果文件内容不同的话),这时CVS会提示需要手工解决。
文件仓库中的版本1.4:
#include stdio.h
main()
{
int i;
for(i = 0; i < 100; i++)
printf(“Count: %d
”, i);
}
用户B 1.5:
#include stdio.h
main()
{
int i;
for(i = 0; i < 10; i++)
printf(“Count: %d
”, i);
printf(“Over
”);
}
用户A :
#include stdio.h
main()
{
int i;
for(i = 0; i < 50; i++)
printf(“Count: %d
”, i);
return;
}
提交时会提示有冲突,需要手工编辑,这时运行了$cvs update 之后再编辑test.c, 会看到:
#include stdio.h
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
}
(2) 文件版本管理
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 stdio.h
1.1 (tang 18-Jan-00): #include string.h
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.5  1.4  1.3  1.2 主干 1.1 1.6

 1.2.2.2  1.2.2.1 分支tlb-1 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

4. 在远程机器上使用CVS
----------------------
通过网络使用CVS 有很多种方式,但在这里只介绍比较简单的一种:通过rsh 执行cvs 命令。
1) 在远程机器的.rhosts中加入对本地机的访问许可:
tom tang

2) 使用下面的命令检出模块ESMSTRG
$cvs –d :ext:tang@esmpro:/work/cvsroot checkout SOURCE

其中, ext 指明了连接方式为 rsh, tang 指明了本地用户, esmpro 指明了远地主机,/work/cvsroot 指明了在远地主机上的$CVSROOT路径,可以在本地设置

0 评论: