codefans

导航

<2024年12月>
24252627282930
1234567
891011121314
15161718192021
22232425262728
2930311234

统计

常用链接

留言簿(2)

随笔分类

随笔档案

文章分类

文章档案

程序设计链接

搜索

最新评论

阅读排行榜

评论排行榜

在linux环境下,cnix的开发中cvs的初步使用

 


© 2003-7 arfankai
欢迎转载,但请保留作者,请不要用于商业性质
last modified 2003-7-23


本文主要讲的是linux操作系统下,在cnix的开发中,cvs的初步使用。

一,什么是cvs? 为什么要使用cvs? cvs的作用。

CVS是Concurrent Version System(并行版本系统)的缩写,用于版本管理,尤其在多人团队合作的开发模式中作用巨大。

为什么要使用CVS呢? 如果各位有过团队合作开发的经验就会知道,在团队合作开发中,要对整个项目的各个文件进行控制是多么繁琐的一件事情,经常会出现不同的人修改了同一个程序,而需要人工合并整理。更糟糕的是,项目会出现多个版本,连开发者自己都不知道自己修改了那些文件,大量的精力消耗在各个版本,各个文件的整合中。这些精力完全可以避免,而省下更多的精力用在项目本身之中。

CVS还有一个更加重要的特性:能记下每个文件的每次修改,以及如何被修改。。。对于基于Internet 的合作方式来说,这些特性太重要了。一个地域上分散的自愿者组织显然不可能投入很多的时间来训练其成员彼此合作。因为这样的话,当该组织有成员变更的时候,为此付出的投资将损失殆尽。所以需要指定一套基本的项目分配方案,以确保新成员能较容易的适应工作,同时也需要设置一个自动的系统来接受外来代码,并使每个成员能及时得到最新修改的代码。

CVS的特点--能通过网络访问源代码(实际上我们后面会讲到,就是拷贝一份源代码到本地),
能同步开发,(废话;)
能自动对修改进行合并。(这个好!!)


二,CVS的工作方式--"拷贝-修改-合并"模型。

CVS是这样组织的:(假设基于网络的合作模式,并且以cnix为例子)
远程的gro.clinux.org上面保存着cnix的repository(源代码库),项目开发者拥有自己的一个 working copy(工作拷贝),这个工作拷贝是通过使用cvs checkout 命令从源代码库中申请得到。之后,项目开发者可以在自己的工作拷贝上进行修改,修改了之后可以进行提交( cvs commit)。由cvs负责对各个开发者所修改的部分进行整合。如下图:

                    cnix(repository)
                       |
            ---------+------------------------------------------------------------------
            |                                          |               |           |            |
          cnix                                      cnix           ...
       (working copy)                  (working copy)

三,CVS基本术语

让我们来了解一下CVS中会经常提到的一些术语:

Revision(修订版本)--文件历史记录中的被开发者提交的变化。一个修订版本就是一个时常变化的项目的snapshot(瞬态图)。

Repository(源代码库)--CVS存储所有修订版本历史记录的地方。每个项目都有自己的一个确定的源代码库。(ft。。晦涩,简单说,就是远程gro上的cnix源代码库)

Working copy(工作拷贝)--开发者对文件作出修改时文件所在的拷贝(ft。。晦涩难懂,简单来说,就是我自己机器上的一份远程cnix的拷贝拉)

Check out(检验)--从源代码库中申请一份工作拷贝。该工作拷贝反映的是取出时项目的瞬时状态。当开发者对拷贝作出修改时,必须运用commit(提交)和update(更新)命令来 "发布"变化和查看其他开发者所作的修改。
(简单来说,就是你需要使用CVS中的check out命令来从gro上得到一份cnix的工作拷贝)

Commit(提交)--将工作拷贝中的变化输入中央源代码库。
(简单来说,就是如果你修改了你自己的工作拷贝,并且想发布这些修改,那么你需要使用 CVS中的commit命令提交这些修改到gro的cnix仓库中;)

Log message(日志信息)--提交修订版本的时候,附带描述变化的注解。通过查阅记录信息,人们可以获得一个当前项目进程的总结。
(还是要简单的来说一下,xixi, 你每次cvs commit的时候,它都会要求你输入一些log,你可以写一下你这次修改的目的,修改了那些地方。。。这样做的好处是别人可以通过查看cvs log得知你的修改,还可以通过一个cvs到ChangeLog 的工具把这些Log自动的转化成Gnu的ChangeLog格式)

Update(更新)--从源代码库中取出别人的修改数据,将其输入自己的工作拷贝,并显示自己的工作拷贝是否有未提交的修改。注意,不要和commit(提交)混淆,更新和提交是一对互补的指令。记住:Update将使工作拷贝和源代码库拷贝保持同步更新。
(简单来说,就是是试图使自己本地的工作拷贝更新到跟ropository一致的状态。)

