Linux DevCenter    
 Published on Linux DevCenter (
 See this if you're having trouble printing code examples

Tracking Changes in CVS

by Jennifer Vesperman

CVS, the Concurrent Versioning System, manages simultaneous development of files. It stores files in a central repository, and allows users to check out working copies of the files and commit changes back to the repository.

CVS maintains a record of the changes to each file, allowing the user to revert to a previous version, merge versions, and track changes. Change-tracking can be surprisingly useful, and is frequently underutilized.

This article builds on Introduction to CVS and CVS Administration. Some topics discussed there are used but not defined in this article.


cvs annotate displays the last change for each line of a file in the repository. For each line, it shows the revision number for the last change of each line, the user, the date, and the contents of the line. It is a quick way of discovering who made what changes when.

Annotate displays file data from the repository, not from the working directory, so changes that have not yet been committed will not be displayed.

Options to cvs annotate include:

display files even if no matching tag or date can be found for the file (uses the latest revision).

check only the current directory, do not go into subdirectories.

go into subdirectories (default).

-D date
show the most recent revision before the date.

-r tag
display the revision identified with the tag.

Example 1

$ cvs annotate test.html
Annotations for test.html
1.1 (jenn 30-Apr-02): <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
1.1 (jenn 30-Apr-02): "">
1.1 (jenn 30-Apr-02): <html>
1.1 (jenn 30-Apr-02): <head>
1.4 (jenn 04-May-02): <title>Sample Article</title>
1.1 (jenn 30-Apr-02): </head>
1.1 (jenn 30-Apr-02): <body>
1.4 (jenn 04-May-02): <h1>Sample Article</h1>
1.1 (jenn 30-Apr-02): <p>
1.11 (jenn 07-May-02): Body text for the sample article.
1.1 (jenn 30-Apr-02): </p>

CVS Pocket Reference

Related Reading

CVS Pocket Reference
By Gregor N. Purdy


The command cvs diff compares two revisions of a file and displays the differences. The cvs diff output is very like the standard diff output. cvs rdiff is a variant that can be used to create a patch file that can be installed using the standard patch command.

cvs diff is usually called with at least one -r tag parameter. If called with a single tag, the current copy in the working directory is compared to the version in the repository. The cvs log command shows revision numbers that can be used as parameters to cvs diff.

Example 2

$ cvs diff -r 1.11 cvs_changes.html
Index: cvs_changes.html
RCS file: /home/cvs/oreilly/articles/cvs/cvs_changes.html,v
retrieving revision 1.11
diff -r1.11 cvs_changes.html
&gt; The command &lt;code&gt;cvs diff&lt;/code&gt; compares two 
revisions of a file and displays the differences.
&gt; &lt;code&gt;cvs diff&lt;/code&gt; is usually called with at 
least one &lt;code&gt;-r &lt;var&gt;tag&lt;/var&gt;&lt;/code&gt; parameter.


Unlike most CVS functions, cvs history is not set up by default. To set it up, create a file called history in the CVSROOT directory of the repository. The CVS user (or whichever user runs CVS on your server) must be able to write to the file.

Example 3

(on the cvs repository server)
$ cd /home/cvs/CVSROOT
$ touch history
$ chmod g+w history
$ ls -la
drwxrwsr-x    4 root     src          1024 May 16 01:04 .
drwxrwsr-x   35 root     src          1024 Mar 20 18:01 ..
drwxrwsr-x    2 root     src          1024 Sep  7  2001 Attic
-rw-rw-r--    1 root     src             0 May 16 01:04 history
-r--r--r--    1 root     src           403 Sep 26  2001 loginfo

Test the history file by committing a file, then running cvs history -c filename (the -c flag displays CVS commits). CVS will display a line that shows the one commit since the history file was created.

Example 4

$ cvs history -c test.html
M 2002-05-15 15:04 +0000 jenn 1.2 test.html oreilly/articles/cvs == <remote> $

Once it is set up, cvs history can be used to show the history of the files and modules in the repository. File and module choices include a particular file or files, a module, or the modules in the current working directory.

The history file records commits, merges, conflicts, tagging, updates (to the working directory), additions, deletions, and modifications of files in the repository. Each of these can be recalled and displayed with the cvs history command.

cvs history will also display data for the user requesting the information, for all users, or for the current working copy. For widely distributed teams, there is an option to display times in a named time zone.

Example 5

$ cvs history -e -w -z EST test.html
M 2002-05-15 10:04 EST jenn 1.2 test.html oreilly/articles/cvs == <remote>
M 2002-05-15 10:41 EST jenn 1.3 test.html oreilly/articles/cvs == <remote>

In example 5, -e specifies showing all types of commits and updates, -w specifies showing only the changes that affect or come from the current working directory, and -z EST sets the time zone for display to EST.


The cvs log command displays information about the file or files in the argument list. If no files are listed, it displays log information about all files in the current working directory and its subdirectories.

The options to cvs log reduce the amount of information it shows. By default, log displays all its information.

Example 6

$ cvs log cvs_changes.html

RCS file: /home/cvs/oreilly/articles/cvs/cvs_changes.html,v
Working file: cvs_changes.html
head: 1.3
locks: strict
access list:
symbolic names:
keyword substitution: kv
total revisions: 3;     selected revisions: 3
revision 1.3
date: 2002/05/15 15:41:54;  author: jenn;  state: Exp;  lines: +53 -0
history mostly done. needs example.
revision 1.2
date: 2002/05/15 15:04:47;  author: jenn;  state: Exp;  lines: +8 -2
Adding a history file
revision 1.1
date: 2002/05/15 14:54:54;  author: jenn;  state: Exp;
Initial entry for both files. Also includes cvs annotate for changes.

Example 6 shows the early log history for this article.

Revision 1.1 occurred when I created two files, forgot to check-in the empty templates, and tried to commit the annotate section of this article.

User-defined Logging

CVS has customization files that define scripts to be called when certain actions occur. The loginfo, modules, and taginfo files can be used to call logging scripts.

These files can be found and configured in the CVSROOT directory in the CVS repository. The files are run on the computer that hosts the repository, but some module scripts are run from the client machine. See that section for more detail.

Use CVS when editing these files -- they are in the module CVSROOT. Simply cvs -d repository checkout CVSROOT to check out all these files.

loginfo and taginfo

The loginfo file controls where log information for cvs commit is sent. Potential uses include keeping a project leader informed of changes her team makes, and maintaining a central log of a project's progress.

taginfo does the same, but for the tag and rtag commands. It has the same syntax as loginfo.

Each line of the file should contain a regular expression that matches a directory, followed by the address of a script, which expects log information as the standard input (stdin).

The special lines start with 'ALL' and 'DEFAULT'. ALL runs cumulatively with any other line that applies. Otherwise, only the first matching regular expression is run, or DEFAULT if none match.

The loginfo file in example 7 would log every commit through a script called logscript, run cvsscript if any file under $CVSROOT/oreilly is committed, and would mail any other commits to cvsadmin.

Example 7

ALL /usr/local/bin/logscript
^oreilly /home/jenn/scripts/cvsscript
DEFAULT Mail -s "CVS commit" cvsadmin


The file CVSROOT/modules records each module and its directories and files. The file also takes options, and some of the options are scripts to be run when CVS actions occur.

-e script
run the script when the module is exported.

-i script
run when the module is committed.

-o script
run when the module is checked out.

-u script
run when the module is updated.

-t script
run when rtag is used on the module. This does NOT run when tag is used. The taginfo file is a better way to log tags.

Please read the manual and info files for CVS if you are changing this file. CVS uses this file every time a user interacts with a module.

Scripts called from a commit or an update are run from the local machine, and scripts called from the rest are run from the server.

Example 8 would run /home/jenn/scripts/cvsscript when the oreilly module is checked out, from the directory oreilly. It also defines the module CVSROOT, with no special options.

Example 8

oreilly -o /home/jenn/scripts/cvsscript oreilly

Final Words

Change-tracking is a useful part of CVS, but I've rarely seen it used in the field. I discovered it when I started using CVS on my own, and had one of those, "Why have I never used this before?" moments.

Try it. I hope you find it as useful as I do.

Further Reading

Jennifer Vesperman is the author of Essential CVS. She writes for the O'Reilly Network, the Linux Documentation Project, and occasionally Linux.Com.

Return to the Linux DevCenter.

Copyright © 2009 O'Reilly Media, Inc.