Linux下CVS的安装、配置与使用(一):安装与本地使用

来源:互联网 发布:电脑包 知乎 编辑:程序博客网 时间:2024/06/06 01:47

1. 到官网http://cvs.nongnu.org/ 下载安装包,官网上发布了rpm和源码格式的安装包。笔者使用的Linux版本为CentOS6.3-64bit,在官网下载的cvs-1.11.18-cvshome.org.9x.1.i386.rpm安装失败,所以只能下载源码格式的安装包了。本处下载的版本为cvs-1.11.23.tar.gz。

2. 安装步骤
a. 检查是否安装了cvs
#rpm -qa | grep cvs
如果通过rpm文件安装了cvs,上面的命令会输出安装的版本号。如果安装了可用rpm -e方式卸载
如果是通过源码方式安装的cvs,用rpm -qa命令是查不到的,所以用下面的命令
#cvs --version
如果已经安装了,也会输出cvs的版本等信息。
b. 解压源文件
#tar zxvf cvs-1.11.23.tar.gz
解压后产生cvs-1.11.23文件夹。
c. 进入cvs-1.11.23目录运行配置文件
./configure
d. #make
这个时候出现错误
In file included from getline.c:25:
getline.h:15: error: conflicting types for ‘getline’
/usr/include/stdio.h:673: note: previous declaration of ‘getline’ was here
getline.c:158: error: conflicting types for ‘getline’
/usr/include/stdio.h:673: note: previous declaration of ‘getline’ was here
make[2]: *** [getline.o] Error 1
make[2]: Leaving directory `/home/chanon/Softwares/JavaEE/cvs-1.11.23/lib'
make[1]: *** [all-recursive] Error 1
make[1]: Leaving directory `/home/chanon/Softwares/JavaEE/cvs-1.11.23'
make: *** [all] Error 2
意思是cvs-1.11.23/lib目录下的getline.h的第15行和getline.c的第158行中函数名getline跟/usr/include/stdio.h文件中的函数名产生冲突,即是stdio.h中也声明了getline函数。为了解决这个冲突,只需把getline.h的第15行和getline.c的第158行中的函数名getline改成get_line就可以了。
重新make,通过,没有错误。
e. #make install
注意得用root权限执行,不然权限不够,某些安装的动作无法执行。
f. 安装完成,检查是否安装成功
#cvs -v
Concurrent Versions System (CVS) 1.11.23 (client/server)
Copyright (C) 2006 Free Software Foundation, Inc.
Senior active maintainers include Larry Jones, Derek R. Price,
and Mark D. Baushke.  Please see the AUTHORS and README files from the CVS distribution kit for a complete list of contributors and copyrights.
CVS may be copied only under the terms of the GNU General Public License, a copy of which can be found with the CVS distribution kit.
Specify the --help option for further information about CVS
3. CVS配置与使用
a. 首先创建Repository的目录,我们在/usr/local下创建cvsroot目录,作为Repository的目录。
[root@localhost ~]# mkdir /usr/local/cvsroot
b. 将创建的目录指定为CVS Repository
[root@localhost ~]# cvs -d /usr/local/cvsroot/ init
这时CVS会在/usr/local/cvsroot目录下生成一个CVSROOT文件夹,用来保存CVS的管理信息。
[root@localhost ~]# cd /usr/local/cvsroot/
[root@localhost cvsroot]# ls
animals  CVSROOT

c. 这里我们自己创建一个临时的项目,用来演示放进Repository,假设项目的名称叫Animals。
首先创建/usr/local/Animals文件夹作为我们的项目目录:
[root@localhost cvsroot]# mkdir /usr/local/Animals
进入Animals目录新建两个文件Animals.java和Dog.java,其内容如下
/*****Animals.java*****/
public class Animals {
public static void main(String[] args) {
Dog aDog = new Dog();
aDog.bark();
}
}

