CVS 管理

CVS 管理

--- 以本次建立的 CVS 系统为例

1. CVS 简介

CVS (Concurrent Versions System)是一个版本控制系统。使用它,你可以记录下你的源文件的历史。例如:修改软件时可能会产生一些bug,而且可能过了很久你才会察觉到它们的存在。有了CVS,你可以很容易地恢复旧版本,并从中看出到底是哪个修改导致了这个bug 。有时这是很有用的。当然了,你可能把所有版本的所有文件都保存了下来。但这会浪费大量的磁盘空间。而CVS用一种聪明的办法来保存一个文件的所有版本——仅仅保存不同版本之间的区别——在一个文件里。如果你是项目开发组的一员,CVS也会帮助你。除非极为小心,成员之间很容易互相覆盖文件。一些编辑器,如GNU Emacs,会保证同一时间内同一文件绝不会被两个人修改。不幸的是,如果有人用了另外的编辑器,这种保护就没用了。CVS用隔离开不同的开发者解决了这个问题。每个开发者在他自己的目录里工作,等每一个开发者都完成了他们自己的工作后,CVS会将它们合并到一起。CVS最初由Dick Grune在1986年12月以shell scripts的形式发布在comp.sources.unix的新闻组第6卷里。虽然当前的CVS中没什么代码来自于这些shell scripts,但许多CVS的冲突解决算法是从它们来的。1989年4月,Brian Berliner设计了CVS并编写了代码,之后Jeff Polk帮助Brian设计了CVS模块发行分支。

CVS 是一个C/S系统,多个开发人员通过一个中心版本控制系统来记录文件版本,从而达到保证文件同步的目的。工作模式如下:

CVS 服务器(文件版本库)

/ | \

(版 本 同 步)

/ | \

开发者1 开发者2 开发者3

2. 建立 CVS 服务器

1) 管理员

可以专门建立一个 CVS 管理员帐号,供 CVS 管理员使用,以后一切关于 CVS 管理的事情,都通过该帐号来完成。

这里,我们以 192.168.0.148 为 CVS 服务器的主机,在里面开设帐号 casic 为管理员帐号,帐号所在的组设为 casic ,凡是想加入 CVS 系统的用户,都必须加入 casic 组。

我们也会为每个开发人员开设帐号,以方便大家使用 CVS 系统。

2) 建立 CVS 服务器

以帐号 casic 登录 192.168.0.148 。

I. 创建 CVS 源代码仓库

创建目录 /home/casic/cvsroot 作为 CVS 源代码仓库。

II. 设置环境变量 CVSROOT

csh:

在 home 目录下的 .cshrc 文件中加入

setenv CVSROOT /home/casic/cvsroot

bash:

在 home 目录下的 .bashrc 文件中加入

export CVSROOT=/home/casic/cvsroot

具体的关于环境变量设置的文件请见附录给出的样例。

III. 初始化 CVS

运行命令:

cvs init

前提是刚才设置的环境变量已经起作用,如果没有起作用,使用命令

cvs –d /home/casic/cvsroot init

当然,尽快使刚才设置的环境变量起作用,以方便以后的操作。

初始化以后,会在 /home/casic/cvsroot 目录下出现一个子目录 CVSROOT ,里面放置了 CVS 服务器的配置文件。至于如何配置,下面再讲。

至此, CVS 服务器已经搭建好了,但只能在本地使用,想要远程使用,还得让服务器运行起来才行。

IV. 运行 CVS 服务器

使用 root 帐号登录,在 /etc/xinetd.d/ 目录下创建文件 cvspserver ,内容如下:

service cvspserver

{

port = 2401

socket_type = stream

protocol = tcp

wait = no

user = root

passenv = PATH

server = /usr/bin/cvs

server_args = -f --allow-root=/home/casic/cvsroot pserver

}

注意:

server : 后面为可执行程序 cvs 的全路径

server_args : 后面 /home/casic/cvsroot 为 CVS 源码库的路径

修改该文件权限:

chmod 644 cvspserver

然后重新启动 xinetd :

/etc/rc.d/init.d/xinetd restart

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

netstat -lnp|grep 2401

若出现以下信息,则服务器已经运行起来了。

tcp 0 0 0.0.0.0:2401 0.0.0.0:* LISTEN 7866/xinetd

3. 设置 CVS 服务器

以帐号 casic 登录。

这里我们只做极简单的改动,以使在 /home/casic/cvsroot/CVSROOT 目录下产生一个文件 commitlog 记录每次文件的修改。

