嵌入式之行(7):使用CVS

说明:

笔者对于CVS的使用仅仅限于个人的(即没有团队)、本机的、浅层的使用。下面的例子中仅仅是为了说明问题,在实际应用中所用到的不外那么几个命令:import、checkout、update等等。

1、安装及配置

(1)、安装

安装过程似乎不用说也可以吧?我所用的Red Flag系统已经安装好了,但FC10上没有安装,可以这样:

1
yum install xinetd

按提示进行安装就可以了。

(2)、添加用户

任何一个开发团队使用CVS都应当添加CVS组以及几个CVS用户。但本文没有使用这种方式,因为在一个人使用的情况下,添加组、用户略显麻烦,这告诉我们遇到具体的情况要具体分析并制定符合实际的方案。

如果实在想这样做,添加组和用户也十分easy,如下:

1
2
3
4
groupadd cvs  // cvs组
useradd cvs_latelee // cvs用户
usermod –g cvs cvs_latelee // 添加cvs_latelee到cvs组中
passwd cvs_latelee // 修改密码

(3)、创建CVS仓库目录

目录名称可以为cvs_root或cvs_home或者其它有意义的名称。可以在自己的家目录创建,也可以在系统的/目录下创建,如果是个人使用,可以以root权限将这些目录的权限修改为自己的,如果是团队使用,可以将仓库目录的属性修改为0774。

因为在/目录中,普通用户是不能创建目录的,所以必须以root身份来创建:

1
2
3
cd /
mkdir cvs_home
chown –R latelee:latelee cvs_home

对于latelee:latelee,前一个是指用户,后一个是指用户组,也可以指定为cvs组。当然,在自己的家目录下就不存在这种问题了。

(4)、服务器配置

CVS配置文件在/etc/xinetd.d/cvs文件中(不保证所有的Linux系统中都是此路径),以root身份来修改:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
 default: off

description: The CVS service can record the history of your source

# files. CVS stores all the versions of a file in a single

# file in a clever way that only stores the differences

# between versions.

service cvspserver

{

disable = no

port = 2401

socket_type = stream

protocol = tcp

wait = no

user = latelee // 用户

passenv = PATH

server = /usr/bin/cvs

env = HOME=/var/cvs

server_args = -f --allow-root=/cvs_home pserver// 目录

# bind = 127.0.0.1

}

user指定了用户,server_args指定了仓库目录(/cvs_home)以及访问方式(pserver)。

(5)、启动服务

命令如下:

1
#service xinetd restart

可以看一下2401端口是否处于监听状态:

1
2
3
# netstat -ln | grep 2401

tcp 0 0 0.0.0.0:2401 0.0.0.0:* LISTEN

在fedora中可以让xinetd开机自动启动。

(6)、初始化服务器

初始化服务器有两种方式,一是在终端exportCVSROOT环境变量,二是使用在系统中初始化环境变量,前者只在一个终端有效,后者比较方便。在自己家目录的.bashrc文件最后添加:

1
2
CVSROOT=/cvs_home
export CVSROOT

注意:这里的“家目录”是指你所用的用户目录,比如有人喜欢使用root,那么就要在/root/.bashrc文件添加了。

CVS的初始化命令,普通用户与root用户都可执行,但最好是使用你所用的用户来执行该命令:

1
$ cvs init

初始化成功,会在/cvs_home目录生成一个CVSROOT目录。里面有许多文件,是与CVS相关的。不用理会也行。

##2、使用例子
注意:如果设置了CVSROOT环境变量,则输入cvs命令时可以不指定仓库目录。此处设置了在.bashrc中环境变量CVSROOT=/cvs_home

(1)、常用

检入(import),这里没有-m选项,所以会出现默认的编辑器VI,可以在里面写一些有关的信息。

1
2
3
4
5
6
7
8
9
10
11
[latelee@localhost thread]$ cvs import thread threadproject ver0-1

N thread/thread.cpp

N thread/thread.h

N thread/main.cpp

N thread/Makefile

No conflicts created by this import

没有check out,不能update:

1
2
3
4
5
[latelee@localhost thread]$ cvs update

cvs update: in directory .:

cvs [update aborted]: there is no version here; run 'cvs checkout' first

check out时,会在当前目录下创建该工程目录,注意:我们本来的目录是/home/latelee/linux-c/thread/,之后则变为:/home/latelee/linux-c/thread/thread,当然,也可以在别的目录下check out

1
2
3
4
5
6
7
8
9
10
11
[latelee@localhost thread]$ cvs co thread

cvs checkout: Updating thread

U thread/Makefile

U thread/main.cpp

U thread/thread.cpp

U thread/thread.h

可以看一下某些文件的状态:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
[latelee@localhost thread]$ cvs status -v main.cpp

=========================================================

File: main.cpp Status: Locally Modified

Working revision: 1.1.1.1 Thu Apr 22 04:43:21 2010