/*****Dog.java*****/
public class Dog {
public void bark() {
System.out.println("Dog bark.");
}
}
d. 将项目导入CVS的Repository,一般Repository里面的项目名是以小写开头的,所以我们设置项目Animals在Repository里面的项目名为animals。
首先进入我们要导入的项目的目录下
[root@localhost cvsroot]# cd /usr/local/Animals/
接着使用CVS的import命令将项目导入/usr/local/cvsroot
[root@localhost Animals]# cvs -d /usr/local/cvsroot import -m "" animals animals initial
N animals/Animals.java
N animals/Dog.java
No conflicts created by this import
这条命令的-d参数是用来定义导入的Repository,关键字import表示要导入一个项目,-m和""(空字符串)是用来给导入项目添加一个注释的,这里我们为空。之后的animals表示导入的项目在repository的名称。最后的两个参数是标签,暂时不管。
可以看到执行导入命令后,CVS提示我们新增了两个文件,N表示New的意思。
导入完成后,我们可以看到在/usr/local/cvsroot中多了一个animals的文件夹
[root@localhost Animals]# ls /usr/local/cvsroot
animals  CVSROOT
animals就是我们导入的项目,可以看到里面已经有了我们两个项目文件的版本信息了
[root@localhost Animals]# ls /usr/local/cvsroot/animals/
Animals.java,v  Dog.java,v
现在可以看到,我们的文件已经安全的保存到Repository里面了。
e. 前面的步骤我们都是用管理员root权限执行,接下来我们要讲解这个项目的其他开发人员(用户)如何check out这个项目的代码。
i. 首先创建一个用户组,就叫做AnimalsGroup
[root@localhost Animals]# groupadd AnimalsGroup
ii. 为AnimalsGroup组创建两个新用户Jim和David
[root@localhost Animals]# adduser -G AnimalsGroup Jim 
[root@localhost Animals]# id Jim
uid=501(Jim) gid=502(Jim) groups=502(Jim),501(AnimalsGroup)
[root@localhost Animals]# adduser -G AnimalsGroup David
[root@localhost Animals]# id David
uid=502(David) gid=503(David) groups=503(David),501(AnimalsGroup)
在Centos里面,useradd和adduser的作用是完全一样的。都是在创建了用户之后,会在/etc/passwd文件中加一条新建用户的记录,然后在/home目录下创建新用户的主目录,并把/etc/skel目录中的文件复制到这个主目录下面。 注意:这种方法创建的新用户,在设置密码之前是不能登陆到系统上的,你需要在root权限下使用“passwd 用户名”的方法为指定的用户设置密码。下次才能以该用户名和密码登陆到系统中。
这里我们将密码设置为123456
[root@localhost cvsroot]# passwd Jim
Changing password for user Jim.
New password: 
BAD PASSWORD: it is too simplistic/systematic
BAD PASSWORD: is too simple
Retype new password: 
passwd: all authentication tokens updated successfully.
[root@localhost cvsroot]# passwd David
Changing password for user David.
New password: 
BAD PASSWORD: it is too simplistic/systematic
BAD PASSWORD: is too simple
Retype new password: 
passwd: all authentication tokens updated successfully.
iii. 将当前用户切换为Jim,在Jim的主目录下创建一个工作目录JimWork用来Check Out animals项目文件
[root@localhost animals]# su Jim
[Jim@localhost animals]$ cd
[Jim@localhost ~]$ mkdir JimWork
iv. 进入JImWork,执行cvs的Check Out指令,co表示Check Out的意思,后面接着要Check Out的项目名称
[Jim@localhost ~]$ cd JimWork/
[Jim@localhost JimWork]$ cvs -d /usr/local/cvsroot/ co animals
cvs checkout: failed to create lock directory for `/usr/local/cvsroot/CVSROOT' (/usr/local/cvsroot/CVSROOT/#cvs.history.lock): Permission denied
cvs checkout: failed to obtain history lock in repository `/usr/local/cvsroot'
cvs checkout: Updating animals
cvs checkout: failed to create lock directory for `/usr/local/cvsroot/animals' (/usr/local/cvsroot/animals/#cvs.lock): Permission denied
cvs checkout: failed to obtain dir lock in repository `/usr/local/cvsroot/animals'
cvs [checkout aborted]: read lock failed - giving up