基本命令操作请参照另一份文档《 CVS 常用命令》。我们可以直接对 CVS 仓库进行操作,但这样做容易出错且不容易恢复,所以不到万不得以,我们对 CVS 库的操作都应该通过 CVS 的命令进行。

这里,我们只修改文件 /home/casic/cvsroot/CVSROOT/loginfo ,首先提取它:

cvs co CVSROOT/loginfo

进入工作目录 CVSROOT ,对 loginfo 作如下修改:

a) 并在文件的开头添加一行:

# $Id$

b) 将其最后一行的行首的注释符删除

c) 在最下面添加两行:

ALL (echo ""; id; echo %{sVv}; date; cat) > $CVSROOT/CVSROOT/.temp_commitlog

ALL cat | $CVSROOT/CVSROOT/commit_mail %s

注意大小写,保存该文件,然后将其提交。提交以后再打开该文件,你会发现刚刚加入 的 $Id$ 已经被 cvs 自动扩展了,记录了文件名、版本号、修改时间和修改人。

在上面 loginfo 的修改中,我们使用了一个命令: $CVSROOT/CVSROOT/commit_mail ,这是一个用来发信的脚本,需要自己写。

该文件的内容如下:

$CVSROOT/CVSROOT/commit_mail:

#! /bin/csh

# $Id$

set tmplog="$CVSROOT/CVSROOT/.temp_commitlog"

cat $tmplog | grep "$CVSROOT/pub" >> /dev/null

if ( $status ) then

set maillist=`cat $CVSROOT/CVSROOT/cvs-maillist`

mail -s "CASIC CVS Mail: $1" $maillist < $tmplog

endif

这个脚本的作用是:在每次有人提交的时候,都会发信给所有使用 CVS 的人。当然,排除了 pub 这个目录的提交,即大家在 pub 里练习 cvs 命令的时候所作的提交不会发信给大家。

同时,在把 commit_mail 拷贝到目录 $CVSROOT/CVSROOT 的时候,也把它提交到 CVS 库里。

同时还要在 $CVSROOT/CVSROOT 里维护一个 CVS 邮件列表:文件 cvs-maillist ,里面是所有可以使用 CVS 的用户的列表。格式很简单:

casic

ynding

dyn

这样,简单的设置就结束了。

4. 导入源代码

下面要做的就是要将以前的源代码导入 CVS 库了。

在建立 CVS 服务器以前,我们已经积累了相当多的代码了,现在将这些代码存入 CVS 源码库。

1) 导入命令 cvs import

我们第一次提交源代码时使用命令 cvs import 。将要导入的源代码放到一个目录下,该目录下只有要导入的源代码文件和子目录。

进入该目录,运行命令:

cvs import –m “comment for project_name” project_name vendor_tag release_tag

其中: vendor_log 为开发商标志, release_tag 为版本标志, release_tag 很有用,下面会讲到怎么用它。

运行结束后,就将该目录下的文件、子目录都导入到 CVS 库了。

cvs import 命令并不改变你运行它的当前目录,也不把当前目录当作 CVS 的工作目录。导入以后,如果你想要修改文件,可以在其他目录里把它提取出来再修改。

2) 导入举例

以本次导入的 EP7312 项目为例。

CVS 主要是用来记录源代码的历史,所以在导入的时候,我们就不能一下子把最新的版本导入进去,得分层次地把源代码导进去,首先把最初始的从网上下载的没有改动的源代码导进去,然后将移植的补丁打进去,再把打过补丁的源代码导进去。

I. 导入初始未改动的源代码

建立目录 /home/casic/temp/ep7312 ,将 linux-2.4.13.tar.gz 解压缩到目录 /home/casic/temp/ep7312 下,移除 linux-2.4.13.tar.gz ,这样,在目录 /home/casic/temp/ep7312 下只有一个 linux 子目录。

进入目录 /home/casic/temp/ep7312 ,运行命令:

cvs import –m “Project EP7312” ep7312 EP7312 EP7312_1_0

这里源代码比较多,导入需要比较长的时间,耐性等待到导入结束。

这时可以查看一下目录 /home/casic/cvsroot ,可以发现里面多了一个目录 ep7312 ,该目录下就就刚才导入的源代码文件,不过文件名后面都有 “,v” 标记(目录没有),说明这些文件已经入库了。

II. 导入添加了补丁的源代码

回到刚才的目录,将补丁程序拷贝到目录 /home/casic/temp 下,然后进入目录 /home/casic/temp/ep7312/linux ,依次将补丁添加进来:

gunzip < ../../patch-2.4.13-ac4.gz | patch -p1 -t

