| 关键词: CVS 资源库 文件 CVSROOT 源码 目录 冲突 一个 人员 命令 |
什么是 CVS? CVS 是一种客户机/服务器系统,可以让开发人员将他们的项目存储在称为资源库的中央位置。使用 cvs 客户机工具,开发人员可以对资源库的内容进行更改。CVS 资源库会依次记录对每个文件所做的每个更改,并创建一个完整的项目开发进展历史。开发人员可以请求特定源文件的旧版本、查看更改日志,并根据需要执行其它一些有用的任务。 许多开放软件项目都有他们自己的 CVS 服务器,项目开发人员把这些服务器作为他们工作的源码仓库。源码仓库的源码目录中保存的都是实现版本控制的历史文件(history file),历史文件名为filename,v。历史文件包含用来恢复所有版本文件的足够信息、所有提交的信息以及提交者信息。历史文件常常被称作RCS文件,因为最早是RCS程序用这种格式来保存文件的所有修改信息,可以从man rcsfile得到历史文件的。 开发人员每天都会改进 CVS 资源库内的源码,且他们往往分布在世界各地,而 CVS 提供了一种必要的机制,将他们的项目联合成一个集中的、协作的整体。CVS 创建了"组织粘和剂",可以让这些开发人员改进代码而不会干扰别人、丢失重要数据或遗漏彼此对特定源文件的重要更新。 当开发人员准备好以后,他们把 CVS 上部分当前工作打包成 .tar.gz 文件,作为软件包的新官方版本来发布它。然而,由于种种原因,最新的官方发行版有时并不是最新的。在本教程的第一部分将首先介绍如何使用CVS为个人使用获取最新和最高开发人员版本的源码。 CVSROOT 在开始前,您需要了解一些 CVS 的基础知识。首先,为了连接到 CVS 资源库,您需要知道称为 "CVSROOT" 的路径。CVSROOT 是一个字符串,就象 URL,它告诉 cvs 命令远程资源库在哪里,以及如何连接它。不仅如此,根据 CVS 资源库是本地的还是远程的,以及连接到它的不同方式,CVS 还有许多不同的 CVSROOT 格式。这里有一些带有解释的 CVSROOT 示例。 本地 CVSROOT CVSROOT=/home/cvsroot 这是一个本地 CVSROOT 路径的示例;如果您想连接到 /home/cvsroot 中存在的本地资源库,或者有一个经 NFS 安装在 /home/cvsroot 的资源库,需要象这样使用 CSROOOT。 远程密码服务器 CVSROOT CVSROOT=:pserver:[email protected]:/home/cvsroot 这里是一个远程资源库的 CVSROOT 示例,该资源库位于 foo.bar.com 主机上,并在这台机器的 /home/cvsroot 目录中活动。前导 ":pserver:" 告诉我们的客户机使用 CVS 密码服务器协议连接到这台远程机器,该协议内置在 CVS 中。一般情况下,公共 CVS 资源库使用密码服务器协议以允许匿名用户访问。 远程 rsh/ssh CVSROOT [email protected]:/data/cvs 这是一个使用 RSH 或 SSH 协议的 CVSROOT 的示例;在该例中,CVS 服务器尝试使用 drobbing 帐户来访问在 foo.bar.com 上的资源库。如果 CVS_RSH 的环境变量设置成 "ssh",那么我们的客户机就尝试用 ssh 去连接;否则就使用 rsh。那些关注安全性的用户往往使用 ssh 访问法;但是,无论是 RSH 还是 SSH 方法都不能对匿名用户提供一种获取源码的方式。为了使用这种方法,您在 foo.bar.com 上必须有个登录帐户。 除了 CVSROOT 之外,您还需要知道要检出的模块(源码集合)的名称,以及登录到 CVS 密码服务器的匿名密码。与匿名 ftp 不同,匿名密码没有什么"标准"格式,所以您需要从开发人员网站或开发人员那里获得具体的密码。一旦知道了所有这些信息,就可以开始了。 与 CVS 交互 获取源码需要两个步骤。首先,以远程密码服务器的方式登录到CVS服务器。然后,使用"checkout"命令获取源码。这里有一组命令的示例,用于检出最新的 Samba 源码(一个流行的 UNIX/Windows 集成项目): # export CVSROOT=:pserver:[email protected]:/cvsroot 第一个命令设置 CVSROOT 环境变量。如果没有设置这个变量,下面两个命令将需要跟在 "cvs" 命令后再加上 "-d :pserver:[email protected]:/cvsroot"。设定 CVSROOT 环境变量省去了一些输入。 # cvs login (Logging in to [email protected]) CVS password:(在此输入密码) # cvs -z5 checkout samba U samba/COPYING U samba/Manifest U samba/README U samba/Read-Manifest-Now U samba/Roadmap U samba/WHATSNEW.txt (这只是完整的 cvs check 输出的一小段摘录) 上面第一个 cvs 命令是让我们登录到 pserver,第二个命令告诉 CVS 客户机使用 gzip 压缩级 5 ("-z5") 在慢速连接上加快传输速度,来检出 ("checkout") samba 模块。对于每个在本地创建的新文件,cvs 都会打印 "U [path]" 表明这个特定的文件已经在磁盘上更新过了。 一旦检出命令完成,将在包含最新源码的当前工作目录中看到 "samba" 目录。还会注意到每个子目录下都有一个"CVS"目录 -- CVS 在这些目录中存储帐户信息,可以放心地忽略它们。一旦检出结束,用户就无需担心是否设置了 CVSROOT 环境变量,也无需再在命令行上指定它,因为现在所有额外的 "CVS" 目录里都有它的缓存。 记住 -- 只需要为初始登录和检出设置 CVSROOT。 更新源码 现在已经有了源码,就可以继续编译和安装它们、检查它们,或者对它们执行任何操作。 偶尔,也需要将已检(checkout)出的源目录与 CVS 上的当前版本保持同步。为了做到这一点,您无需再次登录到 pserver;cvs 会将您的认证信息缓存到那些 "CVS"帐户目录中。首先,进入主检出目录(在这里是 "samba"),然后输入: # cvs update -dP 如果有任何新文件,cvs就会在更新每一行的时候输出 "U [path]" 行。另外,如果本地编译了源码,您有可能会看到许多 "? [path]" 行;cvs 指出这些目标文件不来自于远程资源库。 另外,请注意我们用于 "cvs update" 的两个命令行选项。"-d" 告诉 cvs 创建可能已添加到资源库的新目录(缺省情况下,这不会发生),"-P" 告诉 cvs 从本地已检出的源码副本中除去所有空目录。"-P" 是个不错的选择,因为 cvs 倾向于收集许多随时间产生的空(曾经使用过,但现在已经放弃)目录树。 如果只是要获得最新的源码,这些就是您所需要了解的。现在,来看一下作为一个开发人员如何与 CVS 交互。 修改文件 作为一名开发人员,您需要修改 CVS 上的文件。要修改文件,只需要对资源库的本地副本进行适当的更改。在您明确地告诉 cvs "提交"更改之前,您对源码做的更改不会应用到远程资源库。测试过所有修改以确保它们可以正常运作之后,就可以准备将这些更改运用到资源库中,遵循下面的两个步骤。首先,在主源码目录中输入以下命令来更新源码: # cvs update -dP CVS 合并其他人的更改 我们在前面已经看到,"cvs update"将用资源库中的当前版本使您的源码保持最新状态 -- 但对您已经做过的更改会发生什么情况呢?不要担心,它们不会被丢弃。如果另一个开发人员对您没动过的文件做了一些更改,您的本地文件将进行更新以使它与资源库中的版本保持同步。 如果您修改了本地文件中的第 1-10 行,而另一个开发人员删除了第 40-50 行,在文件末尾添加了 12 行新行,同时修改了 30-40 行,然后在您之前他向资源库提交了他的更改,cvs 会智能地将这些更改合并到您本地已修改的副本中,这样你们的更改就都不会丢失。这可以让两个或更多开发人员针对同一文件的不同部分同时操作。 然而,如果两个或多个开发人员更改同一文件的同一部分,那么事情就有些复杂了。如果发生这种情况,cvs 会告诉您有冲突发生。所做的工作不会丢失,但需要手工干预,因为 cvs 需要您提供意见来决定如何合并这些有冲突的更改。 提交 我们过一会儿来看看冲突究竟是如何解决的,但现在,先让我们假设在输入 "cvs update -dP" 后没有冲突 -- 通常都没有冲突。由于没有冲突,本地源码是最新的。可以在主源码目录中输入以下命令来提交对资源库的更改: # cvs commit 提交所起的作用 "cvs commit" 不只将您的更改应用到资源库。在真正将您的更改提交给远程资源库之前,cvs 会调用缺省编辑器,可以让您输入修改的描述。输入了注解后,保存该文件,退出编辑器,您的更改(和注解)就会应用到远程资源库,小组中的其他开发人员可以看到这些更改。 查看日志 要查看某个特定文件完整的历史以及提交时开发人员(包括您)所加的注解是很容易的。要查看这些信息,输入: # cvs log myfile.c "cvs log" 命令是递归的,所以如果您想查看整个目录树的完整日志,只需要进入该目录,输入: # cvs log | less 提交选项 您可能想要使用另一个输入 "cvs commit" 时 cvs 在缺省情况下启动的编辑器。如果是这样,只需要把您希望使用的编辑器的名称放进 EDITOR 环境变量中。另外,也可以将更新日志消息作为命令行选项指定,这样, cvs 就不需要一上来就装入编辑器: # cvs commit -m I fixed a few silly bugs in portage.py .cvsrc 文件 在继续了解其它 cvs 命令前,建议设置 ~/.cvsrc 文件。通过在您主目录中创建 .cvsrc 文件,可以告诉 cvs 在缺省情况下使用您所需的命令行选项,这样就不必每次都输入它们。这里有一个推荐的缺省 .cvsrc 文件: cvs -q diff -u -b -B checkout -P update -d -P 除了为一组 cvs 命令设置有用的选项以外,.cvsrc 的第一行将 cvs 置于安静模式下,它的主要好处是使 "cvs update" 输出更简洁,更具可读性。另外,一旦完成 .cvsrc 后,就可以输入 "cvs update" 而不是 "cvs update -dP"。 将文件添加到资源库 要将源文件添加到 CVS 很容易。首先,用您喜爱的文本编辑器创建该文件。然后,输入以下命令: # cvs add myfile.c cvs server: use cvs commit to add this file permanently 这将告诉 cvs 在您下次执行 "cvs commit" 时,将该文件添加到资源库。在那之前,其它开发人员看不它。 将目录添加到资源库 将目录添加到 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 熟悉 "cvs update" 在了解如何解决冲突之前,先让我们熟悉一下 "cvs update" 命令的输出。如果创建了一个包含 "cvs -q" 行的 ~/.cvsrc 文件,您会发现 "cvs update" 的输出相当容易理解。"cvs update" 通过打印单个字符、空格和文件名告诉您它都做些什么,看到些什么;如下例所示: # cvs update -dP ? distfiles ? packages ? profiles "cvs update" 用 "?" 字符指示在地副本中找到的这些特殊文件。它们不是资源库的正式部分,也不是计划要添加的部分。这里有一个CVS使用的所有其它单字符信息性消息的列表: U [path] 在本地资源库中创建新文件,或者更新了您没有动过的文件时使用。 A [path] 该文件是计划要添加的,使用 "cvs commit" 时,它被正式添加到资源库。 R [path] 象 "A" 一样,"R" 让您知道该文件计划要除去。输入 "cvs commit" 后,该文件就会从资源库中除去。 M [path] 这意味着您已经修改过该文件了;而且,有可能资源库中新的更改已成功地合并到该文件。 C [path] "C" 字符表明该文件存在冲突,需要在使用 "cvs commit" 提交更改前手工修改它。 如何解决冲突 现在,让我们看一下如何解决冲突。我参与了大部分的 Gentoo Linux 项目,我们在 cvs.gentoo.org 上设置了自己的 cvs 服务器。我们这些开发人员花了绝大部分时间来修改 "gentoo-x86" 模块内部的源码。在 gentoo-x86 模块中,有一个叫 "ChangeLog" 的文件,它包含了(您猜一下它)我们对资源库中该文件做的主要更改的描述。 冲突的示例 因为几乎每次开发人员对 CVS 进行主要更改时都会对该文件做一些修改,这就成为冲突的主要根源 -- 这里有冲突的一个示例。假设我在 ChangeLog 的顶部添加了以下行: date 25 Feb 2001 This is the thing I added myself 然而,在我提交这二新行之前,另一个开发人员也在 ChangeLog 的顶部添加了这些行并提交了他的更改: date 25 Feb 2001 This is the part added by another developer 现在,当我运行 "cvs update -dP" (每次提交前您都应该这么做),cvs 不能把他的更改合并到我的 ChangeLog 本地副本,因为我们俩都向文件的同一部分添加了行 -- cvs 怎么知道用哪个版本?所以,CVS 会出现以下错误: RCS file: /home/cvsroot/gentoo-x86/ChangeLog,v retrieving revision 1.362 retrieving revision 1.363 Merging differences between 1.362 and 1.363 into ChangeLog rcsmerge: warning: conflicts during merge cvs server: conflicts found in ChangeLog C ChangeLog 啊 -- 有冲突!幸好消除这些冲突很容易。如果我启动我喜爱的文本编辑器,将会在 ChangeLog 文件的顶部看到以下文本: <<<<<<< ChangeLog date 25 Feb 2001 This is the thing I added myself ======= date 25 Feb 2001 This is the part added by another developer >>>>>>> 1.363 cvs 不是选其中一个而舍弃另一个,而是把两个版本都加进 ChangeLog 文件,并用特殊的分隔符将它们圈起,以明确地标记出有问题的冲突。现在,我要用一个应该出现在 ChangeLog 里的文本来替换这部分;在这种情况下,替换的文本既不是我的版本也不是他的版本,而是两者的组合: date 25 Feb 2001 This is the thing I added myself This is the part added by another developer 我用适当的文本替换掉了有冲突的部分(并除去了 "=======" 等标记),可以顺利地将我的更改提交给 cvs。 无论什么时候需要编辑文件来解决冲突时,都要确保已经浏览过整个文件,以便您知道所有内容;如果您忘记解决某个冲突,那么在这个冲突解决之前,cvs 是不允许您提交的!很显然,除去 cvs 添加到冲突文件中的特殊标记是很重要的。 如果您在解决某个冲突时犯了错误,然后意外地保存了您所作的更改,那么您可以在 ".#filename.version" 文件中找到您的原始副本。 |
|
声明:文章版权归原作者所有 部分文章转自互联网 如有侵权请联系
[邮箱地址] 删除
|