由Check Out命令输入的结果我们可以知道执行失败,失败的原因是cvs要在/usr/local/cvsroot/CVSROOT创建#cvs.history.lock和/usr/local/cvsroot/animals中创建#cvs.lock时,权限不够,我们可以查下这两个目录的权限
[Jim@localhost JimWork]$ ll /usr/local/cvsroot/
total 8
drwxrwxr-x. 2 root root 4096 Jan  9 00:49 animals
drwxrwxr-x. 3 root root 4096 Jan  9 00:48 CVSROOT
可以看到必须是root用户或者root用户组才能有在这两个目录下创建文件的权限,接下来我们要做的是把这两个目录的用户组改为AnimalsGroup,这样Jim就属于这两个文件的组用户了。当然首先得切换到root用户才有这个权限,建议打开多个terminal,并切换到不同用户,这样就不用来回切换那么麻烦了。下面讲解时不再提示当前用户,大家从命令行的提示符可以看出来。
[root@localhost cvsroot]# chgrp -v AnimalsGroup CVSROOT
changed group of `CVSROOT' to AnimalsGroup
[root@localhost cvsroot]# chgrp -v AnimalsGroup animals/
changed group of `animals/' to AnimalsGroup
chgrp命令是是change group,-v表示输出结果的详细信息,AnimalsGroup表示更改后所属的用户组,最后一个参数表示更改的目录或文件。
现在Jim就可以在他的工作目录下Check out了。
[Jim@localhost JimWork]$ cvs -d /usr/local/cvsroot/ co animals
cvs checkout: Updating animals
U animals/Animals.java
U animals/Dog.java
[Jim@localhost JimWork]$ ls
animals
[Jim@localhost JimWork]$ ls animals/
Animals.java  CVS  Dog.java
可见,Check Out成功之后JimWork目录下出现了我们要导出的项目文件夹了。再看项目文件夹里面,除了有我们之前的两个项目文件Animals.java和Dog.java,还多了一个文件夹CVS,这里面存放了cvs的控制信息,能够记录我们在本地工作目录做了哪些修改。
f. 修改代码,更新Repository
i. 好了,既然我们Check Out了项目信息,那么我们就可以对代码进行修改了。我们在Animals.java文件中添加两行
/*****Animals.java*****/
public class Animals {
       public static void main(String[] args) {
               System.out.println("Hello Everyone!");
               System.out.println("Here is a dog barking.");
               Dog aDog = new Dog();
               aDog.bark();
       }
}
ii. 我们可以通过status命令来查看项目文件的状态,即可以查看当前目录下所有文件的状态,也可以指定查看某一个文件的状态
[Jim@localhost animals]$ cvs status 
cvs status: Examining .
===================================================================
File: Animals.java     Status: Locally Modified

  Working revision:1.1.1.1 Wed Jan  9 08:49:57 2013
  Repository revision:1.1.1.1 /usr/local/cvsroot/animals/Animals.java,v
  Sticky Tag: (none)
  Sticky Date:(none)
  Sticky Options:(none)

===================================================================
File: Dog.java         Status: Up-to-date

  Working revision:1.1.1.1 Wed Jan  9 08:49:57 2013
  Repository revision:1.1.1.1 /usr/local/cvsroot/animals/Dog.java,v
  Sticky Tag: (none)
  Sticky Date:(none)
  Sticky Options:(none)

[Jim@localhost animals]$ cvs status Animals.java 
===================================================================
File: Animals.java     Status: Locally Modified

  Working revision:1.1.1.1 Wed Jan  9 08:49:57 2013
  Repository revision:1.1.1.1 /usr/local/cvsroot/animals/Animals.java,v
  Sticky Tag: (none)
  Sticky Date:(none)
  Sticky Options:(none)
