Introduction to CVS

I wrote the following parpagraph back in 2005, and now that it is 2016, you really ought to be using GIT, plain and simple. CVS and SVN are all things of the past. This guide was written back in 1999.

Well, as of 2005, you really should think about not using cvs at all and using subversion instead, and I have a set of notes on subversion also.

CVS is the "concurrent version system" - which is a popular and freely available tool for source code management. I have been using it for several years now to manage my own projects, and find it to be an indispensible part of the way I develop software. It has seriously saved my bacon on several occasions.

This page is my own personal "cheat-sheet" for using CVS. To get the whole story, you really should refer to the real documentation, but perhaps this will help you get going with CVS.
If you are reading a printed copy, you can go to the online copy (with working links) at

	http://cholla.mmto.org/computers/cvs

The current CVS home page seems to be: the CVS home page

A source for additional information is here: CVS resources

CVS has a wonderful and detailed manual (the PDF version is 184 pages).
I keep copies of the manual in pdf format, as a bundle of html files for you to download, and in html format for you to peruse.

You may want to visit the CVS main site to see if more up to date versions of the documentation have become available. These are appropo to cvs version 1.11.2 which may be shipping with Red Hat Linux 7.3.

Another great resource is the CVS intro pages at Sourceforge. It was through these that I learned about the book by Karl Fogel Open Source Development with CVS parts of which are available online at: red bean. Chapter 1 comes highly recommended.

Long ago, I used RCS (upon which early versions of CVS were based), but frankly I doubt if anyone uses RCS anymore (or SCCS either for that matter), so I won't spend any time contrasting the two. Suffice it to say that CVS is one of the flagship free software efforts and was the clear choice until subversion came along to do version control even better.

The primary benefits that I appreciate are:

CVS is supposed to be good for allowing multiple developers to work on a project, but I haven't put that facility to use. I have sort of misused it as a software distribution tool. I develop code on my desktop machine, then use CVS to update other machines where the code is used (this is chiefly useful for scripting languages where the source code is the executable).

CVS resources

First off, you may want to look at this nice little introduction that comes with the 1.10 distribution:
And then there is the FAQ which hasn't seen much attention in quite some time.

Here are some links to resources on the WWW.

Graphical (and other) front ends to CVS abound, and tend to come and go. There was a project called "GIC" (Graphical interface to CVS) which has now been abandoned with interest being redirected to TkCVS.

CVS at the MMT

Now here are my notes on how I use CVS for projects here at the MMT:

First of all I have set up my CVS repository on mmt: as

/home/tom/CVSarchive

Once upon a time, long ago I did:

For a long time, I set the CVSROOT environment variable in my .bashrc via:

Then, somewhere along the way, I began using multiple repositories and was worried about all hell breaking loose, so I deleted this forcing myself to explicitly indicate the repository when necessary. It turns out that "when necessary" is only at checkout time for all practical purposes. In this case, use something like this:

cvs -d machine:CVSarchive checkout project

Setting up a new project

To start a new project under CVS control: Notice above that I check the project in as MMT/xxx - this path specifies where the project will go in the repository. This is how I am doing things now, and perhaps it is not the wisest plan. If you screw up (as I have done) and check it in as "xxx", then just go into the repository and move it to MMT/xxx. Then edit the modules file (see below).

