AESOP home


Using CVS

By Ashok Argent-Katwala.

CVS is a way of sharing a set of files between people so they can each work on their own copy without disturbing others, and merge the changes back together without too much pain. It is mainly useful for text files and we use it locally for both source control and when writing papers.

We have a CVS repository, for working on shared documents and code - both within the group and with our collaborators.


This guide is just a quick outline, covering our most basic needs and uses.

We focus here on command-line use of CVS, tips for graphical CVS clients would be gratefully incorporated. You can get a command line client for any Unix-like system, including Mac OS X or Linux, or Windows using a suitable shell environment (e.g. CygWin).

The local conventions we use apply no matter how you access CVS, so please read through this if you intend to use our CVS repository.

It is easiest to get started with CVS working with an existing project, already stored in CVS. Then you can get to grips with adding your own projects later on. If that doesn't suit you, read the initial setup, then skip ahead to adding a new project and then return to the earlier sections.

The rest of the guide is structured as follows:

CVS Software
Where to find tools to access our CVS repository
Initial setup
Permissions, where the repository lives, and configuring your environment to talk to it.
Checking out
Getting your own copy of a project that is already in the repository.
Adding new files
Adding your own files to a project.
Adding a new project
Adding a whole project.
Other handy commands
CVS tip for finding who changed what.
Handling white-space amongst different OSes.
Update CVS Root files
Fixing an old checkout to point to a new repository location.
(We had to move the repository in the past, but will hopefully never again.)
Tweaks for your profile
Little tricks to make working with CVS a little easier.
Further reading
CVS Bubbbles has a fairly useful FAQ
For general CVS Help section. Otherwise, man cvs has a short piece and info cvs has the full documentation

CVS software

For Cygwin, choose the cvs and openssh pacakges.
TortoiseCVS apparently does a good job of hooking CVS up to Wiindows' Explorer. Suggestions of other decent alternatives without Cygwin would be gratefully received.
Mac OS X
CVS is part of the Xcode tools, which ships with all new Macs, but is not installed by default. Find them on Install Disc 1 and run the Xcode Tools.mpkg from the XCode Tools folder. Or, you can download them for free from Apple.
Alternatively, you can use fink and fink install cvs
CVS will often be installed by default. Otherwise, it will surely be available via your distribution's package management system (e.g. emerge cvs on Gentoo; apt-get cvs on Debian).

Conventions for the examples

Things the machine outputs appear like this.
Things that you type are like this.
Things you should replace with your own text are like this.
Comments and other notes, are set like this.

Initial Setup

To use our CVS repository at all you will need a departmental login, and proper permissions for the repository. Contact the member of the group you are working with if you find you are told 'permission denied' when following these instructions.

The CVS root used to live on tungsten, but that machine has since expired. It is now available across the department over NFS at /vol/aesop/cvsroot/. We will keep this symlink up-to-date, hiding any behind-the-scenes movements from you. If you have existing checkouts, with different CVS roots, please update them to the current scheme. is the name that our Computing Support Group recommend for this purpose, so it ought to be quite stable. If you prefer, you could replace it with any other machine in DoC that you trust in any of the commands below. Just use a machine you expect to be generally available. You may wish to change where your existing checkout points, if you want to move an old checkout to the new cvsuser hostname, or if the machine you checked out via is having problems.

Set CVS_RSH to ssh, as none of this will work using rsh, and set CVSROOT environment variable to "":

[in bash]
$ export CVS_RSH='ssh'
$ export CVSROOT=''
[in (t)csh]
% setenv CVS_RSH 'ssh'
% setenv CVSROOT ''

If your ssh configuration does not know your DoC login, you can put 'login@' before cvsuser. Alternatively, put this in your ~/.ssh/config file:

Host *
User login

Other profile tweaks.

Checking out

To check out (take a local copy you can play with) a module, set the CVSROOT environment variable as above, then:

$ cvs checkout name

Where name is either a module or a path (to a directory or file) within the repository. Modules are just shortcuts to some path in the repository, and are defined in CVSROOT/modules. You can find out what modules are available with:

$ cvs checkout -c

… and what directories are available to looking in /vol/aesop/cvsroot (which is a department-wide NFS-mount of the appropriate directory). Important: you can do serious damage by messing about in the repository, don't mess with files and directories in there directly (there's likely a cvs command to list the directories and files in the repository, I just don't know it, offhand; suggestions welcome).

We have the following basic structure in the CVS archive:

Source code
Project-specific work
Papers, named with your login, as the existing papers.

So cvs checkout ipc and cvs checkout aesop/src/ipc are effectively the same (the first gets you an ipc directory, the latter places it in the tree under aesop). You can happily move checkouts around, take sub-directories and blow away the rest, it's just your local copy. Once you have checked out a module, you need not set your CVSROOT variable, it will pick it up from the meta-information it keeps in the CVS directories.

You can now play with the local copy and do whatever you like, without harming the copy in the repository. To see other people's changes run (the -d means you will also see newly added directories, by default these are omitted):

$ cvs update -d

An update will never change the repository, but it could leave inline diffs in your checked out copy if there is a conflict (C in the first column; P or U mean there are changes in the repository; M means you have local changes you have not yet commited). You can use cvs -n update to do a dry-run, and find out if there are any conflicts.

When you are happy with your changes and want to add them back to the common pool, you have to have updated recently. So, run:

$ cvs update
[resolve any conflicts]
$ cvs commit filenames