Repository revision: 1.1.1.1 /cvs_home/thread/main.cpp,v

Sticky Tag: (none)

Sticky Date: (none)

Sticky Options: (none)

Existing Tags:

ver_0-1 (revision: 1.1.1.1)

thread_project (branch: 1.1.1)

修改某些文件了,但还没有提交到仓库,更新会出现:

1
2
3
4
5
6
7
8
9
10
11
[latelee@localhost thread]$ cvs update

cvs update: Updating .

M main.cpp

M thread.cpp

M thread.h

? thread

其中M代表当前目录下已修改了的文件,这里有三个,?是说thread在仓库里没有找到,因为我检入库时是没有这个文件的,这里是编译后生成的可执行文件,一般来说,在仓库里的基本上都是源代码和说明文档等等,在这里,我不将编译生成的结果检入库。好,那么就检入库:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
[latelee@localhost thread]$ cvs commit

cvs commit: Examining .

Checking in main.cpp;

/cvs_home/thread/main.cpp,v <-- main.cpp

new revision: 1.2; previous revision: 1.1

done

Checking in thread.cpp;

/cvs_home/thread/thread.cpp,v <-- thread.cpp

new revision: 1.2; previous revision: 1.1

done

Checking in thread.h;

/cvs_home/thread/thread.h,v <-- thread.h

new revision: 1.2; previous revision: 1.1

done

当输入cvscommit时,我没有带参数(这里的参数是指文件),则代表目录下所有的文件都入库,这里有三个。回车后,将会出现文本编辑器(此处是VI,当然也可以修改,如-e emacs),在VI中记录修改日志。保存退出,即可。

下面再check out这个工程,在上一目录中执行cvs co thread,它不再是check out,而是update,因为当前目录已有了thread目录了。

1
2
3
4
5
6
7
[latelee@localhost thread]$ ls

main.cpp Makefile thread thread.cpp thread.h //注意,第三个文件thread其实是我们的工程目录

[latelee@localhost thread]$ cvs co thread

cvs checkout: Updating thread

我们再看一下main.cpp的状态:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
[latelee@localhost thread]$ cvs status -v main.cpp

=========================================================

File: main.cpp Status: Up-to-date

Working revision: 1.2 Thu Apr 22 04:57:48 2010

Repository revision: 1.2 /cvs_home/thread/main.cpp,v

Sticky Tag: (none)

Sticky Date: (none)

Sticky Options: (none)

Existing Tags:

ver_0-1 (revision: 1.1.1.1)

thread_project (branch: 1.1.1)

可以看到,版本已经变化了。

(2)、标记

我们创建一个标记:

1
2
3
4
5
6
7
8
9
10
11
[latelee@localhost thread]$ cvs tag prealpha0-1

cvs tag: Tagging .

T Makefile

T main.cpp

T thread.cpp

T thread.h

标记名为prealpha0-1,这个名称可以随意修改。

我也不知道下面这个是什么意思。在书上的:

1
2
3
4
5
6
7
8
9
10
11
[latelee@localhost thread]$ cvs update -d -r prealpha0-1

cvs update: Updating .

U Makefile

U main.cpp

U thread.cpp

U thread.h

再看一下main.cpp的状态:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
[latelee@localhost thread]$ cvs status -v main.cpp

=========================================================

File: main.cpp Status: Up-to-date

Working revision: 1.2 Thu Apr 22 05:02:20 2010

Repository revision: 1.2 /cvs_home/thread/main.cpp,v

Sticky Tag: prealpha0-1 (revision: 1.2)

Sticky Date: (none)

Sticky Options: (none)

Existing Tags:

prealpha0-1 (revision: 1.2)

ver_0-1 (revision: 1.1.1.1)

thread_project (branch: 1.1.1)

改名:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
[latelee@localhost thread]$cvs tag -r prealpha0-1 prealpha0-1branchroot

cvs tag: Tagging .

T Makefile

T main.cpp

T thread.cpp

T thread.h

[latelee@localhost thread]$ cvs status -v main.cpp

=========================================================

File: main.cpp Status: Up-to-date

Working revision: 1.2 Thu Apr 22 05:02:20 2010

Repository revision: 1.2 /cvs_home/thread/main.cpp,v

Sticky Tag: prealpha0-1 (revision: 1.2)

Sticky Date: (none)

Sticky Options: (none)

Existing Tags:

prealpha0-1branchroot (revision: 1.2)

prealpha0-1 (revision: 1.2)

ver_0-1 (revision: 1.1.1.1)

thread_project (branch: 1.1.1)

可见,版本1.2有两个标记,下面我们删除一个:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
[latelee@localhost thread]$ cvs tag -d prealpha0-1

cvs tag: Untagging .

D Makefile

D main.cpp

D thread.cpp

D thread.h

[latelee@localhost thread]$ cvs status -v main.cpp

cvs status: main.cpp is no longer in the repository

=========================================================