Conflicts(冲突)--俩个开发者对同一个区域所作的变化都提交给主版本时出现的情况,在 CVS觉察并指出这个冲突后,开发者必须解决该冲突。
(怎么解决,看下去,我会举一个例子)


四,CVS中比较常用和简单的命令介绍

(1),cvs import
使用这个命令进行源代码的第一次导入。比如远程gro中还没有cnix的时候,需要使用:

[kai@kai cnix ]$ cd ~/Projects/cnix
[kai@kai cnix ]$ cvs import -m "import cnix" cnix arfankai start
把当前目录下的项目导入到远程gro的源代码仓库中,作为一个项目最初的开始。

(2),cvs checkout
具体使用的时候可以缩写成cvs co。
使用这个命令从远程的源代码库导出一份cnix的代码到本地。比如:

[kai@kai / ]$ cd ~/
[kai@kai kai ]$ export CVS_RSH=ssh 
[kai@kai kai ]$ cvs -z3 -d arfankai@cvs.cnix.gro.clinux.org:/cvs/cnix co cnix
cvs server: Updating cnix
U cnix/Makefile
U cnix/define.mk
cvs server: Updating cnix/boot
U cnix/boot/boot.S
U cnix/boot/head.S
cvs server: Updating cnix/driver
U cnix/driver/Makefile
U cnix/driver/ide.c
... ...
之后,在你的家目录里将会看到一个cnix的目录。

(3),cvs commit
具体使用的时候,可以缩写成cvs ci。
使用这个命令把你修改的文件提交给远程的cvs server。假设我修改了cnix/Makefile文件:

[kai@kai cnix ]$ cvs status Makefile
======================================================
File: Makefile          Status: Locally Modified

   Working revision:    1.1.1.1
   Repository revision: 1.1.1.1 /cvs/cnix/cnix/Makefile,v
   Sticky Tag:          (none)
   Sticky Date:         (none)
   Sticky Options:      (none)

[kai@kai cnix ]$
然后提交之~,如下:
[kai@kai cnix <118>]$ cvs ci -m "test by arfankai" Makefile
Checking in Makefile;
/cvs/cnix/cnix/Makefile,v  <--  Makefile
new revision: 1.2; previous revision: 1.1
done
[kai@kai cnix <119>]$
-m选项后面接的是log msg.

(4),cvs status
简单的用法如(3)所示。用于看一个文件的状态。

(5),cvs add
往源代码库里面增加一个文件或者是一个空的目录名。注意:你使用这个命令的时候, 文件名或者是目录名必须是已经在你的本地工作目录中有了,然后才能添加。注意2:如果添加的是文件,那么你使用这个命令之后,并不会立刻在远程repository中就会出现该文件,还需要使用cvs ci命令。如果添加的是目录名,那么会立刻放映到远程repository。

建立一个空的本地test文件:

[kai@kai cnix <173>]$ touch test
把test文件加入到工作列表:
[kai@kai cnix <174>]$ cvs add test
cvs server: scheduling file `test' for addition
cvs server: use 'cvs commit' to add this file permanently
使用cvs ci提交文件到远程源代码库:
[kai@kai cnix <175>]$ cvs ci -m "add test" test
RCS file: /cvs/cnix/cnix/test,v
done
Checking in test;
/cvs/cnix/cnix/test,v  <--  test
initial revision: 1.1
done
经过这样俩步,文件tmp.c才真正的加入到了源代码仓库中。

(6),cvs delete
删除一个文件或者目录。
删除一个文件的步骤分三步:

1),删除本地工作目录中的该文件。(我们以删除刚才加入的test文件为例子)

[kai@kai cnix <181>]$ rm test

2),将删除的文件加入到工作列表:cvs remove 文件名

[kai@kai cnix <182>]$ cvs remove test
cvs server: scheduling `test' for removal
cvs server: use 'cvs commit' to remove this file permanently

3),提交删除动作到远程源代码库:cvs ci 文件名
(从另外一个方面来说,添加和删除都是一个"修改",所以他们对于源代码库来说是一样的,都需要提交这些"修改")

[kai@kai cnix <183>]$ cvs ci -m "remove test" test
Removing test;
/cvs/cnix/cnix/test,v  <--  test
new revision: delete; previous revision: 1.1
done

(7),cvs update
更新本地工作拷贝。可以缩写成cvs up
cvs update 文件名(目录名)

cvs up 文件名(目录名)

cvs up (不加参数,则会更新当前目录所有的文件以及递归的子目录文件)

如果要连源代码库中新增的目录也下载,则要加上 -d 选项。
cvs up -d

举例如下:

[kai@kai cnix <198>]$ cvs up
cvs server: Updating .
U test                                                 <---把源代码库中的test文件更新到本地。
cvs server: Updating boot                   <---依序检查各个子目录
cvs server: Updating driver
cvs server: Updating fs
cvs server: Updating include
cvs server: Updating include/asm
cvs server: Updating include/cnix
cvs server: Updating init
cvs server: Updating kernel
cvs server: Updating lib
cvs server: Updating mm
cvs server: Updating shell
cvs server: Updating shell/app
cvs server: Updating tools

(8),cvs diff
比较版本差异。当发现本地工作拷贝和源代码库中的文件不一致时,可以了解差异之处。
cvs diff 文件名

cvs diff (不加文件名参数,表示递归的比对当前目录所有的文件和文件夹)
(具体的例子我不举了)

(9),cvs log
查询记录,可以缩写成cvs lo
比如,查询一下Makefile文件的记录:

[kai@kai cnix <200>]$ cvs log Makefile

RCS file: /cvs/cnix/cnix/Makefile,v
Working file: Makefile
head: 1.2
branch:
locks: strict
access list:
symbolic names:
        start: 1.1.1.1
        asmcos: 1.1.1
keyword substitution: kv
total revisions: 3;     selected revisions: 3
description:
----------------------------
revision 1.2
date: 2003/07/22 13:35:45;  author: arfankai;  state: Exp;  lines: +1 -0
test by arfankai
----------------------------
revision 1.1
date: 2003/03/25 09:51:27;  author: asmcos;  state: Exp;
branches:  1.1.1;
Initial revision
----------------------------
revision 1.1.1.1
date: 2003/03/25 09:51:27;  author: asmcos;  state: Exp;  lines: +0 -0

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

五,如何使用CVS进行cnix的开发。

(本来已经写了好多了,突然停电。。。55)

在前一份文档中,我已经讲了一些本地ssh的设置的问题。请参考这里:
http://cnix.gro.clinux.org/doc/dev_cnix.htm 按照那份文档设置好之后,我们可以使用cvs checkout出一份cnix的本地working copy.

[kai@kai / ]$ cd ~/
[kai@kai kai ]$ export CVS_RSH=ssh 
[kai@kai kai ]$ cvs -z3 -d arfankai@cvs.cnix.gro.clinux.org:/cvs/cnix co cnix
cvs server: Updating cnix
U cnix/Makefile
U cnix/define.mk
cvs server: Updating cnix/boot
U cnix/boot/boot.S
U cnix/boot/head.S
cvs server: Updating cnix/driver
U cnix/driver/Makefile
U cnix/driver/ide.c
... ...
之后,在你的家目录里将会看到一个cnix的目录。以后的所有修改都可以在这个目录中进行。

现在假设一种情况:我把cnix checkout到本地之后,由于忙毕业设计的事情,一个礼拜没有怎么看代码。今天想起Makefile有一个bug,于是先在本地改正之~
准备提交之前,先用cvs update更新一下本地的working copy.

[kai@kai cnix <11>]$ cvs up
cvs server: Updating .
M Makefile                                                  <---本地修改了Makefile文件
cvs server: Updating boot
cvs server: Updating driver
cvs server: Updating fs
cvs server: Updating include
cvs server: Updating include/asm
cvs server: Updating include/cnix
cvs server: Updating init
cvs server: Updating kernel
cvs server: Updating lib
cvs server: Updating mm
U mm/page_alloc.c                                    <---合作者新添加了page_alloc.c文件
P mm/memory.c                                       <---合作者修改了memory.c文件
cvs server: Updating shell
cvs server: Updating shell/app
cvs server: Updating tools
[kai@kai cnix <12>]$

可以看到,cvs会提示一些文件的状态。比如Makefile文件前面有一个"M"标志,表示本地有修改,还没有提交到源代码库。mm目录下的page_alloc.c文件是新增加的("U"标志),可能是在这一个礼拜中的某个时候,xiexiecn或者是ps/2或者是asmcos或者是别的开发者添加了这个文件,所以现在运行cvs update 会update到本地。mm目录下的memory.c 可能被其他的合作者进行了修改("P"标志),所以也会由cvs更新到本地。

运行cvs update之后,就能把源代码库中的更新的文件更新到本地。现在需要做的是把我自己的修改Makefile提交到源代码库。

[kai@kai cnix <13>]$ cvs ci -m "test" Makefile
Checking in Makefile;
/cvs/cnix/cnix/Makefile,v  <--  Makefile
new revision: 1.3; previous revision: 1.2
done
[kai@kai cnix <14>]$

我们来考查几种比较简单的情况下,CVS的处理方式:

ps/2和xiexiecn各自都从gro的cvs源代码库中取了一份工作拷贝。ps/2随意编辑自己的工作拷贝, xiexiecn也编辑自己的工作拷贝。