可以看到cvs能够为我们识别到Animals.java在本地修改过,还没有提交到Repository。
iii. cvs不仅能通过status命令查看文件的状态,还能通过diff命令查看文件修改的地方。
[Jim@localhost animals]$ cvs diff Animals.java 
Index: Animals.java
===================================================================
RCS file: /usr/local/cvsroot/animals/Animals.java,v
retrieving revision 1.1.1.1
diff -r1.1.1.1 Animals.java
3a4,5
> System.out.println("Hello Everyone!");
> System.out.println("Here is a dog barking.");
上面的3a4,5表示Animals.java第三行后面添加了4-5行这两行新的代码,并在下面通过>列出新增代码。
另外,diff命令还可以让我们把原代码跟修改代码一起比较
[Jim@localhost animals]$ cvs diff --side-by-side Animals.java 
}


iv. 修改了代码之后需要把我们代码的修改更新到Repository,这个可以通过commit命令完成。-m参数后面跟着这次更新的说明,如果没有使用这个参数,cvs会转到一个界面。
[Jim@localhost animals]$ cvs commit -m "Print some introduction first."
cvs commit: Examining .
Checking in Animals.java;
/usr/local/cvsroot/animals/Animals.java,v  <--  Animals.java
new revision: 1.2; previous revision: 1.1
done
可以看出,cvs只更新有修改的文件,并且更新了版本号。
查看文件的状态,已经是最新版本了
[Jim@localhost animals]$ cvs status Animals.java 
===================================================================
File: Animals.java     Status: Up-to-date

  Working revision:1.2 Wed Jan  9 13:00:17 2013
  Repository revision:1.2 /usr/local/cvsroot/animals/Animals.java,v
  Sticky Tag: (none)
  Sticky Date:(none)
  Sticky Options:(none)