gunzip < ../../patch-2.4.13-ac4-rmk1.gz | patch -p1 -t

gunzip < ../../patch-2.4.13-ac4-rmk1-codegen1.gz | patch -p1 –t

然后

cp edb7312 arch/arm/def-configs

这样,补丁就添加完了。

下面开始导入添加完补丁的代码,进入目录 /home/casic/temp/ep7312 ,运行命令:

cvs import –m “patches for EP7312” ep7312 EP7312 EP7312_1_1

注意 release_tag 的变化,下面就要利用 release_tag 来将这个分支合并到主干上。

III. 合并分支到主干

进入目录 /home/casic/temp ,建立目录 merge ,进入目录 merge ,运行命令:

cvs co –jEP7312_1_0 –jEP7312_1_1 ep7312 >& log

之所以要将 cvs co –jEP7312_1_0 –jEP7312_1_1 ep7312 的输出到文件 log ,是因为输出的信息下面我们要用到。

执行完成后,打开 log 文件,会看到很多文件前打了 R 标记,表示该文件被移除了,需要使用命令 cvs ci 来确认。下面再介绍一下其它标记的含义(对 cvs update 也一样):

U 提取的文件跟库里一样。

P 跟 U 差不多,不过提取的是一个补丁而不是整个文件。

A 文件被 cvs add 添加了,但没有用 cvs ci 确认。

R 文件被 cvs rm 删除了,但没有用 cvs ci 确认。

M 文件被改动了,可以用 cvs ci 提交了。

C 合并的时候存在冲突。

? 文件在工作目录里,但不在库里。

检查 log 的内容,看看有哪些标记,结果只有 U 和 R ,将标 R 的文件找出来,然后将其一一用命令 cvs ci 提交。

这样,合并就完成了。

3) 其他导入类似

目前已导入的 CVS 源码库的目录结构如下:

/home/casic/cvsroot/at91

CVSROOT

dev-tools

ep7312

misc-docs

pub

at91/bootloader

dev-docs

uClinux-dist

CVSROOT: 配置文件

dev-tools/cross-compiler-2.95.3-ep7312

cross-compiler-at91

ep7312/dev-docs

linux

romdisk

user

misc-docs: 存放其他各种文档。

pub: 供大家练习 cvs 命令

5. 设置客户端

上面的一切操作都是在 CVS 服务器本地机器上进行的。但实际情况下,很多开发人员的机器并不 CVS 服务器,需要在自己的机器上进行操作开发;而且如果大家都跑到 CVS 服务器上来操作开发的话, CVS 服务器也会不堪重负,无论是系统负荷还是硬盘空间。

下面就讲讲如何远程访问 CVS 服务器。

首先要在 CVS 服务器上开设用户帐号,并加入 casic 组,这里假设开设了帐号 ynding 。给帐号 ynding 设置环境变量 CVSROOT 的值为 /home/casic/cvsroot

这样,在 CVS 本地机上帐号 ynding 就可以访问 CVS 库了。

在远程机器上也建立帐号 ynding (当然也可以是其他帐号,开发时为了不混淆,取相同的帐号名为好),也给该 ynding 设置环境变量 CVSROOT :

setenv CVSROOT :pserver:ynding@192.168.0.148:/home/casic/cvsroot

或者

export CVSROOT=:pserver:ynding@192.168.0.148:/home/casic/cvsroot

设置完以后,并让环境变量起作用以后,就可以使用 CVS 服务器了。

先要登录到 CVS 服务器上:

cvs login

会提示输入密码,输入帐号 ynding 在 CVS 服务器上的密码,就能登录成功了。以后的对 CVS 服务器的操作跟在 CVS 服务器本地操作一样。完事以后,记得使用命令 cvs logout 退出 CVS 服务器。

6. 打标签,建分支

1) 确认项目里程碑

当项目开发的一定时间后,可以给所有文件指定一个阶段里程碑版本号,方便以后按照这个里程碑版本号导出项目,同时,也是多个项目分支开发的基础。

指定里程碑版本号就是给当前最新的版本打上一个标签,运行命令:

cvs tag release_1_0_project_name

这样,就给项目打上了一个标签,表示这就是 1.0 版本了,以后要提取这个 1.0 版本只要运行命令:

cvs co –r release_1_0_project_name project_name

就可以把 1.0 版本提取出来了。

这样,就可以进入 2.x 的开发了。运行命令:

cvs ci –r 2

就可以使所有的文件版本号变为 2.0 ,从而进入 2.x 的开发了。

注意:

项目里文件的版本号跟项目的发布版本没有直接关系,但所有文件的版本号跟发布版本一直有助于维护。所以,将所有文件的版本号都改为 2.x 不是必需的。

