手把手教你使用CVS客户端进行项目开发

来源:互联网 发布:java 导出本地excel 编辑:程序博客网 时间:2024/06/11 18:50

CVS使用手册:手把手教你使用CVS客户端进行项目开发

摘要本文详细介绍了CVS的基本入门知识以及cvs客户端的配置过程,并由浅入深的描述了如何应用CVS进行系统开发或其它文档的版本管理与控制,并对CVS的常见问题进行了分析与解答,可以说是一篇CVS入门、学习与提高的完美教程。通过本教程你可以在最短的时间里面最快的掌握CVS的所有内容,并用CVS来进行项目的开发。
*************************************
内容概览:
一、CVS入门知识详解
        1、什么是 CVS?
        2、CVS基本概念
二、CVS客户端的安装和配置
        1、连接CVS服务器
        2、登录CVS服务器
        3、拷贝相应代码准备开发
三、如何用CVS来开发项目
        1、更新源码
        2、提交修改后的文件
        3、查看日志
        4、将文件添加到资源库
        5、将目录添加到资源库
        6、删除文件或目录
        7、标签的定义和使用
        8、备份源码仓库
        9、分支的定义和使用
四、CVS常见问题分析
        1、cvs用户为什么不能登录?
        2、我怎么知道别人改了哪些内容?
        3、什么是冲突?怎么解决?
五、结束语
*************************************

由于文章涵盖的内容很多,飘扬建议对于不同需求的朋友请各取所需。如果你是一位CVS初学者,那么请你多花点时间通读本文,他将帮你完全掌握CVS;如果你想了解CVS的开发过程,你可以读本文的第二部分《三、如何用CVS来开发项目》;最后,如果你是因为在使用CVS而遇到问题搜索到本文时,那么请你读《四、CVS常见问题分析》吧,当然你也可以直接和飘扬联系,你可以去我的博客http://www.piaoyang.org  (飘扬博客)给我留言或QQ47720194,我会及时看到你的问题的。好啦,下面开始和飘扬一起学习CVS吧!

一、CVS入门知识详解

1、    什么是 CVS?

CVS 是一种客户机/服务器系统,类似于microsoft SourceSafe,可以让开发人员将他们的项目存储在称为资源库的中央位置。使用 cvs 客户机工具,开发人员可以对资源库的内容进行更改。CVS 资源库会依次记录对每个文件所做的每个更改,并创建一个完整的项目开发进展历史。开发人员可以请求特定源文件的旧版本、查看更改日志,并根据需要执行其它一些有用的任务。所有重要的免费软件项目都使用 CVS 作为其程序员之间的中心点,以便能够综合各程序员的改进和更改。这些项目包括: Gnome, KDE, The GIMP, Wine, 等等。

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

CVS可以协助一组人共同开发一个工程。如果你是一个项目中的一组成员之一,CVS也能够帮助你。除非你特别仔细,你很容易覆盖其他人的工作。一些编辑器,例如GNUEmacs,试图去判定一个文件是否被两人同时修改。不幸的是,如果一个人使用其它的编辑器时,这个安全方式将不再有效。CVS使用让不同开发者独立工作的方式解决了这个问题。每一个开发者的工作都在他自己的目录内,并且CVS将 在每个开发者的工作完成后进行合并工作。

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

2、    CVS基本概念

Repository(仓库)

CVS的仓库存储全部的版本控制下的文件copy,通常不容许直接访问,只能通过cvs命令,获得一份本地copy,改动后再check in(commit)回仓库。而仓库通常为与工作目录分离的。CVS通过多种方式访问仓库。每种方法有不同目录表示形式。数据如何存放在repository中:随着CVS版本的不同,存放结构会发生变化,一般情况下用户无需了解数据到底是如何存放的。