[Jim@localhost animals]$ cvs log Animals.java 
RCS file: /usr/local/cvsroot/animals/Animals.java,v
Working file: Animals.java
head: 1.2
branch:
locks: strict
access list:
symbolic names:
initial: 1.1.1.1
animals: 1.1.1
keyword substitution: kv
total revisions: 2;selected revisions: 2
description:
----------------------------
revision 1.2
date: 2013/01/09 13:18:06;  author: Jim;  state: Exp;  lines: +2 -0
Print some introduction first.
----------------------------
revision 1.1
date: 2013/01/09 08:49:57;  author: chanon;  state: Exp;
branches:  1.1.1;
Initial revision
g. 冲突的处理
i. 首先,我们让David也加入到开发中来,安装之前的方法在David的主目录下创建DavidWork目录来导出我们的项目文件。方法跟之前一样,不过David想改变项目在本地保存的文件夹的名称,所以在Check Out时用了-d参数将animals改为MyProject
[David@localhost ~]$ mkdir DavidWork
[David@localhost ~]$ cd DavidWork/
[David@localhost DavidWork]$ cvs -d /usr/local/cvsroot/ co -d MyProject animals
cvs checkout: Updating MyProject
U MyProject/Animals.java
U MyProject/Dog.java
[David@localhost DavidWork]$ ls
MyProject
[David@localhost DavidWork]$ ls MyProject/
Animals.java  CVS  Dog.java
ii. 考虑第一种情况:
David在Dog.java添加一个eat方法,然后提交更新
/*****Dog.java*****/
public class Dog {
       public void bark() {
               System.out.println("Dog bark.");
       }
       public void eat() {
               System.out.println("Dog eat.");
       }

}
[David@localhost MyProject]$ cvs commit -m "Add a new method:eat"
cvs commit: Examining .
Checking in Dog.java;
/usr/local/cvsroot/animals/Dog.java,v  <--  Dog.java
new revision: 1.2; previous revision: 1.1
done
这时如果Jim也想提交他的版本,cvs就会提示他Dog.java没有更新到最新版
[Jim@localhost animals]$ cvs commit -m 'just try to commit'
cvs commit: Examining .
cvs commit: Up-to-date check failed for `Dog.java'
cvs [commit aborted]: correct above errors first!
为了查看Dog.java的最新版是否会影响本地代码,我们可以通过diff命令来比较:
[Jim@localhost animals]$ cvs diff -r HEAD Dog.java 
Index: Dog.java
===================================================================
RCS file: /usr/local/cvsroot/animals/Dog.java,v
retrieving revision 1.2
retrieving revision 1.1.1.1
diff -r1.2 -r1.1.1.1
6,9d5
< public void eat() {
< System.out.println("Dog eat.");
< }

注意到diff命令多了一个-r HEAD的参数,这个参数表示跟Repository里面的最新版比较,如果没有这个参数的话,是表示跟本地保存的Repository的最新版比较(也就是跟本地最近一次Check Out的代码比较)。显然,这里我们必须跟Repository的最新版比较。由比较结果可以看出,最新版不仅多加了一个eat方法,还多出来一个空行。
另外,这个改变并不会影响到其他的代码,所以我们可以直接用update命令来更新本地的代码
[Jim@localhost animals]$ cvs update
cvs update: Updating .
U Dog.jav
iii. 现在考虑第二种情况:David跟Jim同时修改了同一个文件的不同地方
David将eat打印输出的字符串全部改为大写字母:
/*****Dog.java*****/
public class Dog {
       public void bark() {
               System.out.println("Dog bark.");
       }
       public void eat() {
               System.out.println("DOG EAT.");
       }

}
Jim将bark打印输出的字符串全部改为大写字母:
/*****Dog.java*****/
public class Dog {
       public void bark() {
               System.out.println("DOG BARK.");
       }
       public void eat() {
               System.out.println("Dog eat.");
       }

}
假设Jim抢先一步提交更新
[Jim@localhost animals]$ cvs commit -m "change 'Dog bark' to 'DOG BARK'"
cvs commit: Examining .
Checking in Dog.java;
/usr/local/cvsroot/animals/Dog.java,v  <--  Dog.java
new revision: 1.3; previous revision: 1.2
done
接下来David也提交自己的更新
[David@localhost MyProject]$ cvs commit -m "change 'Dog eat' to 'DOG EAT'"
cvs commit: Examining .
cvs commit: Up-to-date check failed for `Dog.java'
cvs [commit aborted]: correct above errors first!
这时同样会出现上一钟情况的问题,同样我们也用update命令来解决这个问题,看看会发生什么事:
[David@localhost MyProject]$ cvs update
cvs update: Updating .
RCS file: /usr/local/cvsroot/animals/Dog.java,v
retrieving revision 1.2
retrieving revision 1.3
Merging differences between 1.2 and 1.3 into Dog.java
M Dog.java
这时cvs智能地合并了两个版本,结果如下:
/*****Dog.java*****/
public class Dog {
       public void bark() {
               System.out.println("DOG BARK.");
       }
       public void eat() {
               System.out.println("DOG EAT.");
       }

}
cvs把我们的修改跟最新版的修改合并起来了,这正是我们想要的。但是别忘了,我们还要把这个最新的合并版本提交到Repository。
[David@localhost MyProject]$ cvs commit -m "DOG BARK and DOG EAT"
cvs commit: Examining .
Checking in Dog.java;
/usr/local/cvsroot/animals/Dog.java,v  <--  Dog.java
new revision: 1.4; previous revision: 1.3
done
这样Jim再次更新的时候就同样可以得到最新版本了
[Jim@localhost animals]$ cvs update
cvs update: Updating .
U Dog.java
iv. 接下来考虑第三种情况:
David跟Jim同时修改了同一行
Jim将“DOG BARK”改为“A Dog barks”
/*****Dog.java*****/
public class Dog {
       public void bark() {
               System.out.println("A Dog barks.");
       }
       public void eat() {
               System.out.println("DOG EAT.");
       }

}
David将“DOG BARK”改为“A dog is barking”
/*****Dog.java*****/
public class Dog {
       public void bark() {
               System.out.println("A dog is barking.");
       }
       public void eat() {
               System.out.println("DOG EAT.");
       }

}
这次假设是Jim先commit:
[Jim@localhost animals]$ cvs commit -m "change 'DOG BARK' to 'A Dog barks'"
cvs commit: Examining .
Checking in Dog.java;
/usr/local/cvsroot/animals/Dog.java,v  <--  Dog.java
new revision: 1.5; previous revision: 1.4
done
这时David如果想commit的话就会碰到文件过期的错误
[David@localhost MyProject]$ cvs commit -m "change 'DOG BARK' to 'A dog is barking'"
cvs commit: Examining .
cvs commit: Up-to-date check failed for `Dog.java'
cvs [commit aborted]: correct above errors first!
按照我们之前的做法,可以通过update命令对文件进行更新就行了
[David@localhost MyProject]$ cvs update
cvs update: Updating .
RCS file: /usr/local/cvsroot/animals/Dog.java,v
retrieving revision 1.4
retrieving revision 1.5
Merging differences between 1.4 and 1.5 into Dog.java
rcsmerge: warning: conflicts during merge
cvs update: conflicts found in Dog.java
C Dog.java
我们发现这次update在合并我们的代码时发生了冲突,我们再看看Dog.java现在的状态是什么样的
[David@localhost MyProject]$ cvs status Dog.java 
===================================================================
File: Dog.java         Status: Unresolved Conflict

  Working revision:1.5 Result of merge
  Repository revision:1.5 /usr/local/cvsroot/animals/Dog.java,v
  Sticky Tag: (none)
  Sticky Date:(none)
  Sticky Options:(none)
可以看到Dog.java更新后已经是1.5最新版本了,但是状态时“ Unresolved Conflict”,这个告诉我们文件里面还有未解决的冲突。
我们可以打开Dog.java文件来看看,cvs已经把冲突的地方用
<<<<<<<和>>>>>>>标记起来
/*****Dog.java*****/
public class Dog {
       public void bark() {
<<<<<<< Dog.java
               System.out.println("A dog is barking.");
=======
               System.out.println("A Dog barks.");
>>>>>>> 1.5
       }
       public void eat() {
               System.out.println("DOG EAT.");
       }
}
可以看到,原来是有人改了同样的地方。David必须找出是谁改的,才能商量要怎么处理这个冲突。这个可以通过log来查看某个版本的历史信息
[David@localhost MyProject]$ cvs log -r1.5 Dog.java 
RCS file: /usr/local/cvsroot/animals/Dog.java,v
Working file: Dog.java
head: 1.5
branch:
locks: strict
access list:
symbolic names:
initial: 1.1.1.1
animals: 1.1.1
keyword substitution: kv
total revisions: 5;selected revisions: 1
description:
----------------------------
revision 1.5
date: 2013/01/10 01:54:21;  author: Jim;  state: Exp;  lines: +1 -1
change 'DOG BARK' to 'A Dog barks'
===========================================================================
从最后两行我们可以看到是Jim把'DOG BARK' 改成'A Dog barks'。这个时候,只能寻求客户或者需求人员来决定哪个更合适了。通过协调,客户比较认同David的表达。
所以现在David可以把冲突标识去掉,再提交自己的版本了
/*****Dog.java*****/
public class Dog {
       public void bark() {
               System.out.println("A dog is barking.");
       }
       public void eat() {
               System.out.println("DOG EAT.");
       }
}
[David@localhost MyProject]$ cvs commit -m "change 'DOG BARK' to 'A dog is barking'"
cvs commit: Examining .
Checking in Dog.java;
/usr/local/cvsroot/animals/Dog.java,v  <--  Dog.java
new revision: 1.6; previous revision: 1.5
Done
提交之后生成了新的版本1.6,这时Jim可以通过update来更新通过协调之后的最新代码了:
[Jim@localhost animals]$ cvs update
cvs update: Updating .
U Dog.java

原创粉丝点击