当前位置: 首页 > 图文教程 > 服务器 > Linux服务器 > 并行版本系统CVS简单教程

Linux服务器
Linux上双网卡绑定方法(Suse9SP3)
Linux操作系统调优参数的意义
Linux下使用SSH客户端及其Sftp文件传送
教你恢复被误删除的Linux文件
SQL Server注入大全及防御
Linux无法解析域名的解决办法
Linux系统下安装和配置MyEclipse的方法
Ubuntu下VirtualBox 1.4.0设置文件共享
Windows与Linux系统共享StarDict字典文件
修改Linux下相关的登陆信息
Windows通过SecureCRT远程登录Linux主机
Linux操作系统如何修改SWAP交换区的大小
Linux操作系统下为Apache目录添加密码
Linux时间设置与同步(NTP)
Linux内核补丁AMD旁路转换缓冲(TLB)错误
Linux架设DHCP服务器的方法
Fedora 8下Apache配置与管理
Linux操作系统下用单网卡捆绑双IP的方法
Ubuntu Linux系统环境变量配置文件
SUSE Linux中将Tomcat作为Service运行

Linux服务器 中的 并行版本系统CVS简单教程


出处:互联网   整理: 软晨网(RuanChen.com)   发布: 2009-10-18   浏览: 101 ::
收藏到网摘: n/a

CVS是ConcurrentVersionSystem(并行版本系统)的缩写,用于版本管理。如果大家曾经参与过多人协作开发的项目,大家肯定有这样的痛苦经历:由于多个人同时修改同一个文件,自己辛辛苦苦修改的程序被别人彻底删除了。另外,如果你的软件/程序已经发布了三个版本,而这时候用户需要你修改第二个版本的东西,也许你会因为只保留了最新版本而痛哭流涕。还有就是你对程序做了一些修改,但是修改很少,你只想给远方的同事发一个两个版本之间的差别文件,这样可以免于邮箱不够大,网速太慢之类的问题。为了解决类似这样的问题,以及诸如生成补丁文件,历史版本修改等,一帮黑客(褒义)在原先Unix体系里很成熟的SCCS和RCS的基础上,开发了CVS.(SCCS:SourceCodeControlSystem,RCS:RevisionControlSystem)

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

由于CVS是典型的C/S结构的软件,因此它也分成服务器端和客户端两部分。不过大多数CVS软件都把它们合二为一了。


结合文档和一些网上资源,我写一点非常简单的“速成”的教材.希望对大家有用.

下面是我的步骤和做法:

前提要求:

  • root权限;
  • CVS软件,请找到相关的rpm,tgz,deb等包装上,或者到
    http://www.cvshome.org/CVS/Dev/code
    下载原程序编译安装,这里我不准备介绍它的安装,请参考CVS自身的文档安装.我使用Slackware的tgz包,安装的命令是
    #installpkgcvs*.tgz
    其他包请参考对应包管理工具的命令.
  • 一定的系统资源,要有一定内存(32M就能工作得很好),要一定的磁盘空间,看你的项目的大小和多少而定.
