this summary written by Geoff Berry gcb@cs.duke.edu

What is CVS?

From the man page:
  cvs - Concurrent Versions System

DESCRIPTION
     cvs is a front end to the  rcs(1)  revision  control  system
     which  extends the notion of revision control from a collec-
     tion of files in a single directory to a  hierarchical  col-
     lection  of  directories  consisting  of revision controlled
     files.  These directories and files can be combined together
     to  form  a  software  release.   cvs provides the functions
     necessary to manage these software releases and  to  control
     the  concurrent  editing  of  source  files  among  multiple
     software developers.
  

Setting Up A Repository

What Is A Repository?

For a group to use CVS a single CVS repository must be created. The CVS repository stores a complete copy of all the files and directories which are under version control.

Normally, you never access any of the files in the repository directly. Instead, you use CVS commands to get your own copy of the files, and then work on that copy. When you've finished a set of changes, you check (or "commit") them back into the repository. The repository then contains the changes which you have made, as well as recording exactly what you changed, when you changed it, and other such information.

Specifying A Repository

To allow the CVS commands to work on your group's repository, you must set the $CVSROOT environment variable to the absolute path to the root of the repository. For example if the repository for my group was in my home directory in the subdirectory cps108/Repository I would add the following line to my .cshrc file (don't forget to source the .cshrc file so the changes take effect): setenv CVSROOT ~/cps108/Repository If the repository is in another user's directory hiearchy you cannot use the abbreviation, you'll need to specify the complete path, e.g., setenv CVSROOT /afs/acpub/users/g/c/gcb/cps108/Repository

Creating A Repository

Now that the location of the repository has been specified in the environment, it must be created. Note that this is only done once, NOT for each project. To create a repository, type: cvs init This will create an empty repository in the directory specified by $CVSROOT. If you get an error message then you probably forgot to source your new .cshrc file and the shell can't find the $CVSROOT environment variable.

File Permissions in the Repository

The directories inside the repository should be writable by the persons that have permission to modify the files in each directory. This normally means that you must create a group consisting of the persons that are to edit the files in a project, and set up the repository so that it is that group that owns the directory.

Creating Groups on AFS (acpub)