File: main.cpp Status: Entry Invalid

Working revision: 1.2 Thu Apr 22 05:02:20 2010

Repository revision: No revision control file

Sticky Tag: prealpha0-1 - MISSING from RCS file!

Sticky Date: (none)

Sticky Options: (none)

Existing Tags:

prealpha0-1branchroot (revision: 1.2)

ver_0-1 (revision: 1.1.1.1)

thread_project (branch: 1.1.1)

是不是有点麻烦?更名过程就是将旧标记贴上新的标记,再将旧标记删除。

(3)、分支测试:

在上面的基础上,添加一个分支:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
[latelee@localhost thread]$ cvs rtag -r prealpha0-1branchroot -b prealpha0-1_branch thread

cvs rtag: Tagging thread

[latelee@localhost thread]$ cvs status -v main.cpp

cvs status: main.cpp is no longer in the repository

=========================================================

File: main.cpp Status: Entry Invalid

Working revision: 1.2 Thu Apr 22 05:02:20 2010

Repository revision: No revision control file

Sticky Tag: prealpha0-1 - MISSING from RCS file!

Sticky Date: (none)

Sticky Options: (none)

Existing Tags:

prealpha0-1_branch (branch: 1.2.2)

prealpha0-1branchroot (revision: 1.2)

ver_0-1 (revision: 1.1.1.1)

thread_project

回到上一目录,将一个分支check out出来:

1
2
3
[latelee@localhost thread]$ cvs co -r prealpha0-1_branch thread

cvs checkout: Updating thread

看一下main.cpp的状态:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
[latelee@localhost thread]$ cvs status main.cpp

=========================================================

File: main.cpp Status: Up-to-date

Working revision: 1.2 Thu Apr 22 05:34:38 2010

Repository revision: 1.2 /cvs_home/thread/main.cpp,v

Sticky Tag: prealpha0-1_branch (branch: 1.2.2)

Sticky Date: (none)

Sticky Options: (none)

注意:在实际开发中,分支最好不要跟主干的目录混在一起。

(4)、远程访问(检出代码)

下面这种方法只适合一个终端,因为export只在一个终端有效。

1
2
3
4
5
6
7
[latelee@FightNow latelee]$ export CVSROOT=:pserver:latelee@192.168.1.13/cvsroot

[latelee@FightNow latelee]$ cvs login

Logging in to :pserver:latelee@192.168.1.13:2401/cvsroot

CVS password: (在这里输入密码)

没有错误,说明已经连接上服务器了。这里进入到一个测试目录:

1
2
3
4
5
[latelee@FightNow latelee]$ cd work/nfs

[latelee@FightNow nfs]$ ls

hello-arm

将代码checkout出来

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
[latelee@FightNow nfs]$ cvs co camera-server

cvs checkout: Updating camera-server

U camera-server/Makefile

U camera-server/video/utils.h

U camera-server/video/v4l2uvc.h

[latelee@FightNow nfs]$ cvs co camera-client

cvs checkout: Updating camera-client

U camera-client/Makefile

U camera-client/main.c

U camera-client/my-types.h

U camera-client/my_udp.c

U camera-client/v4l2/v4l2uvc.h

目录中多了两个文件夹。

1
2
3
4
5
[latelee@FightNow nfs]$ ls

camera-client camera-server hello-arm

[latelee@FightNow nfs]$

上述例子中没有讲如何在开发过程中添加或删除文件(或目录),下面讲一下。在thread工程中添加了fork.cpp文件。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
[latelee@51 thread]$ cvs add fork.cpp

cvs add: scheduling file `fork.cpp' for addition

cvs add: use 'cvs commit' to add this file permanently

[latelee@51 thread]$ cvs commit

cvs commit: Examining .

cvs commit: Up-to-date check failed for `main.cpp'

cvs commit: Up-to-date check failed for `thread.cpp'

cvs commit: Up-to-date check failed for `thread.h'

cvs [commit aborted]: correct above errors first!

出错了!因为没有check out,正确的cvs commit显示如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
[latelee@51 thread]$ cvs commit

cvs commit: Examining .

RCS file: /cvs_home/thread/fork.cpp,v

done

Checking in fork.cpp;

/cvs_home/thread/fork.cpp,v <-- fork.cpp

initial revision: 1.1

done

删除一个文件(fork.cpp)过程如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
[latelee@51 thread]$ rm fork.cpp

[latelee@51 thread]$ cvs remove fork.cpp

cvs remove: scheduling `fork.cpp' for removal

cvs remove: use 'cvs commit' to remove this file permanently

[latelee@51 thread]$ cvs commit

cvs commit: Examining .

Removing fork.cpp;

/cvs_home/thread/fork.cpp,v <-- fork.cpp

new revision: delete; previous revision: 1.1

done

至于目录的添加删除,就不显示了。

又:本文的例子不是同一时间、同一台PC上完成的,但对于使用CVS来说,是没有关系的。