LAB 9 - CVS - Concurrent Version System

Goal

What is CVS

CVS is a system that lets groups of people work simultaneously on groups of files (for instance program sources). It works by holding a central `repository' of the most recent version of the files. You may at any time create a personal copy of these files by `checking out' the files from the repository into one of your directories. If at a later date newer versions of the files are put in the repository, you can `update' your copy. You may edit your copy of the files freely. If new versions of the files have been put in the repository in the meantime, doing an update merges the changes in the central copy into your copy. When you are satisfied with the changes you have made in your copy of the files, you can `commit' them into the central repository. When you are finally done with your personal copy of the files, you can `release' them and then remove them.

CVS terminology

Repository
The directory storing the master copies of the files. The main or master repository is a tree of directories.
Module
A specific directory (or mini-tree of directories) in the main repository. Modules are defined in the CVS modules file.
RCS
Revision Control System. A lower-level set of utilities on which CVS is layered.
Check out
To make a copy of a file from its repository that can be worked on or examined.
Revision
A numerical or alpha-numerical tag identifying the version of a file.

How to make a repository

If you have no CVS repository yet, it will be necessary to create one. The repository can store any ASCII files, and even binary files. Earlier versions of CVS could not store binary files. So, source code, Makefiles, READMEs, data cards, HTML files, and even postscript files. To create a repository, you simply declare an environment variable CVSROOT to point at a directory to use as the repository, and run 'cvs init'. You don't even have to create the directory first. Example: Creating a private CVS repository.
/tmp> setenv CVSROOT /tmp/cvs
/tmp> cvs init

It can make a big difference where you are in the directory tree when you execute a CVS command. You should normally be in the directory you were in when you retrieved your code from the CVS repository, or in the directory immediately above it. You should never issue CVS commands in the directory you have declared to be your CVSROOT, nor in any directory below it. CVS will get confused if you do, and may go into an infinite loop which will fill the disk. Nor should you ever edit files in the CVSROOT directory tree by hand, unless you are willing to learn a lot more about CVS than I explain here! In short, the CVSROOT directory is for CVS, and you should only use CVS commands to manipulate the files therein. In the examples I give here, you can see the last two elements of the directory I am in as part of the prompt. I have a CVS repository in /tmp/cvs, and a CVS working area in /tmp/test. When you want to play with CVS, start with a private repository. You can switch between different repositories as needed simply by changing the CVSROOT environment variable, though be warned that you should NOT try to use two different repositories for the same piece of code.

Creating a module using cvs import command

Once the administrator has created the repository, users with write permissions to the repository’s directory may create "modules"-- that is, groups of files that are related by project. Once a module is created, then new files and revisions of old files may be added to an existing module. Users who wish to work on a particular group project may check out a module, modify the files contained in it, and then commit the changes back to the repository for other users to work with later on. To create a new module, a user must use the cvs import command. For example, suppose that you are in the directory /home/paul/images/ and you want to create a new module stored in a directory called newmodule. The user could then type

cvs import newmodule unm start
In this case, the command creates a subdirectory called "newmodule" contained within the directory /var/cvs/. The tag unm is known as a vendor tag (specifies the organization which created the module) and the tag start is known as a release tag (not very important for our purposes; might be used to specify a particular edition of a project - in any case, it can’t be left blank). After the command is entered, CVS brings up an editor so the user can create a log entry to mark the module’s creation. This can be bypassed by using the -m option, for

example: cvs import -m "First new module" newmodule unm start

This does the same thing as the previous cvs command, except that it automatically enters into the log whatever is typed between the quotation marks. When the cvs import command is executed, you’ll notice that a directory called CVS is created recursively in all directories below the current directory as well as in the current directory itself; this informs CVS that the current directory and every directory below the current directory are all parts of the specified module (newmodule, in this case). In this way, any files added to the repository that are located within /home/paul/images/ or within any of its subdirectories will automatically be placed within the module "newmodule".

Obtaining a working copy

After creating a module using cvs import, you need to obtain a working copy of the module in your own directory before you can commit or view modifications to the files within the module. Once you have checked out a module to your own directory, you can edit any of the files within the module (regardless of whether anyone else using the repository is editing them), update them to include new changes applied by others to the source repository, or commit your work as a permanent change to the source repository. YOU MUST checkout a module from the repository before you can use most of CVS’s useful commands. All of these things are done using the cvs checkout command. For example, you might type cvs -d /var/cvs/ checkout newmodule which would cause CVS to look in the directory /var/cvs/ to find the module called "newmodule" and then to create a new subdirectory called newmodule in your current directory. From inside this directory, you can add files to the repository using the cvs add command, update files that have been added using the cvs update command, and commit your own changes to added files using the cvs commit command.