On the acpub system running AFS, individual users can create groups. Use the pts command to do this. To create a group (done by the user with login-id peter, for example): pts creategroup peter:hyperwag To add users to the group: pts adduser paul peter:hyperwag pts adduser mary peter:hyperwag Now the directory in the repository can be made writable by the group, peter does this since he owns the directory. If the name of the project is `hyperwag' peter would type: fs setacl ${CVSROOT}/hyperwag peter:hyperwag write Now everyone in the group `peter:hyperwag' can access and modify files in the `hyperwag' subdirectory of the repository. (Note, if you get an "undefined variable" when you type the line above try without the braces, i.e., $CVSROOT/hyperwag instead of ${CVSROOT}/hyperwag.


Using CVS

Starting a Project From a Tree of Files

When you begin using CVS, you will probably already have several projects that can be put under CVS control. In these cases the easiest way is to use the `import' command. An example is probably the easiest way to explain how to use it. If the files you want to install in CVS reside in ~/cps108/hyperwag , and you want them to appear in the repository as `$CVSROOT/hyperwag', you can do this: prompt> cd ~/cps108/hyperwag prompt> cvs import -m "Imported sources" hyperwag Group7 start Unless you supply a log message with the `-m' flag, CVS starts an editor and prompts for a message. The string `Group7' is a "vendor tag", and `start' is a "release tag". They may fill no purpose in this context, but since CVS requires them they must be present.

You can now verify that it worked, and remove your original source directory. In the dialog below, the user moves the hyperwag directory to hyperwag.orig then check out the project named hyperwag (the hyperwag.orig directory is a backup in case something didn't work properly).

prompt> cd .. prompt> mv hyperwag hyperwag.orig prompt> cvs checkout hyperwag prompt> ls hyperwag prompt> rm -r hyperwag.orig Erasing the original sources is a good idea, to make sure that you do not accidentally edit them in `hyperwag.orig', bypassing CVS. Of course, it would be wise to make sure that you have a backup of the sources before you remove them.

Starting a Project From Scratch

For a new project, the easiest thing to do is probably to create an empty directory structure in your working directory ( e.g. ~/cps108 ), like this: prompt> mkdir hyperwag prompt> mkdir hyperwag/doc prompt> mkdir hyperwag/testing After that, you use the `import' command to create the corresponding (empty) directory structure inside the repository: prompt> cd hyperwag prompt> cvs import -m "Created directory structure" hyperwag Group7 start Then, use `add' to add files (and new directories) as needed. $ cvs add Reader.cc Writer.cc

Getting the Source

The first thing you must do is to get your own working copy of the source for hyperwag. For this, you use the checkout command: cvs checkout hyperwag This will create a new directory called `hyperwag' and populate it with the source files (e.g. `Reader.cc' and `Writer.cc').

You start your favorite editor, hack away at `Reader.cc', and a couple of hours later you have added support for a new week-at-glance language to the Reader hiearchy.

Committing Your Changes

When you have checked that hyperwag is still compilable you decide to make a new version of `Reader.cc'. cvs commit Reader.cc CVS starts an editor, to allow you to enter a log message. You type in "Added support for new language.", 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 the editor defaults to vi. If you want to avoid the overhead of starting an editor you can specify the log message on the command line using the `-m' flag instead, like this:

cvs commit -m "Added support for new language." Reader.cc

Bringing a File Up to Date

When you want to update or merge a file, use the update command. For files that are not up to date this is roughly equivalent to a checkout command: the newest revision of the file is extracted from the repository and put in your working copy of the module.

Your modifications to a file are never lost when you use update. If no newer revision exists, running update has no effect. If you have edited the file, and a newer revision is available, CVS will merge all changes into your working copy.

For instance, imagine that you checked out revision 1.4 and started editing it. In the meantime someone else committed revision 1.5, and shortly after that revision 1.6. If you run update on the file now, CVS will incorporate all changes between revision 1.4 and 1.6 into your file.

If any of the changes between 1.4 and 1.6 were made too close to any of the changes you have made, a "conflict" occurs. In such cases a warning is printed, and the resulting file includes both versions of the lines that overlap, delimited by special markers.

Handling Conflicts

Suppose revision 1.4 of `Reader.cc' contains this:
      Reader::Reader( const string & filename )
      {
        myFilename = filename;
      }
      
Revision 1.6 of `Reader.cc' contains this:
      Reader::Reader( const string & filename )
        : myFilename( filename )
      {
      }     
      
Your working copy of `Reader.cc', based on revision 1.4, contains this before you run cvs update:
      #include 

      Reader::Reader( const string & filename )
      {
        myFilename = fullPath( filename );
      }     
      
You run cvs update: prompt> cvs update Reader.cc RCS file: ~cps108/Repository/hyperwag/Reader.cc,v retrieving revision 1.4 retrieving revision 1.6 Merging differences between 1.4 and 1.6 into Reader.cc rcsmerge warning: overlaps during merge cvs update: conflicts found in Reader.cc C Reader.cc CVS tells you that there were some conflicts. Your original working file is saved unmodified in `.#Reader.cc.1.4'. The new version of `Reader.cc' contains this:
      #include 

      Reader::Reader( const string & filename )
        : myFilename( filename )
      {
      <<<<<<< Reader.cc
        myFilename = fullPath( filename );
      =======
      >>>>>>> 1.6
      }
      
Note how all non-overlapping modifications are incorporated in your working copy, and that the overlapping section is clearly marked with `<<<<<<<', `=======' and `>>>>>>>'.

You resolve the conflict by editing the file, removing the markers and the erroneous line. Suppose you end up with this file:

      #include 

      Reader::Reader( const string & filename )
        : myFilename( fullPath( filename ) )
      {
      }
      
You can now go ahead and commit this as revision 1.7. prompt> cvs commit -m "Changed constructor to use initializer list." Reader.cc Checking in Reader.cc; ~/cps108/Repository/hyperwag/Reader.cc,v <-- Reader.cc new revision: 1.7; previous revision: 1.6 done

CVS Keywords

You can include CVS keywords in source (and object) code so that the revision number, author, date, etc. is always shown in code (and in object files). A keyword is typed with case matching exactly as shown below between two dollar signs $$, e.g., $Date$. When a file is checked out, the keyword is replaced by its value, e.g., "January 20, 1998". Keywords are typically put in comments as shown below. #include <iostream.h> // Demo program for CVS // $Id$ int main() { cout << "Hello World" << endl; } When the file is checked out (for the first time) the source is as follows: #include <iostream.h> // Demo program for CVS // $Id: foo.cc,v 1.1 1997/01/20 22:58:41 ola Exp $ int main() { cout << "Hello World" << endl; } To include CVS information in object files, create a dummy string variable in your source code that will generate a string in the compiled code. static const char CVSid[] = $Id$;

For More Information

To find out anything else you could possibly want to know about CVS consult the CVS info pages. The can be accessed via emacs through the following commands: M-x info g (/usr/pkg/cvs-1.9/share/info/cvs.info)Top
This document contains text from the CVS info pages, the man page cvs(1), and is based on the cps108 RCS tutorial availible on the cps108 web page.
Owen L. Astrachan
Last modified: Fri Feb 13 11:42:22 EST 1998