Back to #itlab main page

Probably the most definitive handbook for CVS usage is and the following documents the CVS usage at Laboratory of Information Processing.

Setting up on Linux/Unix workstations

The CVSROOT environment variable needs to be set.
In tcsh: setenv CVSROOT ""
In bash: export CVSROOT=""
Replace user with your login name in the NIS.

CVS also needs a text editor to allow you to write the commit messages. It can be set via the environment variables EDITOR or specifically for cvs CVSEDITOR. Do not change the file name when saving your message to a file during commit.

Before you can use the CVS repository, you have to

cvs login

The encrypted password is saved in file ~/.cvspass.

Using CVS (basic)

Binary files should not be put into CVS without special care. Should you want to add binary files, use command

cvs add -kb file_name(s)

Writing a good commit message

In every commit and also on some other occasions CVS asks you to write a log message. You should never leave it blank, no matter how simple changes you made. It's not so important to tell exactly what you did but why you did it. If someone wants to know what you changed, he can view the differences in files with the cvs diff command. Of course, some kind of description of changes is always apropriate. You can view the log messages with the cvs log command, and if you write good messages, you will “automatically” get a work diary.

Suggestion for module layout

This is an example from the GMMBayes project, as instructed to PQ by Joni, and refined a bit.

The module is called gmmbayes and all the following are directories:

|-- doc                        documentation tree
|   |-- report01               paper/report
|   |   `-- resources          resources (e.g. pictures)
|   |-- report...
|   |
|   `-- resources              common document resources, e.g. bibfile
`-- src                        source code tree
    |-- c                      C code tree
    `-- matlab                 Matlab code tree
        |-- base               Matlab functions to be used by others, also a usage demo
        `-- demos              Matlab codes used in documents
            |-- report01       Codes used in report 1
            `-- report...
  • gmmbayes/doc/index.txt should tell what the different reports are.
  • gmmbayes/src/matlab/base/Contents.m should show a summary of the available functions in base/.

All functions in the base/ should have a unique prefix so that there will be no name space clashes when the base directories of several different modules are added to Matlab search path. Drastic changes - like API changes - should not be done in an existing and used base directory, because it will break applications that use it. If backwards compatibility cannot be preserved, a new base directory should be created. In that case gmmbayes/src/matlab/index.txt would be a good idea.

When to commit?

It depends. If the target is in active use others, like the base/ directory, you should first make sure the commit does not break anything.

If the target is used just by you, you should commit after every completed edit and even during longer editing sessions. CVS can be a backup repository so use it as such. Also it's good to commit all changes as the last thing done every day. Your computer might explode any time ;-)

Configuration files under version control

If you have files that the user is likely to have to modify for their local environment, do not put them directly into CVS. If they are in CVS as themselves, users might accidentally commit their local changes into CVS, and other users might pull these (incorrect for them) changes from CVS, corrupting their own files. Also cvs diff command would always show differences and cvs update would report local changes, that should never go into CVS.

Instead, add .cvs to the file name and put that into CVS. Users can identify files, that may need local changes, from the suffix .cvs and make a local copy of the file outside CVS. This way users do not accidentally commit or corrupt local configurations to/from CVS.

There is a helper script for this in the itlab CVS-module at itlab/utils/checklocal.bash. The script automatically creates the local copies without the suffix of all .cvs files if they do not exist. The script notifies if the .cvs file is newer than the local copy, so you can easily see if there have been updates in CVS. The script can also show the difference of all .cvs files versus their local copies.


Branching in CVS is somewhat tedious and may lead to human errors. Therefore we usually copy entire directories instead of actually branching; we use forking. When forking, be sure that you will never want to merge all changes from the fork back into trunk. If you think you might merge changes back to trunk, use branching instead.

When forking a directory, first make sure you have the latest version of the contents:

cvs update -d

Then, tag the contents so you can trace the files later if necessary:

cvs tag BASE4

The tag is named BASE4 because we the fork will be base4/. Then create the fork:

cd ..
mkdir base4
cp -r base3/* base4/
rm -r base4/CVS
cvs add base4
cd base4
cvs add <i>files...</i>
cvs commit

And in the commit message state why you forked, where you forked from, and what was the tag.

Do not edit any files in the copy phase, you will lose traceability of those changes.

Before you do cvs add for directories, remember to remove all the old CVS directories.

There is also another way to do the fork, perhaps a better one. After tagging your src:

cd ..
mkdir base4
cvs export -r BASE4 -d base4 mymodule/src/base3

and then remove the files you do not want in the fork from base4/ and then continue with cvs add etc.


When really want to use branches, like with CPP Library, this is how you do it.

To create a branch, first tag the current version of the tree, do a new checkout into a different directory, and create the branch tag. Do not forget to update branch information in the project documentation.

Here is an example where initial tag name is Config_0-begin and branch name is Config_0-branch.

cvs tag Config_0-begin
cd ..
cvs co -d mytree-config -r Config_0-begin mytree
cd mytree-config
cvs tag -b Config_0-branch

Now you are still in the old branch. You can get to the new branch with

cvs update -r Config_0-branch

or by checking out once more

cvs co -d mytree-config-branch -r Config_0-branch mytree

To see all the changes in your branch, once you have been working on it

cvs -q diff -N -rConfig_0-begin -rConfig_0-branch

A nasty feature of CVS is that it works on per file basis and all files have their own history. Therefore it is recommended to branch the whole module (or a subtree).The branches and tags of a file, and the active branch (sticky tag), can be seen with

cvs status -l -v dirorfile


Branches can be merged back to the trunk, or to another branch. To be explained…

Images and Data in CVS

CVS is not a place for large data files, use itlabdata for that.

Images, that are used in documents, can be put into CVS along the document source code. However, the images should be scaled down to reduce file size, no need to put a high resolution image into a document, that cannot be printed in that resolution. Put the high resolution original images into itlabdata, and scaled down EPS format versions of them into CVS.

For proper downscaling, see LaTeX Hints: Using pixel images.

This does not concern vector graphics as those files tend to be a lot smaller than pixel images.

Note! Whenever you add binary files into CVS (and that should not be too often), remember to use -kb

Final Versions of Documents

Generated files should usually not be put into CVS. However, final versions of documents and other similar things would be good in the CVS. That way the submitted article or whatever is permanently saved, even though (in theory) it could be generated again. Software changes and the source might not compile anymore, things happen. Do NOT put the final version so that the next 'make' will overwrite it. Use for instance subdirectory final/, where you copy the final complete versions by hand. And remember to use -kb when you 'cvs add' the files.

Binary executable files should probably not be saved like this, they need to be recompilable.

Small tips and tricks

Changing your password requires a new cvs login (or else you get “authorization failed” :)

Use keyword substitution in your code files, so that when the file is taken away, you can still see what revision and from where it is. Recommended keywords are $Id$ and $Name$. Put those strings in the code as comments and cvs commit will rewrite those strings showing useful info.

If you happen to cvs add a file and notice a mistake before doing cvs commit, you can revert the situation by removing the corresponding line from CVS/Entries file. for automatically creating a GNU-style changelog.

Access outside LUT

Purpose to make LUT cvs working in machine A, when we have different kind of connections between A and some machine (cvs accessible) at LUT. Here are some examples:

  • Available connection: LUT→A
  • LUT=polaris
  • A:cvssp-ssh
  • SSH-PORT:22 (default, after “-p”)
  • FORWARD-PORT:2401 (cvs default, ensimmainen 2401)

Go somehow to machine LUT and there say:

polaris:~> ssh -C -v -R -p 22 sleep 3600000
  • Available connection: A→LUT
  • LUT=polaris
  • A:betelgeuse

Go somehow to machine A and there say:

[jkamarai@betelgeuse|~]$ ssh -C -v -L -p 22 sleep 3600000
  • Available connection A→B←LUT
  • LUT=polaris
  • A: cpc1-glfd4-0-0-cust926
  • B: cvssp-ssh

Go somehow to machine LUT and there say:

# Go somehow to machine A and there say:
[jkamarai@cpc1-glfd4-0-0-cust926|~]$ ssh -C -v -L 2401:localhost:2401 -p 22 sleep 3600000

After one of the previous ones is done you may use cvs in machine A (Note: if localhost does not for some reason work, use

% cvs -d:pserver:jkamarai@localhost:/net/regulus/project/cvsroot login
% cvs -d:pserver:jkamarai@localhost:/net/regulus/project/cvsroot co rtmosaic