还有,在以标签提取出来的项目里,对文件的改动不能提交到 CVS 库里,会提示错误信息:这不是一个分支。

2) 建立分支

在开发 2.x 的时候,如果发现 1.0 版本有问题需要修复。这时一般并不在 2.x 里修改,一来是因为 2.x 还处于开发阶段,还不稳定,二来是在 2.x 里可能已经添加了很多新的功能,并不想让 1.0 的用户白白得到。

这时,我们可以为 1.0 建立一个分支,在这个分支了修改 bug 。这时,上面介绍的打的标签就起了作用,运行命令:

cvs rtag –b –r release_1_0_project_name release_1_0_project_name_patch project_name

这样就建立了一以 1.0 版本为基础的分支。在改分支里修改完 bug 以后,将修改提交到该分支里。

这时也可以在该分支里打一个标签:

cvs tag release_1_0_project_name_bug_fixed_1

当然了,也可以在当前工作目录下打标签,不管你提取的项目是以前的版本、补丁还是分支等等,直接在当前目录下运行命令:

cvs tag –b release_1_0_project_name_branch

这样就建立起一个分支了。提取分支和按发布版本提取的方法一样:

cvs co –r release_1_0_project_name_branch project_name

7. 分支操作

CVS 允许你修改代码到不同的开发线上,这就是分支( branch ) 。当你改变一个分支中的文件时,这些更改不会出现在主开发主干 (main trunk) 和其它分支中。

1) 访问分支

有两种方式可以进入分支:重新提取出一份或从当前工作目录切换过去。

A. 重新提取一份

运行命令:

cvs co –r release_1_0_project_name project_name

-r 后面跟的是标签名。

B. 切换

在当前工作目录下运行命令:

cvs update –r release_1_0_project_name project_name

这对现有拷贝是主干代码或是其他分支都是有效的,上面的命令把它转移到命名的分支。跟 cvs update 相似, cvs update –r 将合并你所做的任何改动,请注意有没有冲突出现。

一旦你的工作拷贝转移到一个特定的分支,它将一直保持在这个分支内,除非你做了其他操作。这意味着从这个工作拷贝的提交将添加到这个分支的新版本中,而不影响主干和其他分支。

想看一个工作拷贝是基于哪一个分支的,可以使用命令 cvs status 命令,在输出的结果中查看“ Sticky Tag ”项,如果为 none ,则处于主干中,如果不是,则处于该分支中。

例如,在 pub 目录下运行命令:

cvs st test.txt

结果:

File: test.txt Status: Locally Modified

Working revision: 1.4 Fri Aug 1 01:18:12 2003

Repository revision: 1.4 /home/casic/cvsroot/pub/test.txt,v

Sticky Tag: release_08_03_pub (revision: 1.4)

Sticky Date: (none)

Sticky Options: (none)

则处于分支 releae_08_03_pub 中。

使用 -v 选项还可以看出该文件处于哪些分之中,运行命令:

cvs st –v test.txt

结果:

File: test.txt Status: Locally Modified

Working revision: 1.4 Fri Aug 1 01:18:12 2003

Repository revision: 1.4 /home/casic/cvsroot/pub/test.txt,v

Sticky Tag: release_08_03_pub (revision: 1.4)

Sticky Date: (none)

Sticky Options: (none)

Existing Tags:

release_08_03_pub_patch_2 (branch: 1.4.4)

release_08_03_pub_patches (branch: 1.4.2)

release_08_03_pub (revision: 1.4)

注意结果:

如果在标签名后面的括号里的注释为 revision ,则是单纯的一个标签;如果是 branch ,则是一个分支。

2) 合并整个分支

你可以合并另一个分支上的修改到你的工作目录,只要在 update 命令中加 -j branchname 的标识。使用 -j branchname 将合并这个派生分支点与原版本的最新版之间的变更 ( 到你的工作目录 ) 。 -j 的意思是“ join ”。

例如,我们要将分支 release_1_0_project_name_branch 合并到主干中:

cvs co project_name

进入工作目录:

cvs update –jrelease_1_0_project_name_branch

注意有没有冲突发生,有的话解决以后再提交:

cvs ci –m “include release_1_0_project_name_branch”

也可以在提取的时候加上 -j 选项:

cvs co –jrelease_1_1_project_name_branch project_name

cvs ci –m “include release_1_0_project_name_branch”

效果和上面讲到的相同,当然也要注意处理冲突的问题。

3) 从一个分支多次合并

