Source code control with CVS

You may have noticed that RCS has some shortcomings that make it inadequate for use on large projects. First, without some sophisticated wrapper scripts to provide the directory handling machinery, RCS doesn't work very well with a single, centralized repository. And you need such a repository for a programming team with more than a few members.

An RCS repository is always the current directory unless you exert yourself to use a directory located elsewhere. More pertinent for Linux and other open source projects, RCS is utterly unsuitable for distributed development because it doesn't support network protocols. (That is, it doesn't work over the Internet.)

Furthermore, RCS suffers from programmers forgetting commands. If you forget to check out a file with a certain option, you may regret it later. Even if you work alone, you may find CVS a better option.

The Concurrent Versions System (CVS) supports both centralized repositories and network-based access. It is well-suited for use by multiple programmers, and a single CVS repository can support multiple projects. To keep the discussion simple, however, the example in this chapter deals only with a repository accessed locally. The following steps resemble the process described earlier for RCS, but they are slightly more involved and obviously use CVS concepts:

1. Create a CVS repository:

$ mkdir /space/cvs $ export CVSROOT=/space/cvs $ cvs init

The first command creates a directory named /space/cvs in which to establish the repository. The second command defines the environment variable $CVSROOT with this directory. Defining $CVSROOT makes using CVS much simpler. The third command initializes the repository, which creates some administrative directories CVS needs to work properly.

2. Create a top-level working directory in which to store your various projects and then change into this directory:

$ mkdir projects $ cd projects

3. Check out a copy of the CVS root directory into the directory you just created:

cvs checkout: Updating .

The -d option tells cvs the directory containing the CVS repository ($CVSROOT, or / space/cvs); co means check out (just as with RCS); the -l option, which stands for local, means to work only in the current directory rather than recursing through subdirectories; and the . specifies the current directory.

4. Create a directory to hold a project and add it to the repository:

$ mkdir newhello $ cvs add newhello

Directory /space/cvs/newhello added to the repository

5. Change into the new directory, copy your project files into it (fill in the your_new_ hello_code with the name of the directory where you have the actual source code files for the new project), and then add those files (and any directories that might be present) to the repository:

$ cd newhello

$ cp /your_new_hello_code/* . $ cvs add *c *h cvs add: scheduling file 'hello.c' for addition cvs add: scheduling file 'msg.c' for addition cvs add: scheduling file 'main.c' for addition cvs add: scheduling file 'showit.c' for addition cvs add: use 'cvs commit' to add these files permanently

6. Do as the instructions recommend: Execute the command cvs commit to make the added files and directories permanent. You'll first see a screen (which is actually a vi editor session) asking you to enter a log message. If you don't want to enter a log message, press Esc, and type ZZ to save and exit. After you close the vi session, the output you see should resemble the following:

$ cvs commit cvs commit: Examining .

RCS file: /space/cvs/newhello/hello.c,v done

Checking in hello.c;

/space/cvs/newhello/hello.c,v <-- hello.c initial revision: 1.1


RCS file: /space/cvs/newhello/msg.c,v done

Checking in msg.c;

/space/cvs/newhello/msg.c,v <-- msg.c initial revision: 1.1


RCS file: /space/cvs/newhello/showit.c,v done

Checking in main.c;

/space/cvs/newhello/main.c,v <-- main.c initial revision: 1.1


Notice that CVS uses RCS filenaming conventions to work with files in the repository because CVS was built on top of RCS and retains compatibility with the basic RCS feature set.

CVS handles checking files in and out slightly differently than RCS. When checking a file out, it isn't necessary to specifically request a lock to get a writable copy of the file. To work on a file, you do need to use the checkout or co command:

$ cd projects

$ cvs -d /space/cvs co newhello cvs checkout newhello U newhello/hello.c U newhello/msg.c U newhello/main.c

The checkout command used in this example specifies the path to the repository using the -d option. This is unnecessary if you set the $CVSROOT environment variable. After you have made changes to files such as main.c, you can check them in using the cvs commit command (commit is comparable to RCS's ci command):

$ cd projects/newhello $ cvs commit .

cvs commit: Examining . [editor session] Checking in main.c;

/space/cvs/newhello/main.c,v <-- main.c new revision: 1.2; previous revision: 1.1 done

When you check in a modified file, CVS opens an editor session to enable you to enter a log message that describes the changes you made. The editor used is the editor defined in the $EDITOR environment variable or compiled-in default (usually vi text editor) if $EDITOR is undefined. This example did not use the -d option because the $CVSROOT environment variable is set.

To check out a specific version, or revision, of a file, use the -r option following the checkout or co command, followed by a revision number. For example, to check out revision 1.1 of the main.c file, use the following command:

U main.c

To see the differences between two revisions, use the diff command, using the -r m.n, where m.n indicates the revision number you want to check. If you specify -r only once, the indicated version will be compared against the working file (using the diff option). If you specify -r twice, the two versions will be compared against each other. The following example compares revision 1.2 of showit.c to the current working revision (the revision currently in the working directory):

Index: main.c

RCS file: /space/cvs/newhello/main.c,v retrieving revision 1.2

retrieving revision 1.3


< char msg_hi[] = { "Hi there, programmer!" };

< char msg_bye[] = { "Goodbye, programmer!" };

> char msg_hi[] = { "Hi there, programmer!\n" };

> char msg_bye[] = { "Goodbye, programmer!\n" }; 12c12

The diff output is easier to understand than you might expect. Lines that begin with < appear in the first file (revision 1.2 of main.c) but not in the second (revision 1.3 of main.c). Similarly, lines beginning with > appear in the second file, but not in the first. Each section of diff output begins with an alphanumeric sequence such as 9,10c9,10 or 12c12.

The numeric values of the diff output indicate the lines in the first and second files to which an operation must be applied to get the second file from the first. The operation to perform, such as inserting, deleting, or changing lines, is specified by the alphabetic character. So, for example, the sequence 9,10c9,10 means to create the second file from the first you have to change (c) lines 9 and 10 of the first file to lines 9 and 10 of the second file.

Finally, if you totally botch all of your changes to your working files and want to revert to the most recent versions, use the update command. It updates the specified directory with the most recent versions stored in the repository, as shown in the following example:

cvs update: Updating . U showit.c U msg.c U hello.c

There's much more to CVS than the few examples presented here. For additional information, visit the CVS home page on the Web at

Although CVS improves a lot on the limitations of RCS, CVS has its own limitations. Subversion is a newer source code control system that aims to solve many of the limitations of CVS. See for more on SVN.

Was this article helpful?

0 0

Post a comment