Short Introduction to CVS

by Christian H. Stork

Corrections, comments, and improvements are highly welcome!

CVS (Concurrent Versions System) is a versioning system which manages trees of RCS files. (A very short introductions to RCS can be found here.) These trees are maintained in a single repository, possibly on a remote server. A CVS user creates working copies of some (or all) files and directories of the repository. Working directories are characterized by having a CVS subdirectory.

The focus of this introduction is on the issues peculiar to CVS (as opposed to RCS, software development, etc.). I make no attempt to cover any material which is dealt with in Jim Blandy's Introduction to CVS. You should have read his introduction before proceeding. He covers changing, merging (including conflict handling), and committing files. He also mentions some worthy conventions, like committing log entries which describe the reason for a change. (Maybe these two documents should be merged some day?)

Some of the information in this document is taken from Open Source Development with CVS and other parts are from the famous Cederqvist Manual.

This document only discusses the command line interface for Linux/BSD/Unix systems. This makes it easier to understand what is actually going on. I had big problems with WinCVS until I studied the Unix commands for CVS.

Command Structure

All CVS commands look like this:
    cvs -globaloptions command -commandoptions arguments
When referring to a cvs command I am mostly referring to command from the above line.

Connecting to the CVS Server Nil

We use the peserver (password server) method when connecting to nil. There are three ways to tell CVS that you want to use nil as your pserver. Here I list them highest precedence first:
  1. Use the global option
    -d :pserver:yourlogin@nil.ics.uci.edu:/home/cvs/REPOSITORY
    with your cvs commands.
  2. When already in a working directory, the server, from which this directory was checked out, is used. This information is stored in the CVS subdirectory.
  3. If the environment variable $CVSROOT is set its value is used just as the argument to the -d global option. If you are only using one CVS repository, it's most comfortable to set this variable in one of your start scripts.
Since we are accessing a remote repository using the pserver method we have to log in. Assuming the repository is specified via one of the three methods above, just do
    cvs login
and provide your user password for nil. (Don't forget the -d option in case you are using the first method.)

Creating Your Working Directory

You can either make a copy of the whole repository with mkdir new_working_dir cd new_working_dir cvs checkout . or you can can create copies of top-level subdirectories and modules like this:
    cvs checkout dir_relative_to_cvsroot
    cvs checkout module
(The role of modules will be explained later.) In contrast to the files and directories in the repository, your copies are called working files and they are located in their working directories.

The repository on nil has currently the following directory structure:

    /home/REPOSITORY/
                     lagoona/
                     texmf/
                     www/
                     transprose/
                                prototypes/
                                           mr.brown/
                                           pag/
                                           arithmeticencoding/
                                visions/
                                           mr.blond/
                                           mr.blue/
                                           mr.brown/
                                           mr.orange/
                                           mr.pink/
                                           mr.white/
                                           well/
                                www/
                                           index.html
                     users/
                                phf/
                                cs/
                                more users to come
Sadly, some of these directories are still empty!

Directory Management under CVS

CVS does not maintain a version history for directories. This makes life with CVS a little complicated at times. The behavior of directories is provided by some simple rules: Thus, if you consider a directory live it makes sense to put a file (e.g. README) into this directorie, i.e. add this file with the add command (see further down) to the repository.

Updating Your Working Directory

    cd working_dir
    cvs update
This command updates all the files in the directories rooted at working_dir. It does not create new working directories even if these might have been created in the repository since the last update occurred. All directories are created upon update like this:
    cvs update -d
This weird behavior is more a feature than a bug (though -d should maybe be the default) because it allows the programmer to tell CVS not to update certain directories simply by removing the working copy of it.

The best convention seems to be to put at least one file into every live directory and to use

    cvs update -dP
for all updates. The -P stands for 'purge' and removes all empty working directories which are also empty in the repository.

Note: Don't confuse update and checkout. Technically, the difference is that update expects to be run for an already checked-out working directory, e.g., using the cvs server information in the CVS subdirectory, whereas checkout will create new root directories. (See the Cederqvist Manual (Section A.7) for some quirks of checkout.) For a start, update -d should always be sufficient.

Adding Entries

Adding a directory to the repository

    cd working_dir
    mkdir newdir
    cvs add newdir

Adding a files to the repository

    cd working_dir
    ... create newfile ...
    cvs add newfile
    cvs commit

Deleting Entries

Removing a File from the Repository

    cd working_dir
    rm working_file
    cvs remove working_file
With the next
    cvs commit
the deletion becomes manifest in the repository.

Deleting a Directory in the Repository

This does not work as expected. See Updating Your Working Directory for the why and how.

Releasing a Working Directory

Mostly you can simply delete your working copy of a directory under CVS control but it is good practice to check if you maybe forgot to checkin some relevant modifications.
    cvs release -d working_dir
This command checks for any uncommited changes and asks you if you want to release and delete (that's what the -d stands for) your working directory working_dir. You can give `.' as the working_dir (which makes sense if your $CVSROOT does not point to the repository of the directory you wish to release). This will delete your current working directory. So don't be surprised.

Revisions

    cvs update -rmajor.minor file 
This retrieves version major.minor of file. One thing is special here. Revisions like this are sticky. That is, when you do your next regular update (without the -r option), CVS will still remember to update to version major.minor.

In order to revert to the old behavior of always updating to the current HEAD you must issue:

    cvs update -A

Branching

Creating and working on a branch.

    cvs tag branchname-root
    cvs tag -b branchname-branch
    cvs update -r branchname-branch
    ...edit working copy...
    cvs tag branchname-1
    ...edit working copy...
    cvs tag branchname-2
    ...and so on.

Merging from a branch into the trunk

    in dir of trunk working copy
    cvs update -j branchname-1
    cvs commit -m "merged branch up to branchname-1"
    cvs tag merged-branchname-1
    ...edit working copy...
    cvs update -j branchname-1 -j branchname-2
    cvs commit -m "merged branch up to branchname-2"
    cvs tag merged-branchname-2
    ...and so on.

Syncing with the trunk

    in dir of branch working copy
    cvs update -j merged-branchname-2 -j trunktag1
    cvs commit -m "synchronized with trunk up to trunktag1 (from merged-branchname-2)"
    cvs tag synced-trunktag1
    ...edit working copy...
    cvs update -j trunktag1 -j trunktag2
    cvs commit -m "synchronized with trunk up to trunktag2 (from trunktag1)"
    cvs tag synced-trunktag2
    ...and so on.

...and merging back from a branch??

It seems that you can not merge and sync a branch alternatingly without permanently causing merge conflicts. If somebody knows how to do this, please mail me!

Moving Files Around Without Losing their Revision History

In the repository, copy (don't move!) the RCS files to the desired new location. They must remain in their old location as well. Then, in a working copy, do:
    rm oldfile1 oldfile2 ...
    cvs remove oldfile1 oldfile2 ...
    cvs commit -m "moved from here to there" oldfile1 oldfile2 ...

Changing file attributes and permissions

In order to permanentely change the permissions of a working copy file, it seems to be necessary to change the files permissions directly (!) on the repository's ,v copy of that file, e.g., from non-executable to executable. (If anybody knows of a better way, please email me.)

cvs admin -kb switch for binaries (i.e., no keyword substitution and no RCS deltas?). It might require folks to check out from scratch. More to come here.

Putting Projects under CVS

Putting Your Non-RCS Project under CVS

    cd dir_from_which_to_import
    cvs import -m "what you import" rep_dir_relative_to_cvsroot vendorname releasetag 

The

rep_dir_relative_to_cvsroot
directory will be created if it doesn't exit already.

The

vendorname
and
releasetag
arguments specify where you got the code from and which release it is. (Internally the imported files are also checked in on the vendor branch by default 1.1.1 .) This gives you the opportunity to track different vendor releases without mixing up their changes with yours. See Cederqvist for details.

No working copy is created.

import
only operates on the repository. Do a regular
checkout
in order to create your working copy.

Putting Your RCS Project under CVS

(In contrast to RCS tags, CVS tags are not allowed to start with numbers. Therefore it is a good idea to re-tag the relevant files while still under RCS.)

If you already have a project which you maintained with RCS then you are likely to want to preserve your rcs logs. This is the only instance where you want to operate directely on the server's copy of the repository. If you feel uncomfortable doing that ask me or Peter Fröhlich about it. Basically, you have to create the directory of your project in the repository by hand (either directly on the server or via cvs add dir). Next, the rcs files (the ones ending in ,v) are copied to their destination directly. With

    cd dir
    cvs update -d
you can immediately retrieve your working copy.

History of Whole Repository

    cvs history -e -a
Shows repository's history of everything and for all.

Who to blame?

In order to see who changed a certain line of code last do:

    cvs annotate file

To Come

Server-Side Administration

Creating a Repository

To create a new repository on the cvs server do
    cvs -d repdir init
and create cvs group and make prospective users members of this group. Don't forget to change ownership of repdir (recursively). $CVSROOT/CVSROOT/passwd on the server allows to define new passwords for cvs access only.

Configuring the Repository

All the configuration files are located in the directory CVSROOT in the root directory of the repository. (The name is somewhat unfortunate, especially since it is also used as an environment variable.) Administration is done by check it out, modifying its files, and committing the changes.

The only occations on which direct manipulation of the repositories content should be necessary is the import of files under RCS and copying of files while maintaining their version history.

(It also seems necessary to change file permissions in the repository, once they have been checked in incorrectly.)

Backing up a repository

Use rsync command in conjuncition with cvslock. The cvslock command can lock a whole repository during backup. (mention --delete and removing lock file.) We use ...

Adding New Users

RCSROOT/writers and cvs group


$Id: intro.html,v 1.15 2001/05/30 13:49:13 cst Exp $