cvs commit with no arguments will check in all your local changes. You will then be prompted for your comments for the log, if you write enough this will really help later on when trying to find the correct revision before a certain change.

You can also supply the log message on the command line, with cvs commit -m "Your log message".

Adding new files

To add new files just create them in your local checkout, test them to make sure they work then add them with:

$ cvs add filenames

By default CVS will interpolate strings like $Id:$ and replace them with some appropriate metadata (e.g. $Id: cvs.cgi,v 1.3 2005/07/19 10:22:31 abkk97 Exp $). For binary files this is a terrible idea, so make sure you inform CVS that the file is binary (-k to set an RCS flag, b for binary) with. Even for non-binary files you need to take a little care to see you don't use any of the CVS keywords.

$ cvs add -kb binary_filenames

To fix this if you have already added the file to the repository, look up cvs admin -kb in the documentation.

You can tell cvs how to treat files based on their filenames (so *.jpg would default to being treated as a binary) using CVS Wrappers. If your operating system stores filetype information outside the filename (as in MacOS or BeOS, for example) then you should either use a convention or explicitly flag files when you add them.

Adding a new project

You can import a new project by standing at the top of the tree you want added to the repository and running the following:

$ cvs import -m "log message" path your_user_name initial_flag

See note regarding binary files.


log message
The first entry for each file when you do cvs log
e.g. Initial checkin
The relative path to where in the repository to add the new project. Note the last portion of the name will be created as a directory for you, and your new files added in there. paper_name should be something that makes sense to you, it is likely the topic, or where you sent it.
e.g. aesop/papers/paper_name-user_name
The 'vendor tag', but our convention here is by user name. This is not used for permissioning.
The 'release tag', keyword you want to tag the initial checkin with
e.g. start

Concretely, with the examples above:

$ cvs import -m "Initial checkin" aesop/papers/paper_name-user_name user_name start

I usually create a sparse tree with the simplest text files in, cvs import that, then use cvs add for anything more complicated like binary files.

You may also want to add a module name for your new project. Do this by checking out CVSROOT/modules, adding a line like those already there, and commiting your change.

Other handy commands

cvs annotate
Will show you each line of the file with who last changed it, and in which revision.
cvs diff -b
Will show you just the changes of real text, ignoring changes in whitespace.
cvs -n whatever
Pretend to run whatever, show the output, but don't change any of the local or repository files.
This is particularly useful as cvs -n up to see if you would get conflicts if you did an update now.


This is more about sharing text files with diverse users than anything CVS-specific. Different systems have different line-ending conventions:

DOS, Windows and related systems
Lines end with \r\n
MacOS (pre-OS X)
Lines end with \r
Practically everyone else
Lines end with \n

For a particular text file you must have consistent line endings. It broadly doesn't matter which you choose, but it is simplest if everything in a project shares the same convention. Let's say the unix line endings for convenience:

[Mac to Unix]
% cat foo.txt | tr "\r" "\n" >foo2.txt
[DOS to Unix]
% cat foo.txt | tr "\r" "" >foo2.txt

Beware, if you run the latter on an old-style Mac file, you'll have no line endings at all and you'll have double if you make the other error. You may prefer to use an editor that sorts these things out for you. Also, never do cat foo | some_command >foo or you'll only get an empty file.

Whatever your whitespace conventions, you should take care when fixing a file and checking it back in. When you change lots of whitespace then cvs diff will (rightly) see every line as having changed and might make matters complicated for merges. The civilised thing to do, then, would be to make the whitespace changes in one commit, and any substantial changes in a separate commit. If someone hasn't done this, then cvs diff -b is your friend, as it will tell you just the non-whitespace changes.

Update CVS Root files

In June 2005, our CVS root had to move from the old location on tungsten. We now have a stable NFS name of /vol/aesop/cvsroot/, available department-wide. To update older checkouts you can run this from a bash prompt, standing at the top of your checkout, or in a directory with several aesop checkouts (and no checkouts from elsewhere). This will not behave properly if you have sub-directories with spaces in their names.

$ for i in `find . | grep "/CVS/Root$"`; do echo $i; mv $i $i.bak; echo \
"" >$i; done

Which will replace all your …/CVS/Root files with one referencing the new, stable CVS location. Once you are happy with the way it is working you may want to remove the backed-up files with:

$ for i in `find . | grep "CVS/Root\.bak$"`; do echo $i; rm $i; done

Tweaks for your profile

You can set the editor that this will use by setting the CVSEDITOR environment variable, otherwise it will use $EDITOR or the system default. Put whichever lines fit your needs [minus the $ or % prompt character] wherever you set env variables (for instance ~/.bash_profile or ~/.profile).

[in bash]
$ export CVSEDITOR='vim'        # it might default to vi, otherwise
$ export CVSEDITOR='emacs'      # for your normal emacs
$ export CVSEDITOR='emacs -nw'  # to compel no-window mode and save yourself time
[in (t)csh]
% setenv CVSEDITOR 'emacs -nw'

You may also want to set CVSROOT, as described above, to "". Alternatively, you can make your checkouts with a line like:

CVSROOT="" cvs checkout blah

… and then within the checkout you don't need to set it, it looks it up from the CVS directories in the checkout. I have an alias for this (in bash):

alias aesopcvs="CVSROOT='' cvs"

… and make the checkout with aesopcvs checkout blah. This makes it much easier for me to work with other repositories elsewhere.

Further tips and contributions to this page would be appreciated. Please send them to Ashok.