There are three main advantages to using CVS over RCS. First, CVS allows for multi-directory projects, which RCS does not. Second, CVS allows for concurrent management of projects - in other words, multiple programmers can work on the same project, and CVS will assist in merging each programmer's work into the revisions of the others. Third, CVS allows for remote access to repositories, so you can make your projects available to potential users and developers across the Internet.
There are two main features of CVS that we will use. One is its provision for maintaining a complete history of each document (source code or documentation page) in your projects. At any time you can recover earlier versions of files almost as easily as you can work with the current version. The second feature is the facility that CVS provides for documenting changes you make to your files as you develop a project. There are many more features that CVS can provide, but we will not take advantage of them in this course. If you want to learn more, consult the man page for cvs and the Cederqvist, the main documentation for the CVS project. If you find the manual name puzzling, or have other questions about CVS, you may also wish to consult the official CVS FAQ.
To create the main CVS repository, first choose a directory on your local machine. A typical choice is /usr/local/cvsroot. Assuming that this is the directory you have chosen, you can initialize your repository with the command:
$ cvs -d /usr/local/cvsroot initYou should set the environment variable
CVSROOT
to point to
the CVS repository. In C shell environments, this is achieved with the
command:
$ setenv CVSROOT /usr/local/cvsrootwhile in BASH or KornShell environments, you would use:
$ export CVSROOT=/usr/local/cvsrootYou may wish to place these environment variable settings in a global location such as /etc/profile, or in your local user initialization scripts, so that they are always accessible.
$ mkdir project1 $ mkdir project1/manAfter that, you would use the following commands to register these directories inside the CVS repositories:
$ cd project1 $ cvs import -m "Created directory structure" project1 yourname startThe format of the import command is as follows: the -m directive provides a message that will be stored in CVS' logs, specified by the string after the directive. project1 is the directory under the CVSROOT in which the project will be stored. yourname should be replaced by your name - this is the vendor tag which specifies who has made the revisions; while the concept of vendors won't be used in this course, CVS requires that you specify one in the initial revision. Finally, start tells CVS to initialize the project within the repository.
The next step is to add the project to the CVS modules database, so that CVS can identify the project with a simple project name. To do this, you must first get a working copy of the CVS modules file:
$ cvs checkout CVSROOT/modules $ cd CVSROOTOpen the
modules
file in a text editor and add the
following at the bottom:
project1 project1The first project1 specifies the module name, which you will use to refer to the project. The second refers to the directory under the CVSROOT in which the file will be stored.
After you have saved the file, you must commit the changes you have made:
$ cvs commit -m "Added the project1 module." modulesAnd finally, release the modules file.
$ cd .. $ cvs release -d CVSROOTThe checkout command seen above is used to check a module out from the repository - in other words, to obtain a copy for editing, review, or compilation. The
CVSROOT/modules
module seen
above is automatically provided by CVS; in the case of your project, you
will check out the project1
module you created above using
the command:
$ cvs checkout project1The syntax of the release command is discussed in more detail in the CVS documentation.
.cc
or a header file, starts
like this:
// $Id$ /* SUMMARY * * * REVISION HISTORY * $Log$ */The complete form of this file header is described in the Coding Guidelines for this course. Our attention here is on the
$Id$
and $Log$
lines, which must be written with exactly the capitalization and
punctuation shown here in order to work properly with CVS. These are
examples of CVS keywords (sometimes called CVS macros)
which will be modified by CVS as you work on your project. There is a
list
of all CVS keywords you can look at if you wish, but you only need
the two lines listed here for this course. Note that these keywords
appear on comment lines. If they were placed anywhere else the compiler
would recognize that they are not valid C or C++ code, and would produce
syntax errors.
The other files that you will create for the projects in this course are
the Makefile
that goes in each project directory, and the
man pages that you use to document your projects. Comment lines
in Makefiles start with a hash symbol in column 1:
# $Id$ # comments ... # # $Log$ #Comments in man pages start with dot-backslash-quote:
.\" $Id$ .\" .\" comments ... .\" .\" $Log$ .\" .TH ...Once you are comfortable working with these two CVS keywords, you might want to put some of the other keywords inside character strings so your program can use them as data for one reason or another (such as including the program's version number in the "About" message of a Help window). However, that topic goes beyond the scope of this document. We will look at
$Id$
and $Log$
again after
going over some basic CVS concepts.
After you have created a new file or directory inside the project tree, enter the following command from the directory in which the new file or directory resides:
$ cvs add filenameThis will inform CVS to watch the file and prepare to add it to the repository. You can add as many files as you like before you commit the changes; if you change your mind about adding the file, you can issue the command
$ cvs remove filenamebefore you commit, and the file will be removed from the list of watched files. After adding the file, you commit it:
$ cvs commit filenameThis copies the file into the CVS repository for the project. What this really means is that the file, along with some additional information, will be copied into the CVS subdirectory and given a new name, which will consist of the original file name with ",v" at the end. You can list the contents of the CVS subdirectory to verify this. Do a long listing, and you will also notice that the database file (also called the "history" file) is made read-only. From now on you can make changes to the file only by telling CVS that you want to do so. You could change permissions on the history file and change its contents manually, but don't. Really don't.
When you commit the changes, you must provide a message that will be stored in the history file, providing you with a continuous log of modifications made to the file. This message should be a short summary of just what it is that makes this version of the file different from the previous version. If you fixed a bug, tell what the bug was. If you added a new feature, tell what the feature does. If you changed comments, tell what kind of changes you made. The log message does not have to be long, but it must be concrete and meaningful, not vague.
You have two options as to how to provide this message. If you use the cvs commit filename command above, CVS will attempt to open an editor - specified by the environment variable EDITOR. $EDITOR usually points to vi, but you can change the environment variable to select another editor. Alternatively, you can specify a short message directly at the command line using the -m directive seen above:
$ cvs commit -m "Made some minor spelling corrections." filenameA file need only be added to the repository once; once that is done, you report changes by using the commit command. So from now on, after editing the file, be sure to issue cvs commit filename to copy those changes into the CVS repository and make them publically available. This gives you the benefit of having a stable copy of a source file and a working copy - while the CVS repository may only contain code that you want to make public, you can carry around the working copy and make as many changes as you wish, finally only committing them when you are certain that the code works well.
As another option, you can issue the cvs commit directive in a directory without the filename to commit all of the files in that directory that have been edited. However, as a rule, it's best to commit the files one at a time so that you can keep track of which files have been changed.
If for some reason you want to bring all of your files up to a certain revision number, you can use the -r option - for instance
$ cvs commit -r 3.0will bring all of the files in the repository - including those you haven't edited - up to version 3.0. Correspondingly, you can use -r to retrieve a specific version of a file. If the file
foobar.cc
is currently at version 3.0, and you decide that
you want to re-examine revision 1.2, the command
$ cvs checkout -r 1.2 foobar.ccwill check out the required version.
However, since revision numbers are usually not used for this purpose,
and are difficult to keep aligned, CVS includes support for
tagging. You can use tags to mark a milestone release of a
project without bringing all of the version numbers in synch. To apply
a tag, enter the base directory of your checked-out project, and use the
tag directive to apply a tag name to the current version of your
project. For instance, if you wanted to label the current release of
your project rel-1-0
, you would issue the command:
$ cvs tag rel-1-0This tag will be applied to all of the current versions of the source files; after later revisions, if you wanted to return and check out
rel-1-0
of your project, you could use the -r
directive:
$ cvs checkout -r rel-1-0 project1
$Id$
keyword will tell you the name of the file, its
version number, who last modified it, and when. We put this keyword on
the first line of the file so this basic summary information is always
the first thing anyone sees when they first look at the file. The
$Log$
keyword will be expanded to give the complete
modification history of the file, that is, comment lines from all the
log messages you entered when checking in revised copies of the file
along with the revision dates and numbers. Be sure these log messages
provide useful information for programmers who might need to work on a
file after you.
CVS provides support for reserved checkouts using the -l flag. To lock a file or branch, issue the command:
$ cvs admin -lConversely, you can unlock the file or branch with the -u flag:
$ cvs admin -uHowever, file locking is considered a primitive method of revision control, and CVS was chiefly designed to provide a more sophisticated paradigm for multi-developer programming. The Cederqvist contains CVS' rationale for supporting newer methods in the section Choosing Between Reserved or Unreserved Checkouts; this material is too detailed to cover here. In CVS' model, multiple developers can check out, edit, and commit their changes to a source file. The first developer to check the file back in knows nothing about the subsequent developers; however the later developers are required to integrate their changes on check-in. The CVS documentation covers this topic in far greater detail.
Purdy, Gregor N CVS Pocket Reference. O'Reilly & Associates, 2000. ISBN 0-596-00003-0.There is also a book by the same publisher on RCS and a similar package that comes with Solaris, called SCCS:
Bolinger, D. & Bronson, T. Applying RCS and SCCS. O'Reilly & Associates, 1995. ISBN 1-56592-117-9.Additionally, the same publisher has a book on make:
Oram, A. & Talbott, S. Managing Projects with Make. O'Reilly & Associates, 1991. ISBN 0-937175-90-0.You can contact this publisher at www.oreilly.com.