(1),ps/2修改的是mm/memory.c; xiexiecn修改的是kernel/sched.c。
ps/2修改好了memory.c,进行提交(cvs commit),xiexiecn也修改好了sched.c,进行提交(俩人提交的时间是独立的,没有联系)。由于俩人修改的是不同的文件,所以互不相干。都能很好的将这些修改提交到repository,并可附上修改记录(可多可少,不明确规定)。

假设ps/2先进行了提交,然后看电视去了:p,xiexiecn提交了sched.c之后,还想再工作一会,于是他先使用cvs status看一下,会发现memory.c已经被ps/2修改,可以使用
cvs update mm/memory.c
更新memory.c文件,使得自己的工作拷贝在最update的状态。

(一般来说,一个开发者在决定修改之前,最好是先使用cvs status看一下想要修改的文件,如果别人已经有了修改,就可以先update一下,然后再在这个新版本的基础上进行修改,这样可以省却很多麻烦:)

(2),某一时刻,ps/2和xiexiecn都对mm/memory.c产生兴趣,各自在自己的工作拷贝上对这个文件进行了修改,但是ps/2修改的是文件开头的几行,比如加入了一些版权信息; xiexiecn修改的是文件的最后,比如添加了一个函数。一句话:他们修改的是一个文件的不同文本区。

然后他们分别进行提交,CVS也能很好的处理这些修改,并且把他们俩个人的修改自动的整合到repository中的memor.c,v中。(Great!!)

下次当ps/2又想对memory.c进行修改的时候,记得我刚才的建议吗?:) 可以先使用
cvs status mm/memory.c
看一下这个文件的状态,会发现需要update,于是使用
cvs update mm/memory.c
update之~,再在这个基础上进行修改,以后会愉快得多:) 。。。

(3),某一时刻,ps/2和xiexiecn都对mm/memory.c产生兴趣,各自在自己的工作拷贝上对这个文件进行了修改,并且他们修改的是同一个部分。比如在同一行各自加了条不一样的注释。 ps/2 加了一条:
//This is test.
xiexiecn加的是另外一条:
/* This is a test */

之后他们提交各自不同的修改,这样将会产生冲突。我们假设ps/2先进行了这项提交,他会很顺利的提交成功。然后当xiexiecn也试图提交memory.c的修改时,CVS将会告诉他发现一个冲突(conflicts),并且提交不会成功。CVS会要求你先解决掉这个冲突(conflicts)。于是 xiexiecn可以先使用
cvs status mm/memory.c
看一下本地的memory.c和repository的memory.c的状态报告。如下:

~/Projects/cnix/mm $ cvs status memory.c
=======================================================
File: memory.c       	Status: Needs Merge(需要合并)

   Working revision:	1.14
   Repository revision:	1.14	/cvs/cnix/cnix/mm/memory.c,v
   Sticky Tag:		(none)
   Sticky Date:		(none)
   Sticky Options:	(none)

~/Projects/cnix/mm $

然后使用cvs update 命令先update到本地:

~/Projects/cnix/mm $ cvs update memory.c
RCS file: /cvs/cnix/cnix/mm/memory.c,v
retrieving revision 1.14
retrieving revision 1.15
Merging differences between 1.14 and 1.15 into memory.c (合并到本地的memory.c中)
rcsmerge: warning: conflicts during merge (合并的过程中发现有冲突)
cvs server: conflicts found in memory.c
C memory.c
~/Projects/cnix/mm $ 

可以发现,cvs 提示合并的过程中发现冲突(conflicts)。
我们看一下memory.c文件的相应部分,就可以发现,memory.c文件对应部分变成这样:

<<<<<<< memory.c
/* This is a test */
=======
//This is test.
>>>>>>> 1.15

这就是冲突标记。
xiexiecn需要在整理这个冲突之后(比如只留下这一行: /* This is a test */) 再提交一个已解决冲突的新版本。也许xiexiecn和ps/2需要彼此交流一下以解决分歧。

六,总结

综上,CVS的基本使用是非常简单的,而CVS在自由软件中的作用却是巨大的。可以这么说,如果不学会CVS的基本使用,不会理解到合作开发的乐趣。
希望各位能从cnix中得到自己想要的东西。

参考资料:

1,CVS开源软件开发技术,Karl Fogel 著,肖虎勤 陈军等翻译,机械工业出版社
2,http://linux.tnc.edu.tw/techdoc/cvs/book1.html (简单参考手册,很不错)
3,http://www.soforge.com/cvsdoc/zh_CN/book1.html (详细手册)
4,http://www.uml.net.cn/sjms/sjms051612.htm
5,http://www.igenus.org/resource/CVS/cvs.txt
还有很多很多,google一下吧,别偷懒:)

posted on 2005-09-14 13:40 春雷的博客 阅读(212) 评论(0)  编辑  收藏


只有注册用户登录后才能发表评论。


网站导航: