CVS is a version control system. Using it, you can
record the history of your source files.
For example, bugs sometimes creep in when
software is modified, and you might not detect the bug
until a long time after you make the modification.
With CVS, you can easily retrieve old versions to see
exactly which change caused the bug. This can
sometimes be a big help.
You could of course save every version of every file
you have ever created. This would
however waste an enormous amount of disk space. CVS
stores all the versions of a file in a single file in a
clever way that only stores the differences between
CVS also helps you if you are part of a group of people working
on the same project. It is all too easy to overwrite
each others' changes unless you are extremely careful.
Some editors, like GNU Emacs, try to make sure that
the same file is never modified by two people at the
same time. Unfortunately, if someone is using another
editor, that safeguard will not work. CVS solves this problem
by insulating the different developers from each other. Every
developer works in his own directory, and CVS merges
the work when each developer is done.
CVS started out as a bunch of shell scripts written by
Dick Grune, posted to the newsgroup
comp.sources.unix in the volume 6
release of December, 1986. While no actual code from
these shell scripts is present in the current version
of CVS much of the CVS conflict resolution algorithms
come from them.
In April, 1989, Brian Berliner designed and coded CVS.
Jeff Polk later helped Brian with the design of the CVS
module and vendor branch support.
You can get CVS in a variety of ways, including
free download from the internet. For more information
on downloading CVS and other CVS topics, see:
There is a mailing list, known as info-cvs,
devoted to CVS. To subscribe or
If you prefer a usenet group, the right
group is comp.software.config-mgmt which is for
CVS discussions (along with other configuration
management systems). In the future, it might be
possible to create a
comp.software.config-mgmt.cvs, but probably only
if there is sufficient CVS traffic on
CVS can do a lot of things for you, but it does
not try to be everything for everyone.
CVS is not a build system.
Though the structure of your repository and modules
file interact with your build system
(e.g. `Makefile's), they are essentially
CVS does not dictate how you build anything. It
merely stores files for retrieval in a tree structure
CVS does not dictate how to use disk space in the
checked out working directories. If you write your
`Makefile's or scripts in every directory so they
have to know the relative positions of everything else,
you wind up requiring the entire repository to be
If you modularize your work, and construct a build
system that will share files (via links, mounts,
VPATH in `Makefile's, etc.), you can
arrange your disk usage however you like.
But you have to remember that any such system is
a lot of work to construct and maintain. CVS does
not address the issues involved.
Of course, you should place the tools created to
support such a build system (scripts, `Makefile's,
etc) under CVS.
Figuring out what files need to be rebuilt when
something changes is, again, something to be handled
outside the scope of CVS. One traditional
approach is to use make for building, and use
some automated tool for generating the dependencies which
Your managers and project leaders are expected to talk
to you frequently enough to make certain you are aware
of schedules, merge points, branch names and release
dates. If they don't, CVS can't help.
CVS is an instrument for making sources dance to
your tune. But you are the piper and the composer. No
instrument plays itself or writes its own music.
CVS is not a substitute for developer communication.
When faced with conflicts within a single file, most
developers manage to resolve them without too much
effort. But a more general definition of "conflict"
includes problems too difficult to solve without
communication between developers.
CVS cannot determine when simultaneous changes
within a single file, or across a whole collection of
files, will logically conflict with one another. Its
concept of a conflict is purely textual, arising
when two changes to the same base file are near enough
to spook the merge (i.e. diff3) command.
CVS does not claim to help at all in figuring out
non-textual or distributed conflicts in program logic.
For example: Say you change the arguments to function
X defined in file `A'. At the same time,
someone edits file `B', adding new calls to
function X using the old arguments. You are
outside the realm of CVS's competence.
Acquire the habit of reading specs and talking to your
CVS does not have change control
Change control refers to a number of things. First of
all it can mean bug-tracking, that is being able
to keep a database of reported bugs and the status of
each one (is it fixed? in what release? has the bug
submitter agreed that it is fixed?). For interfacing
CVS to an external bug-tracking system, see the
`rcsinfo' and `verifymsg' files
(see section C. Reference manual for Administrative files).
Another aspect of change control is keeping track of
the fact that changes to several files were in fact
changed together as one logical change. If you check
in several files in a single cvs commit
operation, CVS then forgets that those files were
checked in together, and the fact that they have the
same log message is the only thing tying them
together. Keeping a GNU style `ChangeLog'
can help somewhat.
Another aspect of change control, in some systems, is
the ability to keep track of the status of each
change. Some changes have been written by a developer,
others have been reviewed by a second developer, and so
on. Generally, the way to do this with CVS is to
generate a diff (using cvs diff or diff)
and email it to someone who can then apply it using the
patch utility. This is very flexible, but
depends on mechanisms outside CVS to make sure
nothing falls through the cracks.
CVS is not an automated testing program
It should be possible to enforce mandatory use of a
testsuite using the commitinfo file. I haven't
heard a lot about projects trying to do that or whether
there are subtle gotchas, however.
CVS does not have a builtin process model
Some systems provide ways to ensure that changes or
releases go through various steps, with various
approvals as needed. Generally, one can accomplish
this with CVS but it might be a little more work.
In some cases you'll want to use the `commitinfo',
`loginfo', `rcsinfo', or `verifymsg'
files, to require that certain steps be performed
before cvs will allow a checkin. Also consider whether
features such as branches and tags can be used to
perform tasks such as doing work in a development tree
and then merging certain changes over to a stable tree
only once they have been proven.
As a way of introducing CVS, we'll go through a
typical work-session using CVS. The first thing
to understand is that CVS stores all files in a
centralized repository (see section 2. The Repository); this
section assumes that a repository is set up.
Suppose you are working on a simple compiler. The source
consists of a handful of C files and a `Makefile'.
The compiler is called `tc' (Trivial Compiler),
and the repository is set up so that there is a module
The first thing you must do is to get your own working copy of the
source for `tc'. For this, you use the checkout command:
$ cvs checkout tc
This will create a new directory called `tc' and populate it with
the source files.
$ cd tc
CVS Makefile backend.c driver.c frontend.c parser.c
The `CVS' directory is used internally by
CVS. Normally, you should not modify or remove
any of the files in it.
You start your favorite editor, hack away at `backend.c', and a couple
of hours later you have added an optimization pass to the compiler.
A note to RCS and SCCS users: There is no need to lock the files that
you want to edit. See section 10. Multiple developers, for an explanation.
When you have checked that the compiler is still compilable you decide
to make a new version of `backend.c'. This will
store your new `backend.c' in the repository and
make it available to anyone else who is using that same
$ cvs commit backend.c
CVS starts an editor, to allow you to enter a log
message. You type in "Added an optimization pass.",
save the temporary file, and exit the editor.
The environment variable $CVSEDITOR determines
which editor is started. If $CVSEDITOR is not
set, then if the environment variable $EDITOR is
set, it will be used. If both $CVSEDITOR and
$EDITOR are not set then there is a default
which will vary with your operating system, for example
vi for unix or notepad for Windows
In addition, CVS checks the $VISUAL environment
variable. Opinions vary on whether this behavior is desirable and
whether future releases of CVS should check $VISUAL or
ignore it. You will be OK either way if you make sure that
$VISUAL is either unset or set to the same thing as
When CVS starts the editor, it includes a list of
files which are modified. For the CVS client,
this list is based on comparing the modification time
of the file against the modification time that the file
had when it was last gotten or updated. Therefore, if
a file's modification time has changed but its contents
have not, it will show up as modified. The simplest
way to handle this is simply not to worry about it--if
you proceed with the commit CVS will detect that
the contents are not modified and treat it as an
unmodified file. The next update will clue
CVS in to the fact that the file is unmodified,
and it will reset its stored timestamp so that the file
will not show up in future editor sessions.
If you want to avoid
starting an editor you can specify the log message on
the command line using the `-m' flag instead, like
$ cvs commit -m "Added an optimization pass" backend.c
$ cd ..
$ cvs release -d tc
You have  altered files in this repository.
Are you sure you want to release (and delete) directory `tc': n
** `release' aborted by user choice.
The release command checks that all your modifications have been
committed. If history logging is enabled it also makes a note in the
history file. See section C.11 The history file.
When you use the `-d' flag with release, it
also removes your working copy.
In the example above, the release command wrote a couple of lines
of output. `? tc' means that the file `tc' is unknown to CVS.
That is nothing to worry about: `tc' is the executable compiler,
and it should not be stored in the repository. See section C.9 Ignoring files via cvsignore,
for information about how to make that warning go away.
See section A.15.2 release output, for a complete explanation of
all possible output from release.
`M driver.c' is more serious. It means that the
file `driver.c' has been modified since it was
The release command always finishes by telling
you how many modified files you have in your working
copy of the sources, and then asks you for confirmation
before deleting any files or making any note in the
You decide to play it safe and answer n RET
when release asks for confirmation.
You do not remember modifying `driver.c', so you want to see what
has happened to that file.
$ cd tc
$ cvs diff driver.c
This command runs diff to compare the version of `driver.c'
that you checked out with your working copy. When you see the output
you remember that you added a command line option that enabled the
optimization pass. You check it in, and release the module.
$ cvs commit -m "Added an optimization pass" driver.c
Checking in driver.c;
/usr/local/cvsroot/tc/driver.c,v <-- driver.c
new revision: 1.2; previous revision: 1.1
$ cd ..
$ cvs release -d tc
You have  altered files in this repository.
Are you sure you want to release (and delete) directory `tc': y