Howto Set Up And Use A CVS Repository


Table of Contents


Setup Local Repository

To play in a sandbox, you can create local repository under your account,



/home/vlg/
         |-cvsrepo/                  <- Root of local CVS repository
         |        |-libfoo/          <- A project
         |        |       |-README
         |        |          ...
         |        |
         |        |-next-big-thing/  <- Another projectp
         |        |    ...
         |
         |-libfoo/                   <- Working copy checked out of CVS  
         |
         |-rb1.0/                    <- RB_1_0 branch of libfoo
         |
		  

First, create and initialize your local repository:

/home/vlg> mkdir cvsrepo
/home/vlg> cd cvsrepo

/home/vlg> cvs -d ~/cvsrepo init
		  

init command sets up the repository by creating ~/cvsrepo/CVSROOT/ directory that holds CVS housekeeping database files.

To access this repository, use -d ~/cvsrepo as repository locator.

Setup Remote Repository

  1. Setup cvs root directory:

  2. When a remote CVS client uses the :pserver: method to connect to a repository, the client is actually connects to the port 2401. This port is the designated default port for a CVS server.

    The CVS server is not actually waiting for connections on that port - instead the xinetd daemon answers the connection request and starts the CVS server to handle the actual data request. To accomplish this configuration, you have to configure xinetd daemon.

    Create cvs file under /etc/xinetd.d:

    service cvspserver
    {
        socket_type         = stream
        protocol            = tcp
        wait                = no
        user                = root
        server              = /usr/bin/cvs
        server_args         = -f --allow-root=/home/cvs pserver
        disable             = no
    }
    				

    Restart xinetd

  3. To permit the remote access to the CVS repository, you have to set up special CVS passwords separate from the users' regular UNIX passwords, so that people can access the repository without compromising overall system security.

    Make sure that the encrypted passwords are not the same as the user's actual login passwords. The passwords cross over the network in clear.

    Create CVS password authentication file $CVSROOT/CVSROOT/passwd. UNIX command htpasswd(1) created UNIX-style passwords. You have to create passwords for all of the external users of your CVS repository.

    		
    % htpasswd -c passwd.file vlg
    
    Adding password for user vlg
    New password: MY_SECRET
    Re-type new password: MY_SECRET
    
    % cat passwd.file
    
    vlad:XXXXXXXXXXX:cvs
    vlg:XXXXXXXXXXX:cvs
    			  

    One thing to notice here is that the last parameter, cvs, is not added by htpasswd. You have to put add it yourself and them merge passwd.file with $CVSROOT/CVSROOT/passwd.

[up]


Setup user account

Modify $HOME/.profile by adding following line:

export CVSROOT=:pserver:vlad@aurora:/home/cvs
		  

[up]


Login into CVS

Getting in and out of the remote CVS:

cvs -d :pserver:vlg@aurora:/home/cvs login
cvs -d :pserver:vlg@aurora:/home/cvs logout
		  

[up]


Add New Project To CVS

Adding brand new project is done with "import" command:

/home/vlg> mkdir libfoo
/home/vlg> cd libfoo
/home/vlg/libfoo> vi README
                       create initial version

/home/vlg/libfoo> cvs import -m "Initial version" <Path/libfoo> vlg TRUNK

/home/vlg/libfoo> cd ..
/home/vlg> mv libfoo libfoo.0

		  

<Path/libfoo> is how this module is going to be checked into CVS tree. The resultant path will be $CVSROOT/Path/libfoo. Having Path is not necessary.

Configuration file $CVSROOT/CVSROOT/modules allows to specify aliases for the project names, and control the way they are extracted.

# List all modules in CVS

% cvs co -c 

libassa        libassa
libirina -d libirina extras/src/libirina

% cd $CVSROOT/CVSROOT
% cat modules

libassa        libassa
libirina -d libirina extras/src/libirina

		  

Here, libassa is know as itself and can be checked out by its name accordingly. extras/src/libirina, however, is archived with long path to it, but can be checked out by its alias name, libirina. The option -d path controls where CVS files are going to be checked out locally.

[up]


Get files from CVS

% cvs checkout My_File_Name
		  

[up]


Add New File to CVS

				
% cvs add New_File_Name
% cvs commit
		  

Binary files need to be checked into CVS a little bit differently (a CVS hack):

% cvs add -kb WordDocument.doc
		  

[up]


Remove File From CVS

% rm My_Old_File
% cvs remove My_Old_File
% cvs commit
		  

[up]


Modify File

% chmod 644 My_File
% vi My_File
  ... make your changeschanges ...
:wq

% cvs commit
		  

When you want to update or merge a file, use the update command. This brings into your working directory the changes others have recently committed. If you have edited the file, and a newer revision is available, CVS will merge (or attempt to merge) all changes into your working directory. Conflicts may arise if you and someone else modified the same segment of the file. In this case, CVS will create a copy of the file with segment in question marked. You would need to modify the marked segment and the commit the change.

% cvs update -dP
		  

update command reports the modifications applied to files with letters leading each file that is updated or not:

[up]


Tag Current Snapshot of CVS Thread

# Tag the entire package

% cvs tag rel_1_2_0 .

# Tag a particular file

% cvs tag rel_1_2_0 A_Particular_File
		  

The point of the tags is to record successive points on the branch where the developer considers the changes to be mergeable into the trunk. The tags name generally follow the form of [MODULE]_[MAJOR]_[MINOR]_[MICRO].

