CVS - An Overview

by Rick Moen

Revised: Wednesday, 2001-07-18

Master version will be at,
and I'll try to improve it there.

CVS: What does it do?

o Keep complete records of a changing project (new versions stored as diffs).


1986: Dick Grune posts shell scripts to comp.sources.unix.
1989: Brian Berliner & Jeff Polk re-code it in C. Built as an extension to RCS.
And it basically hasn't improved much, since then.

The simplest use of CVS (anonymous checkout):

cvs checkout arla
login: anoncvs
password: anoncvs
# The username/password used for anonymous access differs from site to site.

So you can retrieve the latest arla sourcecode (in directory ./arla), in order to build it. CVS does not build anything, nor administer projects. That part is up to you.

Using CVS to collaborate:

CVS working area (~/CVS/*) versus CVS repository.

Routine operations:

cvs checkout foo  #Put a copy of the named files in your CVS
                  #working area for editing. "foo" can be either
                  #an entire "module" = project or a specific file.
                  #(In general, if you specify a directory name,
                  #CVS will recurse.) Default checkout mode is
                  #"unreserved" -- others may check it out, too.
cvs export foo    #Similar to checkout, except omits CVS admin dirs.

cvs commit foomodule.c #Apply your changes to the repository.
cvs release -d foo     #Makes sure your changes are synced.

cvs update foo # Like checkout; working copy updated from repository.

cd foo
cvs diff foomodule.c

cvs import foo   #Check an entire file hierarchy into CVS.
                 #Note: CVS repositories can take up a LOT of disk space.
                 #Try this on the contents of

cvs release [-d] foo  #Cancels a checkout. "-d" deletes working copy.

cvs add newfile       #Updates repository to add file newfile from working copy.
cvs commit newfile    #Actually perform the addition.

cvs remove filename   #Register the removal of filename to the repository.
cvs commit filename   #Actually perform that removal.
                      #Note that you cannot remove directories from CVS,
                      #but you can empty them.

cvs status filename   #Tells you: up-to-date, locally modified, locally
                      #added, locally removed, needs checkout, needs patch,
                      #needs merge, file had conflicts on merge, unknown.

cvs history filename  #Shows you the revision history.
cvs diff -r rev1 -r rev2 filename

cvs edit filename      #Marks filename read-write. (Use this rather than
cvs unedit filename    #Abandon work on the working file, revert to
                       #repository, make it read-only again if watch was on.
cvs watch on filename  #Set filename so that checkouts will be
cvs watch off filename #Cease making checkouts read-only (default).
cvs watch add [-a action] filename
                       #Notify you when anyone takes "action" (edit,
                       #unedit, commit, all, none) on filename.
cvs watch remove [-a action] filename
                       # Stop doing that.

Using CVS will create a local ~/CVS tree, for CVS to store its records in. Normally, leave it alone.

Specifying a repository (method & location, can be stored in CVSROOT):


export CVS_RSH=ssh
cvs -d checkout foo
        # Note that default transport for "ext" access is rsh.

cvs -d checkout someproj
        # pserver = password server runs out of inetd.
        # pserver does the evil cleartext-password thing.  Avoid if
        # possible.

cvs -d checkout foo
        # This is "GSSAPI" e.g. Kerberos authentication.  Rare.  

cvs checkout someproj

Inside the repository's trees for each project are "history files": the regular file's name followed by ",v". (e.g., Makefile,v). The history-file naming system and format is an RCS feature.

Trees in the repository are normally set read-only by owner, and writable by group. Permissions problem? Make sure they're group-owned (as is the directory). Users must also have write access to file "CVSROOT/val-tags".

CVS uses directory CVSROOT/projectname/CVS to store file attribute info, and CVSROOT/projectname/Attic for history files if the trunk branch's revision has a "dead state".

Inside working directory is directory "CVS", with several CVS-internal housekeeping files.

Inside repository is directory CVSROOT, with more internal housekeeping files.

CVS auto-assigns revision number to successive versions of each file. If you also want a coordinated "release" number for a set of all the files in a project, use CVS'S "tags" feature, instead.

cvs tag rel-0-4 backend.c

("cvs rtag" command apply a tag to specfied revision, rather than the latest revision.)

You can then checkout all files with a specified tag:

cvs checkout -r rel-1-0 foo

"Head revision" of files under CVS is the latest versions of each.

Branching and merging:

"Branch" is a separated line of development with its own change history (separate from the "main trunk").
"Merging" is applying changes from one branch to another.

Create branch in the repository, based on your current working copy:
cvs tag -b rel-1-0-patches


$ cvs checkout foo               # Retrieve the latest revision.
$ cvs update -j branchname       # Merge all changes made on the branch,
                                 # into your working copy.
$ cvs commit                     # Create new revision.

"merge" operation uses diff3 utility -- compares original, yours, my versions.

You may (/probably will) have merge problems -- conflicts. Some are attributable to CVS keywords being expanded differently in the two branches. `-kk' option will prevent keyword expansion.

In the event of conflicts, you'll be shown both versions of the overlapping section. Like this excerpt:

       <<<<<<< driver.c
            exit(nerr == 0 ? EXIT_SUCCESS : EXIT_FAILURE);
       >>>>>>> 1.6

You then edit your local copy to resolve conflicts in the marked area, then commit a new version.

CVSweb: Nice Web front-end for browsing CVS repositories. But it doesn't allow checkout/commit, and such.

CVS Problem areas:

The "Subversion Project" will fix all this, but isn't done yet.

CVS Administrative Issues:

If lots of developers are getting:
[11:43:23] waiting for bach's lock in /usr/local/cvsroot/foo
then a lock may have stuck around that's not needed. Look around the repository for

`#cvs.rfl.*' = read lock
`#cvs.wfl.*' = write lock

Command "cvs admin" (usable by group "cvsadmin"): This is basically an RCS utility. Most functions are now obsolete. Various operations directly upon the repository.

These are locks on CVS's internal data structure, not reserved file locks. Write locks are supposed to last only during a write operation. Might have to delete it manually.

taginfo command: defines programs to execute when someone executes a tag or rtag command.

CVS alternatives:

Further Reading: ("Troubleshooting" section of manual)