Adding a file using cvs add

Once a directory (and all directories below it) have been designated to a particular module, and you have obtained a working copy of the module in your own directory using cvs checkout, then new files created within any of these directories can be added to the module using the cvs add command. Suppose you create a new file called "newfile" contained within /home/paul/images/newmodule. To add this file to the module "newmodule" in the repository, you need only to enter /home/paul/images and type cvs add newfile. This will automatically add newfile to the module newmodule (you need not specify which module you want to add "newfile" to since the cvs import command has already told CVS that any file at or below /home/paul/images that is added to the repository is automatically placed into "newmodule").

Basic Commands

cvs checkout (or cvs co)
To make a local copy of a module's files from the repository execute cvs checkout module where module is an entry in your modules file (see below). This will create a sub-directory module and check-out the files from the repository into the sub-directory for you to work on.
cvs update
To update your copy of a module with any changes from the central repository, execute cvs update. This will tell you which files have been updated (their names are displayed with a U before them), and which have been modified by you and not yet committed (preceded by an M). It can be that when you do an update, the changes in the central copy clash with changes you have made in your own copy. You will be warned of any files that contain clashes by a preceding C. Inside the files the clashes will be marked in the file surrounded by lines of the form and . You have to resolve the clashes in your copy by hand. After an update where there have been clashes, your original version of the file is saved as .#file.version. If you feel you have messed up a file and wish to have CVS forget about your changes and go back to the version from the repository, delete the file and do an cvs update. CVS will announce that the file has been ``lost'' and will give you a fresh copy.
cvs commit
When you think your files are ready to be merged back into the repository for the rest of your developers to see, execute cvs commit. You will be put in an editor to make a message that describes the changes that you have made (for future reference). Your changes will then be added to the central copy. When you do a commit, if you haven't updated to the most recent version of the files, CVS tells you this; then you have to first update, resolve any possible clashes, and then redo the commit.
cvs add and cvs remove
It can be that the changes you want to make involve a completely new file, or removing an existing one. The commands to use here are:
cvs add filename
cvs remove filename
You still have to do a commit after these commands to make the additions and removes actually take affect. You may make any number of new files in your copy of the repository, but they will not be committed to the central copy unless you do a cvs add. CVS remove does not actually remove the files from the repository. It only removes them from the ``current list'' and puts the files in the CVS Attic. When another person checks out the module in the future they will not get the files that were removed. But if you ask for older versions that had the file before it was removed, the file will be checked out of the Attic.
cvs release
When you are done with your local copy of the files for the time being and want to remove your local copy use cvs release module. This must be done in the directory above the module sub-directory you which to release. It safely cancels the effects of cvs checkout. Usually you should do a commit first. If you wish to have CVS also remove the module sub-directory and your local copy of the files then your cvs release -d module.
cvs log
To see the commit messages for files, and who made them, use: cvs log [filename(s)]
cvs diff
To see the differences between your version of the files and the version in the repository do:
cvs diff [filename(s)]
cvs tag
One of the exciting features of CVS is its ability to mark all the files in a module at once with a symbolic name. You can say `this copy of my files is version 3'. And then later say `this file I am working on looked better in version 3 so check out the copy that I marked as version 3.' Use cvs tag to tag the version of the files that you have checked out. You can then at a later date retrieve this version of the files with the tag.
cvs tag tag-name [filenames]
Later you can do: cvs co -r tag-name module
cvs rtag Like tag, rtag marks the current versions of files but it does not work on your local copies but on the files in the repository. To tag all my libraries with a version name I can do:
cvs rtag LIBRARY_2_0 lib
This will recursively go through all the repository directories below lib and add the LIBRARY_2_0 tag to each file. This is one of the most useful features of CVS . Use this feature if you about to release a copy of the files to the outside world or just want to mark a point in the developmental progression of the files.
cvs history
To find out information about your CVS repositories use the cvs history command. By default history will show you all the entries that correspond to you. Use the -a option to show information about everyone.