架设CVS服务器:
  1. 建立CVSROOT目录,因为这里涉及到用户对CVSROOT里的文件读写的权限问题,所以比较简单的方法是建立一个组,然后再建立一个属于该组的帐户,而且以后有读写权限的用户都要属于该组.假设我们建一个组叫cvs,用户名是cvsroot.建组和用户的命令如下

     

      #groupaddcvs
      #addusercvsroot

       

    生成的用户家目录在/home/cvsroot(根据自己的系统调整)

     

  2. 用cvsroot用户登陆,修改/home/cvsroot(CVSROOT)的权限,赋与同组人有读写的权限:

     

      $chmod771.(或者770应该也可以)

      注意:这一部分工作是按照文档说明做的,是否一定需要这样没有试验,我会在做试验后在以后版本的教程说得仔细一点.如果您有这方面的经验请提供给我,谢谢.

  3. 建立CVS仓库,(仍然是cvsroot用户),用下面命令:

     

      $cvs-d/home/cvsrootinit

       

  4. 以root身份登陆,修改/etc/inetd.conf(使用xinetd的系统没有此文件)和/etc/services,

      如果用的是inetd的系统,在/etc/inetd.conf里加入:
      cvsserverstreamtcpnowaitroot/usr/bin/cvscvs-f--allow-root=/home/cvsrootpserver

      说明:上面的行是单独一整行,/usr/bin/cvs应该是你的cvs版本的命令路径,请根据自己的系统调整./home/cvsroot是你建立的CVSROOT的路径,也请根据上面建立目录的部分的内容做调整.

      如果是使用xinetd的系统,需要在/etc/xinetd.d/目录下创建文件cvspserver(此名字可以自己定义),内容如下:


      #default:on
      #description:Thecvsserversessions;

      servicecvsserver
      {
      socket_type=stream
      wait=no
      user=root
      server=/usr/bin/cvs
      server_args=-f--allow-root=/cvsrootpserver
      log_on_failure+=USERID
      only_from=192.168.0.0/24
      }


      其中only_from是用来限制访问的,可以根据实际情况不要或者修改。修改该文件权限:


      #chmod644cvspserver

      在/etc/services里加入:


      cvsserver2401/tcp

      说明:cvsserver是任意的名称,但是不能和已有的服务重名,也要和上面修改/etc/inetd.conf那行的第一项一致.这里我用的是CVS的口令认证方式,CVS还有其他认证方式,我没有做试验,如果您有经验,请补充,谢谢.

  5. 添加可以使用CVS服务的用户到cvs组:
      以root身份修改/etc/group,把需要使用CVS的用户名加到cvs组里,比如我想让用户laser和gumpwu能够使用CVS服务,那么修改以后的/etc/group应该有下面这样一行:

      cvs:x:105:laser,gumpwu


      在你的系统上GID可能不是105,没有关系.主要是要把laser和gumpwu用逗号分隔开写在最后一个冒号后面.当然,象RedHat等分发版有类似linuxconf这样的工具的话,用工具做这件事会更简单些.

  6. 重起inetd使修改生效:

     

      #killall-HUPinetd

      如果使用的是xinetd的系统:


      #/etc/rc.d/init.d/xinedrestart

这样服务器就设置完成了.我们接着搞客户端.

设置客户端

如果是Linux(或者其他*nix),客户端和服务器端的软件是一样的,如果是Win,MAC等平台,请到

http://www.loria.fr/cgi-bin/molli/wilma.cgi/rel

找相应的客户端软件,这里我先说一下在Linux(*nix)里怎么做:

  1. 设置环境变量CVSROOT:

     

      $exportCVSROOT=:pserver:laser@the_server_name:/home/cvsroot

      注意:这里的pserver是访问方式,我在上面设置的是口令认证,所以这里是pserver,如果你的CVS服务器设置成别的访问模式,那么需要相应修改.laser是可以使用CVS服务器的用户名,这里可以根据你的设置修改,我在这个版本设置的是直接使用系统用户的口令文件,也就是说laser必须是CVS服务器上的合法用户,这里当然有安全问题,CVS可以设置成为拥有自己的用户,我将在以后的版本里面增加这些内容,或者您也可以提供一些补充,或者直接读CVS的文档.the_server_name是CVS服务器的名称或者IP地址,根据你的情况填写,/home/cvsroot是你的CVS服务器的CVSROOT目录,根据你的CVS服务器设置做修改或者询问管理员.你可以把这行放到你的shell的profile里(.bash_profile,.profile等)这样就不用每次敲一长串命令了.

  2. 登陆CVS服务器:

     

      $cvslogin,这时候cvs会问你口令,请把你在CVS服务器上的口令敲进去,这里是laser在CVS服务器上的系统用户的口令:
      Passwd:xxxxxxxx


      成功登陆后将在你的家目录建立一个.cvspass文件,以后就不用输入口令了.