经过上面的合并以后,分支 release_1_0_project_name_branch 继续开发,经过一段时间后,又要合并到主干中。如果仍使用命令

cvs update –j release_1_0_project_name_branch

则将试图合并你已经合并过的东西,这可能导致一些不希望发生的事情。

因此,必须表达清楚你希望合并未被合并的内容,这样需要两个“ -j ”选项。 CVS 合并从第一个“ -j ”的版本到第二个“ -j ”的版本的变化。

例如:

cvs update –j1.2.2.2 -j release_1_0_project_name_branch

如果出现的问题是你必需手工指定版本号 1.2.2.2 ,一个更好的方法是使用:

cvs update –j release_1_0_project_name_branch:yesterday

-j release_1_0_project_name_branch ( 应该是在同一行 )

然而,最好的方法是在每一次合并以后给分支加一个标签,然后可以使用标签进行以后的合并:

cvs update -j release_1_0_project_name_branch_02

-j release_1_0_project_name_branch ( 应该在同一行 )

4) 合并两个任意版本之间的不同

使用两个 ”-j revision” 选项, cvs update 和 cvs co 命令能合并任意两个不同的版本的差异到你目录:

cvs update –j1.5 –j1.3 test.txt

这个命令将把 1.5 版本恢复到 1.3 版本,所以一定要注意版本的顺序。

如果你在操作多个文件时使用这个选择项,你必须了解在不同的文件之间,版本的数字可能是完全不同的。你必须使用标笺( tag )而不是使用版本号来完成多个文件的操作。

使用两个 -j 操作也能恢复增加或删除的文件。例如,假定你有一个叫 file1 的文件在在于 1.1 版本中,然后你删除了它(因此增加了一个 dead 版本 1.2 )。现在你又打算恢复它,并用它原先的内容。下面是如何操作的例子:

cvs update -j 1.2 -j 1.1 file1

然后再提交一下:

cvs ci –m “restore file1” file1

5) 合并能添加和删除文件

如果你在合并时做的改变涉及到添加或删除一些文件, cvs update –j 和 cvs co -j 将反映这些变化。

示例请参考本文档开头导入源代码时合并两个分支的情形。

6) 合并与关键字

如果你要合并的文件中包含关键字,你会得到一大堆冲突,这是因为关键字与合并的版本关联。因此,你需要指定 -kk 在合并的命令行里面。这样只会替换关键字名而不包括里面的值。这个选项认为那些都是相同的,使合并避免产生假的冲突。

8. 添加 CVS 用户

1) 添加系统用户

在 CVS 服务器上添加一个系统用户,并加入 casic 组。

然后给该用户设置环境变量 CVSROOT 。

2) 修改 CVS 邮件列表

直接修改文件 /home/casic/cvsroot/cvs-maillist ,在里面添加新加入的用户名。

3) 修改 Sendmail 别名列表

修改文件 /etc/mail/aliases ,在里面添加新加入用户的邮箱别名。

9. 附录

1) bash

刚刚建立帐号时, home 目录下可能还没有环境的配置文件,如果想用 bash ,则要在自己的 home 目录下建立两个文件: .bash_profile 和 .bashrc

以帐号 dyn 为例,在 /home/dyn 目录下建立文件 .bash_profile 和 .bashrc ,文件的内容如下:

.bash_profile:

# .bash_profile

# Get the aliases and functions

if [ -f ~/.bashrc ]; then

. ~/.bashrc

fi

# User specific environment and startup programs

PATH=$PATH:$HOME/bin

export PATH

unset USERNAME

.bashrc:

# .bashrc

# User specific aliases and functions

# Source global definitions

if [ -f /etc/bashrc ]; then

. /etc/bashrc

fi

CVSROOT=:pserver:dyn@192.168.0.148:/home/casic/cvsroot; export CVSROOT

2) csh

刚刚建立帐号时, home 目录下可能还没有环境的配置文件,如果想用 csh ,则要在自己的 home 目录下建立一个文件: .cshrc

以帐号 ynding 为例,在 /home/ynding 目录下建立文件 .cshrc ,文件的内容如下:

.chsrc:

#!/usr/bin/csh

###set path###

set path=( . \

/usr/bin \

/usr/local/arm/2.95.3/bin \

/usr/local/arm-elf/bin \

/usr/local/bin \

/usr/bin \

/bin \

/usr/sbin \

/usr/local/sbin \

/usr/X11R6/bin \

/usr/X11R6/LessTif/Motif1.2/bin \

)

###ENVIRONMENTAL SETTING

setenv CVSROOT /home/casic/cvsroot

###END

umask 027

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值