Running the cvs tag command without arguments case CVS to select the revisions which are checked out in the current working directory. This way you can create a snapshot of the current state of the project. Note that tag is applied immediately to the files in repository and doesn't require cvs commit to transfer that modification to the repository. Running cvs tag -c rel-MAJOR-MINOR with -c option makes sure all local modifications are checked in before tagging occurs.

[up]


Using Branches

Use branch to create a release. Release can be then further patched in a release branch, while main development will continue in the trunk.

[up]


Branch off an Existing Tag

Sometimes you want to create an additional branch from a place different from the tip of the TRUNK. To do so, you need an existing tag in the TRUNK. In the example above, the Root-of-RB_1_0 tag can be used to create another branch. We call it RB_Experiment and it will be a sibling of RB_1_0 branch. With rtag, you can create a new branch in CVS from anywhere in your account.

/home/vlg> cvs -d$CVSROOT rtag -b -r Root-of-RB_1_0 RB_Experiment libfoo
			

The -b switch creates a new branch. The -r EXISTING_TAG switch tells CVS where to insert new branch at. If omitted, the default is the tip of the TRUNK.

Now, you are ready to checkout and start coding in your new branch.

/home/vlg> cvs -d$CVSROOT co -r RB_Experiment -d libfoo-experiment libfoo
			

The branch tree now looks like this:

                  o----------- RB_Experiment branch
                 / 1.3.4     
                /
               /o----------- RB_1_0 branch
              //  1.3.2
             //       
        1.3 //
TRUNK  ====oo=======================================
           ^^
           ||
           |\____ RB_1_0 tag
           |
           \___ Root-of-RB_1_0
			

[up]


Get File Status

% cvs status -v README
			

Examine the output from above. Lines that being with "revision:" in the righthand column above are normal tags.

The ones that start with "branch: " is a branch tag (RB_1_0, vlg) -- it will always point to the latest version of the file on that branch! If you were to check out the code from the trunk TRUNK, you would get version 1.4 of README file. If you were to check out the code from RB_1_0 branch, you would get version 1.3.2.3 of the README file instead. Release REL_1_0 tag would get you 1.3.2.1 version.

Notice also the "Status:" of the file:

[up]


Merge changes In and Out of the TRUNK

Now and then a branch developer would need to merge the changes from the TRUNK back into his branch:


/home/cindy/dev-branch> cvs update -j HEAD
		  

Special HEAD tag is reserved just for this action. First, you would merge all the latest changes from the TRUNK, and then tag your branch after the merger to remember the action taken.

[up]


Check Out Module Revision

			
% cvs checkout -r rel1-2 My_Module_Name
% cvs checkout -D '1 year ago' My_Module_Name
		  

[up]


View Diff Between File Versions

				
# diff between local and CVS' versions

% cvs diff My_File

# diff between versions 1.20 and 1.21

% cvs diff -r 1.20 -r 1.21 My_File  
		  

[up]


ViewCVS Front End

ViewCVS lets you browse your CVS repository with a Web browser. At the heart of it is a CGI script that is executed by the Web browser to display CVS entries.

ViewCVS main website is here. Get, unpack, and install latest ViewCVS tar.gz. Installation puts it into /usr/local/viewcvs-VERSION/ directory. Edit viewcvs.conf configuration file:

...
  Development : /home/cvs
...
  main_title = Vlad's CVS Repository

		  

You would also have to configure your Web server to execute CGI scripts, and add users apache and nobody to the cvs group:


cvs::500:apache,nobody,vlad
		  

ViewCVS CGI scripts are installed in its installation tree /usr/local/viewcvs-VERSION/cgi/. You need to add this directory to the ScriptAlias list of /etc/httpd/conf/httpd.conf:

# File: /etc/httpd/conf/httpd.con

#
# ScriptAlias: This controls which directories contain server scripts.
#
ScriptAlias /cgi-bin/ "/var/www/cgi-bin/" 
ScriptAlias /cvs/    "/usr/local/viewcvs-0.9.2/cgi/"
		  

Note: Make sure it is /cvs/, not /cgi-bin/ on the last line. Otherwise, it is not going to work at all!

Restart you Apache server and if you pointed your browser to URL http://host/cvs/viewcvs.cgi/, you would see your CVS!

[up]


Make Nightly Tarball


cvs -z3 -d:pserver:user@host:/home/cvs co Package | tar -cf Package-cvs.tar.gz -
		  

[up]


Make a patch against CVS

Let's say you have checked out a project from its CVS repository, and did some modifications to it to get it working with a new feature. To submit your patch to the project's developer, create a patch of your changes and submit it to the bug tracing system.


% cd libfoo/
% cvs diff -up > libfoo-mychanges.patch
% gzip --best libfoo-mychanges.patch

		  

To merge a 'patch' into your source,

/home/vlg/libassa-trunk> patch -p[n] < [patch]
		  

where n is the number of leading components to strip from the path. This number is relative to where the patch was generated from.

If you need to reverse the patch, you can use the following command

/home/vlg/libassa-trunk> patch -R < [patch]
		  

[up]


Use CVS With SSH

In you ~/.profile set following environment variables:

export CVS_RSH="ssh" 
export CVSROOT=":ext:user@host:/path/to/cvsroot" 
		  

[up]


SourceForge CVS

I keep my open-source projects on SourceForge. There is a small set of repetetive tasks I perform before each release.

Get a CVS snapshot


% export CVSROOT=:pserver:anonymous@cvs-pserver.sourceforge.net:80/cvsroot/libassa
% cvs -z3 -d$CVSROOT co libassa
% cvs -z3 -d$CVSROOT co libassa-manual

		  

[up]


Useful Links

[up]


Copyright © 2005-2006 Vladislav Grinchenko
Last updated: Jun 12, 2006