好,客户端设置完成,简单吧.

管理cvs服务器

服务器可以用了,现在大家最关心的就是如何管理服务器,比如,我想让一些人有读和/或写CVS仓库的权限,但是不想给它系统权限怎么办呢?


不难,在cvs管理员用户(在我这里是cvsroot用户)的家目录里有一个CVSROOT目录,这个目录里有三个配置文件,passwd,readers,writers,我们可以通过设置这三个文件来配置CVS服务器,下面分别介绍这几个文件的作用:

passwd:cvs用户的用户列表文件,它的格式很象shadow文件:

{cvs用户名}:[加密的口令]:[等效系统用户名]

如果你希望一个用户只是cvs用户,而不是系统用户,那么你就要设置这个文件,刚刚安装完之后这个文件可能不存在,你需要以cvs管理员用户手工创建,当然要按照上面格式,第二个字段是该用户的加密口令,就是用crypt(3)加密的,你可以自己写一个程序来做加密,也可以用我介绍的偷懒的方法:先创建一个系统用户,名字和cvs用户一样,口令就是准备给它的cvs用户口令,创建完之后从/etc/shadow把该用户第二个字段拷贝过来,然后再把这个用户删除.这个方法对付数量少的用户比较方便,人一多就不合适了,而且还有冲突条件(racecondition)的安全隐患,还要root权限,实在不怎么样.不过权益之计而已.写一个小程序并不难,可以到linuxforum的编程版搜索一下,有个朋友已经写了一个贴在上面了.

第三个字段就是等效系统用户名,实际上就是赋与一个cvs用户一个等效的系统用户的权限,看下面的例子你就明白它的功能了.

readers:有cvs读权限的用户列表文件.就是一个一维列表.在这个文件中的用户对cvs只有读权限.

writers:有cvs写权限的用户的列表文件.和readers一样,是一个一维列表.在这个文件中的用户对cvs有写权限.

上面三个文件在缺省安装的时候可能都不存在,需要我们自己创建,好吧,现在还是让我们用一个例子来教学吧.假设我们有下面几个用户需要使用cvs:

laser,gumpwu,henry,betty,anonymous.

其中laser和gumpwu是系统用户,而henry,betty,anonymous我们都不想给系统用户权限,并且betty和anonymous都是只读用户,而且anonymous更是连口令都没有.那么好,我们先做一些准备工作,先创建一个cvspub用户,这个用户的责任是代表所有非系统用户的cvs用户读写cvs仓库.

#adduser
...

然后编辑/etc/group,令cvspub用户在cvs组里,同时把其它有系统用户权限的用户加到cvs组里.(见上文)

然后编辑cvs管理员家目录里CVSROOT/passwd文件,加入下面几行:

laser:$xxefajfka;faffa33:cvspub
gumpwu:$ajfaal;323r0ofeeanv:cvspub
henry:$fajkdpaieje:cvspub
betty:fjkal;ffjieinfn/:cvspub
anonymous::cvspub

注意:上面的第二个字段(分隔符为:)是密文口令,你要用程序或者用我的土办法生成.

编辑readers文件,加入下面几行:

anonymous
betty

编辑writer文件,加入下面几行:

laser
gumpwu
henry

这样就ok了,你再用几个用户分别登陆测试,就会发现一切都ok了.这里面的原理和说明我想就不多说了,其实很简单,和系统管理用户的概念是一样的.

现在服务器和客户端都设置好了,那么怎么用呢,我在这里写一个最简单的(估计也是最常用的)命令介绍:

首先,建立一个新的CVS项目,一般我们都已经有一些项目文件了,这样我们可以用下面步骤生成一个新的CVS项目:

  1. 进入到你的已有项目的目录,比如叫cvstest:
      $cdcvstest
  2. 运行命令:
      $cvsimport-m"thisisacvstestproject"cvstestv_0_0_1start
      说明:import是cvs的命令之一,表示向cvs仓库输入项目文件.
      -m参数后面的字串是描述文本,随便写些有意义的东西,如果不加-m参
      数,那么cvs会自动运行一个编辑器(一般是vi,但是可以通过修改环境变量
      EDITOR来改成你喜欢用的编辑器.)让你输入信息,
      cvstest是项目名称(实际上是仓库名,在CVS服务器上会存储在以这个名字
      命名的仓库里.)
      v_0_0_1是这个分支的总标记.没啥用(或曰不常用.)
      start是每次import标识文件的输入层次的标记,没啥用.
这样我们就建立了一个CVS仓库了,然后,我们可以把这个测试项目的文件删除.试验一下如何从仓库获取文件.这里我假设上面的所有客户端工作你都已经做过了.
运行下面的命令:
$cvscheckoutcvstest
从仓库中检索出cvstest项目的源文件.
如果你已经做过一次checkout了,那么不需要重新checkout,只需要进入cvstest项目的目录,更新一把就行了:
$cdcvstest
$cvsupdate一下即可.又或者你不想直接更新,只是想看看有没有更新的东西,那么:
$cvsstatus
这时后会打印出一长串状态报告(你可能需要用类似less这样的命令分页显示,或者定向到一个输出文件里慢慢看.),对项目中的每个文件有一份状态报告,类似这样:
===================================================================
File:foo.cStatus:Up-to-date

Workingrevision:1.1.1.1'SomeDate'
Repositoryrevision:1.2/home/cvsroot/cvstest/foo.c,v
StickyTag:(none)
StickyDate:(none)
StickyOptions:(none)

这里最重要的就是Status栏,这里总共可能有四种状态:
Up-to-date:表明你要到的文件是最新的.
LocallyModified:表明你曾经修改过该文件,但还没有提交,你的版本比仓库里的新.
NeedingPatch:表明有个哥们已经修改过该文件并且已经提交了!你的版本比仓库里的旧.
NeedsMerge:表明你曾经修改过该文件,但是偏偏有个不识相的也修改了这个文件,而且还提交给仓库了!

如果你只是想保持软件的同步的话(象我),那么上面的东西就足够用了.可是如果多人协作开发项目的话,可就不是了这么简单了.当你参加项目,维护文件时,就需要更多命令,比如说你我都是某nasdaq项目的开发人员:

1,你对某个文件做了修改,比如说改了ceo.c,加了一行程序:printf("wherecanIfindVCtocheat!");
改完之后你要把修改提交给仓库,用命令:
$cvscommit-m"addacomplain"ceo.c
或者就是:
$cvscommit-m"worryaboutmoney"
让cvs帮你检查哪个文件需要提交.

2,当我开始干活的时候,可能我先:
$cvsstatus
一把,这时候我会看到:

==================================================================
File:ceo.cStatus:NeedingPatch

Workingrevision:1.1.1.1'SomeDate'
Repositoryrevision:1.2/home/cvsroot/nastaq/ceo.c,v
StickyTag:(none)
StickyDate:(none)
StickyOptions:(none)

于是我知道有人改了ceo.c,于是我就:
$cvsupdateceo.c
或者干脆:
$cvsupdate
把ceo.c这个文件更新为最新版本,然后再干活.然后提交.

如果这天你修改了coo.c,加了一行puts("howaboutanotherkindofbragging?");
并且提交了,但是这时候我已经$cvsstatus过了,就是说我不知道你的修改.
而我加了一行printf("Youmustshamelesslyandseemsknowingnesstoactasacoo");
并且傻乎乎地提交:
$cvscommitcoo.c
这时候,CVS会告诉我
cvscommit:Examing.
cvsserver:Up-to-datecheckfailedfor'coo.c'
cvs[serveraborted]:correctaboveerrorfirst!