Revision(修订版)
每一个file的各个revision都不相同,形如1.1, 1.2.1,一般1.1是该文件的第一个revision,后面的一个将自动增加最右面的一个整数,比如1.2, 1.3, 1.4...有时候会出现1.3.2.2,原因见后。revision总是偶数个数字。一般情况下将revision看作时CVS自己内部的一个编号,而tag则可以标志用户的特定信息。

Tag(标签)
用符号化的表示方法标志文件特定revision的信息。通常不需要对某一个孤立的文件作tag,而是对所有文件同时作一个tag,以后用户可以仅向特定tag的文件提交或者checkout。另外一个作用是在发布软件的时候表示哪些文件及其哪个版本是可用的;各文件不同revision可以包括在一个tag中。如果命名一个已存在的tag默认将不会覆盖原来的;

Branch(分支)
当用户修改一个branch时不会对另外的branch产生任何影响。可以在适当的时候通过合并的方法将两个版本合起来;branch总是在当前revision后面加上一个偶数整数(从2开始,到0结束),所以branch总是奇数个数字,比如1.2后面branch为1.2.2,该分支下revision可能为1.2.2.1,1.2.2.2,...

Conflict(冲突)
完全是纯文本的冲突,不包含逻辑上的矛盾,比如CVS不能解决如下问题:某人修改了函数f的参数,而另外一个人在另外一个地方用老的参数调用该函数。文本冲突需要用户自己参与解决,CVS无法自动解决。(如还有不明之处,请到飘扬博客http://www.piaoyang.org 给我留言或QQ47720194,我会尽力解答你的问题。)

Module(模块):CVS服务器根目录下的第一级子目录。通常用于存放一个项目的所有文件
Check out(检出):通常指将仓库中的一整个模块首次导出到本地。
Check in(导入)::通常指通过提交整个目录结构并创建一个新的模块。
Release(发行版本):整个产品的版本
Update(更新):从模块中下载其他人的修改过的文件。更新本地的拷贝。
Commit(提交):将自己修改过的文件提交到模块中。

二、CVS客户端的安装和配置

在RedHat Linux 7.1之后的版本上,都有自动安装CVS服务器软件,只要对该软件进行设置,即可使用。因此这里不再对CVS客户端的安装一一赘述。此次配置我用的是虚拟机VMware环境下的linux redhat9.0,下面是具体的配置过程。

为了连接到 CVS 资源库,您需要知道称为 "CVSROOT" 的路径。CVSROOT 是一个字符串,就象 URL,它告诉 CVS用户远程资源库在哪里,以及如何连接它。不仅如此,根据 CVS 资源库是本地的还是远程的,以及连接到它的不同方式,CVS 还有许多不同的 CVSROOT 格式。

1、连接CVS服务器
当然你必须拥有cvs用户帐号和密码,以及相关权限。在Linux环境下:
1) 本地 CVSROOT
    # export CVSROOT=/usr/local/cvsroot (告诉CVS客户端,存放代码的资源库在什么地方)
    一个实际的例子,在版本管理员将代码库存放在192.168.0.36 的机器上,路径为:
    /usr/local/cvsroot(如果你telnet 到 192.168.0.36 的机器上的时候,此时你就是在本机)
2) 远程密码服务器 CVSROOT
    # export CVSROOT=:pserver:piaoyang@192.168.0.36:/usr/local/cvsroot(注意冒号不能漏掉,句子中间没有空格)
    pserver 是CVS内部的一种传输协议。
    piaoyang 是用户名,
    192.168.0.36 机器的IP或名字(如果有DNS才能用名字)
    /usr/local/cvsroot 是代码库的具体路径
(注意:如果你不想每次敲这么多枯燥的命令,你可以在你登陆的时候让系统作这些事情,具体的作法是修改你登录的环境变量。现在用piaoyang作为例子,在文件/home/piaoyang/.bash_profile后面加入
export CVSROOT=/home/cvsroot 或export CVSROOT=:pserver:piaoyang@192.168.0.36:/home/cvsroot
并在根目录下运行:. ./.bash_profile)

2、登录CVS服务器
# cvs login
(Logging in to cvs@192.168.0.8)
CVS password:(在此输入密码)

3、拷贝相应代码准备开发
如输入: # cvs -z5 checkout VPN
此命令告诉 CVS 客户端使用 gzip 压缩级 5 ("-z5") 在慢速连接上加快传输速度,来检出 ("checkout")VPN模块。
一旦检出命令完成,将在包含最新源码的当前工作目录中看到 "VPN" 目录。还会注意到每个子目录下都有一个"CVS"目录 -- CVS 在这些目录中存储帐户信息,可以放心地忽略它们。(如还有不明之处,请到飘扬博客http://www.piaoyang.org 给我留言或QQ47720194,我会尽力解答你的问题。)一旦检出结束,用户就无需担心是否设置了 CVSROOT 环境变量,也无需再在命令行上指定它,因为现在所有额外的 "CVS" 目录里都有它的缓存。
记住:只需要为初始登录和检出设置 CVSROOT。至此你就可以在刚才check out的VPN模块上进行修改或开发了

至于怎样用CVS来开发源代码请参考本文《三、如何用CVS来开发项目》部分。

三、如何用CVS来开发项目

经过上面的check out之后,现在已经有了源码,我们可以继续编译和安装它们、检查它们,或者对它们执行任何操作了。现在,来看一下作为一个开发人员如何与 CVS 交互。

作为一名开发人员,您需要修改 CVS 上的文件。要修改文件,只需要对资源库的本地副本进行适当的更改。在您明确地告诉 cvs "提交"更改之前,您对源码做的更改不会应用到远程资源库。测试过所有修改以确保它们可以正常运作之后,就可以准备将这些更改后的文件运用到资源库中,遵循下面的两个步骤。

1、更新源码
在提交之前需要将已检(checkout)出的源目录与 CVS 上的当前版本保持同步。为了做到这一点,您无需再次登录到 pserver;cvs 会将您的认证信息缓存到那些 "CVS"帐户目录中。首先,进入主检出目录(在这里是 "VPN"),然后输入:
# cvs update -dP
如果有任何新文件或者其他人对文件有过更改,cvs就会在更新每一行的时候输出 "U [path]" 行。另外,如果本地编译了源码,您有可能会看到许多 "? [path]" 行;cvs 指出这些目标文件不来自于远程资源库。 (另外,请注意我们用于 "cvs update" 的两个命令行选项。"-d" 告诉 cvs 创建可能已添加到资源库的新目录(缺省情况下,这不会发生),"-P" 告诉 cvs 从本地已检出的源码副本中除去所有空目录。"-P" 是个不错的选择,因为 cvs 倾向于收集许多随时间产生的空(曾经使用过,但现在已经放弃)目录树。)

2、提交修改后的文件
我们假设在输入 "cvs update -dP" 后没有冲突 -- 通常都没有冲突。由于没有冲突,本地源码是最新的。可以在主源码目录中输入以下命令来提交对资源库的更改:
# cvs commit

3、查看日志
要查看某个特定文件完整的历史以及提交时开发人员(包括您)所加的注解是很容易的。要查看这些信息,输入:
# cvs log myfile.c
"cvs log" 命令是递归的,所以如果您想查看整个目录树的完整日志,只需要进入该目录,输入:
# cvs log | less

4、将文件添加到资源库

要将源文件添加到 CVS 很容易。首先,用您喜爱的文本编辑器创建该文件。然后,输入以下命令:
# cvs add myfile.c
cvs server: use cvs commit to add this file permanently
这将告诉 cvs 在您下次执行 "cvs commit" 时,将该文件添加到资源库。在那之前,其它开发人员看不它。

5、将目录添加到资源库
将目录添加到 CVS 的过程类似于mkdir foo命令:
# cvs add foo
Directory /home/cvsroot/mycode/foo added to the repository
与添加文件不同,当您添加目录时,它会立即出现在资源库中;不需要 cvs commit。将本地目录添加到 cvs 后,您会注意到在远程cvs服务器的对应目录中创建了一个 "CVS" 目录,它作为包含 cvs 帐户数据的容器。因而,您只要看一下其中是否有 "CVS" 目录,就可以很容易地知道某个目录是否已添加到远程cvs服务器的 cvs中了
在将文件或目录添加到资源库之前,您必须确保它的父目录已经添加到 CVS。否则,您会看到类似于下面的错误:
# cvs add myfile.c cvs add: cannot open CVS/Entries for
reading: No such file or directory cvs [add aborted]: no repository

6、删除文件或目录
1) 删除文件是分两个过程。首先,从源码的本地副本删除该文件,然后执行 "cvs remove" 命令从资源库中删除该文件:
# rm myoldfile.c
# cvs remove myoldfile.c
在您下次提交时,该文件计划将从资源库中除去。一旦提交,该文件会从资源库当前的版本中正式删除。然而, cvs 不会将该文件抛弃,而是仍然完整地保留该文件的内容及其历史,以备您以后需要它。这只是 cvs 保护您有价值的源代码的众多方法之一。
2) 如果您想除去整个目录,首先用"cvs remove" 删除目录中的所有文件:
# rm *.c
# cvs remove