In the scheme above, proj_name is identical to project (the name of the directory holding the project. After confirming that the cvs checkout has regurgitated the project, the directory project.ORIG can be deleted. The import/checkout cycle is important (or nice anyway) since it gets the starting "image" of the project into the repository and sets the $Id$ stuff in the file headers.

Using CVS

After editing for a while, when you want to update the repository, do this: A good rule of thumb is to use commit frequently! Commit to the repository whenever you get to any kind of coherent stopping point, often several times a day. CVS can only help you when you have made frequent commits, and I really cannot think of a case where too frequent commits are a bad thing.
Every commit to the archive is a potential point of recovery in case of disaster.

To get changes from the repository in your working copy, do this:

To add or remove a file:

CVS works nicely with entire directory trees. Let us say that bigproject is a directory with many subdirectories under it, the following command puts the whole mess into the repository:

After doing this, checkout will get the whole project tree, and commit will check either the whole tree, or part of it, depending on where it is invoked. Don't do this when the directory tree is full of a bunch of .o files (use make clean first!).

An import of a new addition to a directory tree (e.g. a whole new project) can be done. It is important to remember that the project name given on the import command is the path within the repository where the addition will go, and that the import should be issued while in the project directory. An example follows where "Drivers/dir1 is the path within the repository where a new directory will go:

New files and directories can be added to an existing project in just the way you might expect.

I have found modules and tags to be handy tools. The process for creating modules is a bit zany, you have to checkout a file called CVSROOT/modules, edit it, and then commit it. Here is an example:

After doing this, a cvs checkout of the module name can be done.

The -l switch says not to log anything to the history file, this might allow a readonly access to the CVS archive, for folks that just want to get a copy of the source, but do not have write access to the repository.

Notice that a cvs release -d is done to get rid of the working directory. This both deletes the files, and does cleanup so CVS doesn't worry about them any longer. Apparently without the -d, CVS is told to forget about it, but you still have the files to fool with.

Right now I have the following modules defined in CVSarchive:

Tags can be used to mark important stages in the progress of a project. More importantly, they allow a whole set of coherent files (i.e. a snapshot) to be marked for later recovery. You can tag individual files, but I have never wanted to. Much as you might like to, you cannot use dots, use hyphens instead. Use the status command with the -v to view tags. I try to keep a file "versions" that tracks what I have done with tags.
Here is how it works:

Getting past versions of files.

To get a specific version of a single file: (which you will only very rarely want to do).

Really helpful is the -D command, saying to do a checkout or update as of what was current as of a given date:

Beware! When you pull a version out like this, it gets pulled with a sticky date. You will not be able to commit to the archive until this is cleared. You clear it by doing a cvs update -A command. There are a variety of ways to shoot yourself in the foot here (maybe you should extract to stdout using the -p switch) What I do is something like this (which gives you 3 versions to try to sort out):

Moving a repository

To move the repository is simple on one hand, but has some tricky issues on the other. The easy way would probably be to commit everything to the repository and entirely delete all working directories. Then tar up the repository and copy the tarball onto the new machine that will host it. Untar it there, then set up the environment variable CVSROOT to point to the new repository, then check everything back out.

I didn't do the business of checking everything in and nuking my working directories. It turns out that in the CVS directory of every working directory (and all subdirectories thereof) there is a file called Root that typically contains one line which isthe value of CVSROOT at the time the working directory is checked out. This value is then used for all commit and update activity, NOT the value of CVSROOT. So if you do what I did, you need to go in and edit the machine name in this file which is easy but tedious.

Remote CVS and the network

Remote CVS is definitely a useful thing. Here is how it works. First you decide on some machine being the repository machine. It doesn't require any special setup, but of course it has the repository on the local disk and is able to run plain old CVS. Clients must have rsh (or ssh) access to the server machine (perhaps set up by a .rhosts file), and must be able to run cvs. On the client machine, the CVSROOT environment variable is set to server_machine:dir, and then things just work. No special CVS protocol is involved here, rsh/ssh protocols do all the work.

A special note at this point, it is possible (and quite desirable) to access the CVS server via ssh.
This can be done by setting the CVS_RSH environment variable to the path to the remote shell executable, in this case:

	CVS_RSH=/usr/bin/ssh; export CVS_RSH

pserver and anonymous CVS

I have never used this for my own projects, but some large projects offer public access to their latest development code via a CVS pserver. This can be used for a local team as well, but I have found using ssh entirely adequate.

Beyond simple rsh access, there is "pserver" which can be extended to provide anonymous cvs access (some large software projects are now using this to make their development trees publicly accessible). This is a notion of what is required to do this, I have yet to get brave enough (or to find sufficient motivation) to try this. A client may do something like this:

The first "login" will require a password, use "guest". On the server side you need to make changes to /etc/services and /etc/inetd.conf as follows:
/etc/services gets a line: /etc/inetd.conf gets the lines:

The above is just the simplest case of many schemes that can be used. Just to give a view of what is possible, consider the following. Alternate "methods" may be used to access the archive, and some schemes may involve passwords, aliasing of users to a CVS user namespace, kerberos, adding an entry for CVS to the inetd.conf files and /etc/services and so on, ultimately allowing full access only to selected users, and read-only access to others, and perhaps no access to yet others.