于是我知道有个狗屎在我修改文件的当口做了提交,于是我
$cvsupdate
这时cvs会报告:
RCSfile:/home/cvsroot/nasdaq/coo.c,v
retrievingrevision1.1.1.1
retrievingrevision1.2
Mergingdifferencesbetween1.1.1.1and1.2intocoo.c
rcsmerge:warning:conflictsduringmerge
cvsupdate:conflictsfoundincoo.c
Ccoo.c
告诉你coo.c有版本冲突,于是我编辑coo.c,这时一般文件里看起来象这样:
...
printf("Youmustshamelesslyandseemsknowingnesstoactasacoo");
<<<<<<<foo.c
=======
...
puts("howaboutanotherkindofbragging?");
>>>>>>>1.2
...

于是我把上面改成:
printf("Youmustshamelesslyandseemsknowingnesstoactasacoo");
puts("howaboutanotherkindofbragging?");
然后
$cvscommit-m"merged"coo.c
于是下回你再更新的时候就有新的补钉要打...如此往复,直到完成所有修改.
不过这里有一些要注意的地方就是删除程序,如果你删掉一行对你可能没有用的程序
puts("tobehonest");而我不想删除(因为我有用),而我不知情地直接:
$cvsupdate
了,那么我的这行程序也完蛋了,所以这里我们要注意所有开发人员的协调,千万不要乱删东西,大不了用
#if0
#endif
宏定义对括起来.实在要删东西,那最好先标记一个版本:
$cvstagv_0_0_1

然后你可以发布并删除你自己的工作目录里这个版本的文件(注意:不是删除仓库里的.):

$cvsrelease-dnasdaq

然后你再生成一个新分支:

$cvsrtag-b-rv_0_0_1v_0_0_1_1nasdaq

然后再建立v_0_0_1_1的分支

$cvscheckout-rv_0_0_1_1nasdaq

编辑并修改这个分支的文件,这样的做法比较好.

不过要注意的是,新标记和新分支的建立最好由项目的管理人员负责,否则每个人都做一个分支,那么仓库就太乱了.因此,比较的开发人员之间的直接沟通是不能忽略的.一般来说,在互联网上的标准模式是有一个管理员(可能自己并不写程序),有一个邮递列表,大家都在邮递列表上交流看法和做各种决议.当形成决议之后,管理员做一个新版本的标记.以此循环.

还有一些命令,比如要增加一个文件garbage_china_concept_stocks_list:

$cvsaddgarbage_china_concept_stocks_list

然后还要:

$cvscommitgarbage_china_concert_stocks_list

看起来有点象数据库里的事务?的确是这样.CVS维护着一个本地的参考文件(在CVS/Entries里),这样提交的时候就可以一次地把所有改变放到服务器端,这样也更安全.同样,如果想删除文件bankrupted_web_site:

$rmbankrupted_web_site
$cvsremovebankrupted_web_site
$cvscommitbankrupted_web_site

3,一些小技巧:
$Header$标记:把这个标记放在文件的任何地方都会被cvs替换成最后修改的cvs用户名,该文件当前版本号,最后修改时间,该文件的cvs仓库路径,看起来象下面这个样子:

//$Header:/home/cvsroot/simhost/simhost.cpp,v1.22001/04/2008:26:10jqliuExp$

一般我们把它放在开头,这样对程序员修改文件非常便利,很多时候你只要看一眼开头就知道文件是否最新.

$Id$标记:把这个标记放在文件的任何地方都会被cvs替换成最后修改的cvs用户名,该文件当前版本号,最后修改时间,该文件的cvs仓库路径,看起来象下面这个样子:

$Id:simhost.cpp,v1.32001/04/2402:27:36simhostExp$

好了,上面所有的东西,估计就是我们用cvs时80%情况下用的命令和内容,包括文件的更新,提交,冲突的解决,分支的派生,增删文件等.实际上cvs的功能之强大,远远超出我在这里描述的内容,我这个"速成"也就管不了太多了,希望随着时间的推移,我们能够更加有效地使用CVS.也希望大家能够不断补充这篇文章,最后能够成为手册,而不仅仅是速成.当然,还要更多地参考别的文档.

上一页[1][2]