然后执行提交:
# cvs commit

7、标签的定义和使用
源码仓库中各个文件的修订号是独立增加的,相互之间没有任何关联关系,和软件的发布号也没有任何关系,例如一个项目中的各个文件的修订号可能是这样的:
ci.c 5.21
co.c 5.9
ident.c 5.3
rcs.c 5.12
rcsbase.h 5.11
rcsdiff.c 5.10
rcsutil.c 5.10
为了便于标记,可以使用标签来为某个特定版本的特定文件设定一个标记以方便访问,可以使用cvs tag和cvs rtag来定义标签,其中cvs tag用来为仓库中当前工作文件(或文件集合)指定一个符号标记;cvs rtag用来显式地为源码仓库的特定修订号的文件定义一个标记。例如下面的例子就是给文件backend.c的当前修订号定义一个标签,然后察看该文件的状态:
$ cvs tag rel-0-4 backend.c
T backend.c
$ cvs status -v backend.c
但是在实际应用中很少会为特定文件定义一个标签,而往往是在开发过程中的特定阶段为特定项目的所有文件定义一个标签,以方便发布或者定义分支,例如:
$ cvs tag rel-1-0 .
cvs tag: Tagging .
T Makefile
T backend.c
T driver.c
T frontend.c
T parser.c
定义标签以后,可以在随后的任何时候访问对应该标签的项目文件,例如下面这个命令就用来实现检出对应于标签rel-1-0的所有文件(可能是软件的1.0发布):
$ cvs checkout -r rel-1-0 tc
当然也可以删除标签,例如:
cvs rtag(/tag) -d rel-0-4 tc 删除模块tc的rel-0-4标记

8、备份源码仓库
首先断开所有的cvs连接,然后使用cp命令备份即可

9、分支的定义和使用
通过CVS可以实现将对源码的修改提交给一个独立的开发线,被称为分支(branch)。当对分支的文件进行修改时,这些修改不会对主分支和其他分支产生影响。
随后可以将将一个分支的修改合并(merging)到其他分支。合并是通过cvs update -j来合并修改到当前工作目录(本地),然后就可以提交修改来影响其他分支了。

9.1 分支的重要性
让我们假设这种情况,项目tc的1.0版本已经搞定,你将继续开发tc项目,计划在几个月内发布1.1版本,但是客户抱怨软件中有致命的错误。因此你检出1.0版本(这里就是需要使用标记的原因)并发现了这个bug的原因。然而当前的源码处于1.0和1.1版本之间因此代码处于混乱状态,而且在一个月内不大可能出现稳定版本,因此不大可能根据当前的版本得到一个修复错误的版本来发布。 对于这种情况这就需要创建一个包含错误修改的1.0分支发布,而不需要影响当前的开发,在合适的时候可以将修正合并的主发布中去。 (如还有不明之处,请到飘扬博客http://www.piaoyang.org 给我留言或QQ47720194,我会尽力解答你的问题。)

9.2 创建分支
创建分支首先为拟修改的某些文件创建一个标签(tag),标签是赋于一个文件或一组文件的符号.在源代码的生命周期里,组成一组模块的文件被赋于相同的标签。
创建标签:在工作目录里执行cvs tag 。
例: 为src创建标签:
cvs checkout src(/update亦可,用来更新本地的源代码)
cvs tag release-1-0(为当前最新源码加一个标签)
标签创建后, 就可以为其创建一个分支:
cvs rtag -b -r release-1-0 release-1-0-path print
-b :创建分支
-r release-1-0:-r参数用来标记那些包含指定的标签的文件
releas-1-0-patch:分支
print: 模块名

可以使用tag -b来创建分支,例如在工作目录中:
$ cvs tag -b rel-1-0-patches
将会基于当前工作的分支分离一个分支,并将该分支命名为`rel-1-0-patches。应该理解分支是在cvs的源码仓库中创建的,而不是当前工作目录,基于当前修正创建分支不会将当前工作拷贝自动转换为新的分支,需要手工来实现的。也可以通过使用rtag命令实现不涉及工作目录的分支:
$ cvs rtag -b -r rel-1-0 rel-1-0-patches tc
`-r rel-1-0指示创建的新分支应该以标记`rel-1-0指定的修订为基础,而不是基于当前的工作主分支。这主要是用来从旧版本中创建一个分支(例如上面的例子)。
rtag -b指示创建分支(而不是仅仅创建标记)。应该注意的是`rel-1-0包含的各个文件的修订号可能是不一样的。
所以该命令的效果是为工程tc创建一个新分支-名字为`rel-1-0-patches,以标记`rel-1-0为基础。

9.3 访问分支
可以以两种方式访问分支:从源码仓库中检出分支代码,或者将当前的工作拷贝切换为分支。
从源码仓库中创检出新分支可以使用命令checkout -r release-tag命令:
$ cvs checkout -r rel-1-0-patches tc
将当前分支切换到分支命令:
$ cvs update -r rel-1-0-patches tc
或者
$ cd tc
$ cvs update -r rel-1-0-patches
随后的提交等影响源码仓库的操作都仅仅对分支起作用,而不会影响主分支和其他分支。可以使用status命令来察看当前工作拷贝属于哪个分支。输出中察看sticky tag信息,这就是cvs显示当前工作拷贝是在哪个分支上:
$ cvs status -v driver.c backend.c

9.4 合并分支
分支开发一段时间以后往往需要将修订合并到主分支中来,可以通过`-j branchname参数实现合并分支。使用该参数将分支和其父分支合并。 分支1.2.2被定义为标记R1fix。下面的例子假设模块mod仅仅包含一个文件m.c:
$ cvs checkout mod #获取最新的1.4版本
$ cvs update -j R1fix m.c # 合并分支的所有更新到主分支
# 也就是1.2到1.2.2.2的修改合并到当前工作拷贝
$ cvs commit -m "Included R1fix" # 创建修订版本1.5.
合并时可能出现冲突情况,如果发生冲突,应该在提交以前手工处理冲突。

四、CVS常见问题分析

1、cvs用户为什么不能登录?
# export CVSROOT=:pserver:cvsroot@192.168.10.11:2401/cvsroot
# cvs login 
Logging in to :pserver:cvsroot@192.168.10.11:2401/cvsroot
CVS password:
no such user cvsroot in CVSROOT/passwd
解决办法:查看是/cvsroot/CVSROOT/passwd文件,看里面有没有包含该用户

2、    我怎么知道别人改了哪些内容?
假如我们现在修改了,文件config.h , 现在想看看除了我之外还有什么人修改了这个文件,到底修改了什么东西? 怎么办?此时,输入以下命令即可查看:cvs diff config.h

3、什么是冲突?怎么解决?
当两个或两个以上的用户对同一个文件的相同部分进行修改时,往往会引起冲突,下面用一个例子说明。
假设用户A与用户B都下载了文件example.h,内容如下:

void main(int argv,char *argc)              {              printf("I am Cather/n");              }
然后用户A把文件修改成如下,并提交到CVS服务器(一般将正常提交):
void main(int argv,char *argc)              {              printf("I am Cather/n");              printf("I am Pat/n");              }
接着用户B又把文件修改成如下:
void main(int argv,char *argc)              {              printf("I am Cather/n");              printf("I love you Cather/n");              }
如果用户B这时选择“Commit Selection”准备把修改结果提交到CVS服务器,此时将显示如下的错误提示:
cvs -z9 commit -m "update in 11:20" example.h (in directory C:/my cvs/STW/src/)              cvs server: Up-to-date check failed for `example.h'              cvs [server aborted]: correct above errors first!                            ***** CVS exited normally with code 1 *****
表明用户B的修改与其它用户的修改冲突,这时要先选择“Update Selection”,将显示如下提示:
 cvs -z9 update example.h (in directory C:/my cvs/STW/src/)              RCS file: /home/cvsroot/STW/src/example.h,v              retrieving revision 1.9              retrieving revision 1.10              Merging differences between 1.9 and 1.10 into example.h              rcsmerge: warning: conflicts during merge              cvs server: conflicts found in example.h              C example.h                            ***** CVS exited normally with code 0 *****
example.h前面的C表示与其它用户的修改有冲突,并且文件的图标会加显示一个“C”,双击example.h将显示example.h的内容,如下:
void main(int argv,char *argc)              {              printf("I am Yanxi/n");              printf("I am Cather/n");              <<<<<<< example.h              printf("I love you Yanxi,too!/n"); //这部分为你的修改              =======              printf("I love you Cather!/n"); //这部分为其它用户的修改              >>>>>>> 1.10              }
这时你应该与用户A进行协商以决定最终要怎样修改。比如,可以修改成:
void main(int argv,char *argc)              {              printf("I am Yanxi/n");              printf("I am Cather/n");              printf("I love you Yanxi,too!/n"); //这部分为你的修改              printf("I love you Cather!/n"); //这部分为其它用户的修改              }
然后选择“Commit Selection”进行提交,将显示如下的提示信息:
cvs -z9 commit -m "update in 11:20" example.h (in directory C:/my cvs/STW/src/)              Checking in example.h;              /home/cvsroot/STW/src/example.h,v <-- example.h              new revision: 1.11; previous revision: 1.10              done                            ***** CVS exited normally with code 0 *****
表明用户A与用户的修改已经合并成功。这样,向CVS服务器提交文件所会遇到的问题也基本上就是这些,用户要根据所遇到的实际问题进行修改。

五、结束语
如果你是通篇读到这里,那么到这里,你基本掌握了怎样配合使用CVS进行系统开发或其它文档的版本管理与控制。谢谢你的耐心与信任,同时也对你的小有成就小小的祝贺一下。在最后飘扬要申明的是,本教程里的大部分内容是由网上多篇介绍CVS的文章提取而来,飘扬只是用自己的逻辑和语言将这些内容串联起来。在此,飘扬对这些文章的原作者深表感谢。如还有不明之处,请联系飘扬,你可以到我的博客飘扬博客http://www.piaoyang.org 给我留言或QQ47720194,我会尽力解答你的问题。以此拙作,希望能给大家带去些微的帮助。

本文为飘扬原创,首发飘扬博客http://piaoyang.org,作者邮箱piaoyang168#163.com,请尊重版权,转载请保留本行说明。
原创粉丝点击