CVS in the HiPE project


It is just as well to begin this section with a pointer to the CVS Home Page.

Online CVS documentation

For the full CVS documentation, type "info cvs" in your Unix shell.

Using CVS

All shell commands below are given in sh- (bash-) syntax. Modify accordingly if you use another shell.


  1. (Optional step for members of the HiPE project only)
    Execute the following commands:
        mkdir /it/project/fo/hipe/YOUR-USER-NAME
        ln -s /it/project/fo/hipe/YOUR-USER-NAME ~/hipe
        cd ~/hipe
    You should now have a soft link named hipe from your current directory to a new directory with the same name as your Unix user name, under the main directory of the HiPE project. Below that directory, you will place, in step 4 below, your own checked-out copy (the directory called otp) of the Open Source Erlang + HiPE source code tree. You should keep all your HiPE code and related files under the directory that you can now find by either of the paths "~/hipe/YOUR-USER-NAME/" or "/it/project/fo/hipe/YOUR-USER-NAME/".

    Note: If you are not a HiPE group member, or you just don't want to) create a directory under /it/project/fo/hipe/, you can just do the cvs checkout command in any other directory.

  2. (Optional) Add the following to your .bashrc:
            export CVSIGNORE='*.o *.beam'
    (add more entries to CVSIGNORE if you want).

  3. Since December 2006, there is the possibility to use a guest account on our CVS server. However, the guest account gives you only read access to the OTP repository. For some uses, this access is enough and if so, we recommend it as it is the easiest way to get the system. Simply issue the following command:
            cvs -d export otp
    (similar for the module tests). You are now ready to roll.

  4. Otherwise, you first have to establish a login capability with the CVS server where the HiPE-enabled OTP repository lies. This needs to be done once and can be done as follows: If USER denotes your CVS server username (OBS! this is not necessarily your machine account name), issue the following command.
            cvs -d login
    where METHOD is either Regardless of the method, you will then be prompted to type your password (once) which will create a ~/.cvspass file in your home directory.

  5. To get the OTP/HiPE and tests modules that the HiPE CVS server currently contains, execute the following commands (after making sure that the above commands have been successfully executed by your current shell):
        cvs -d checkout otp
        cvs -d checkout tests

If you are not interested in some (or even all) of the things in the checked out directories, you can simply delete them - they are just copies, and you can get them back at any time later. You can also check out multiple copies of the same files, e.g. for different hacks or subprojects.

As soon as you add and check in a new file or subdirectory with CVS, all other HiPE members are able to get a copy of their own, if they want to.

Also note that in each subdirectory that has been checked out, you will find a directory called CVS. This contains a few files with bookkeeping information for CVS and should usually not be tampered with.

Default flags for CVS commands

For HiPE hacking, we recommend creating a file ~/.cvsrc containing the following lines:
    diff -u
    checkout -P
    update -d -P
    tag -c
This assures that you get any newly added directories (-d) when you do an update, and that no empty (typically obsolete) directories are created.

Adding new files/subdirectories

When you want to add new files or subdirectories to a checked-out CVS tree (known as a "module" in CVS terminology - in our case everything under otp), you first create the file/directory at its proper place in the directory tree, and then write:
    cvs add YOUR-NEW-FILE-OR-DIR
    cvs commit -m "Added this thing." YOUR-NEW-FILE-OR-DIR
If you don't give the -m "..." option to "cvs commit", CVS will start your $EDITOR to make you enter a log message. Each cvs commit always logs a message.

(You can use ci as an abbreviation for commit. You can also give an -m "..." option to cvs add; this is to give short description of the file itself, but it is not required.)

Note that cvs add does not work recursively on the contents of a directory, and that you must execute the cvs add command from within the directory of the file to be added.

Committing files

Once added and committed, directories need not be committed again, but each time you have a somewhat stable version of a file, you probably want to commit it, so that version is safely stored and made accessible to the other members of the group.
    cvs ci -m "Changed some stuff." FILE
does this (like after cvs add above), and automatically bumps the CVS revision number. Preferably, you give a more useful log message than in this example.

Note that FILE does not have to be in the current directory, and if FILE is a directory name, CVS will update all its contents recursively, so be careful unless that is really what you want. In particular, leaving out FILE means the current directory (and recursively everything under it). This is the common behaviour for most CVS commands.

Correcting bad commit messages

If you screw up and check in a file with the wrong log message (it happens), you can correct it with the cvs admin command. First you have to note which version number the bad message was used for (e.g. 1.42). Then you do as follows:
    cvs admin -m1.42:'New message instead of the bad old one.'
which replaces the log message in the repository. There cannot be any spaces between -m and the version number - the whole option must be contiguous, that's why you need the quotes.

Updating files

When you check out a file in CVS, you get the latest version that was committed (by anyone). If someone checks out a copy, edits it, and commits the changed file, you might want to refresh your own copy, so you can see the changes (and benefit from them).
    cvs update FILE
will do precisely this. If you have edited FILE, CVS will simply merge the two versions, unless they collide (see CVS documentation on file conflicts), but your own changes are not committed until you yourself do a cvs commit.

Also remember that you can always backtrack to any previously committed version of a file, if you should commit a really stupid change.

Getting rid of changes - the easy way

If you modify a file, but realise that your changes were no good and you want to get back to the clean version from the repository, you could delete or rename the file and then do a cvs update - but the best way is the following:
    cvs update -C FILE
which will both rename your changed file to something like .#FILE.1.42 so you don't lose it, and replace it with a fresh copy from the repository.

Removing a file under CVS

If you have added and checked in a file, and later decide that the file no longer is needed, you do the following:
    rm NAME
    cvs remove NAME
    cvs ci -m "This file is no longer needed." NAME
(Note that you remove the file first, and then tell CVS that it is removed; then you commit the change as usual.)

The file is now considered dead by CVS; it is still stored in the repository, though, and all previously committed versions can be retreived. You cannot reuse the file name in the same directory.

Adding existing sources to CVS (starting a new "module")

Beside the otp directory, there are several other "modules" under the same CVS repository, e.g. bm (benchmarks), cerl (Core Erlang), hipe_doc (HiPE documentation), etc., each containing the code for some subproject. You may create a new such "module" as follows, assuming that you have a directory with stuff which is not already in the CVS repository (or you have an empty directory):

    cvs import -m "Initial import." MODULENAME VENDOR RELEASE:
where MODULENAME is the base path used for placing your files in the repository. This is the path you will use to check out the sources again. Usually, it is simply the last part of YOUR-EXISTING-DIRECTORY. E.g., if you have stuff in ~/project_X, you would cd ~/project_X and type cvs import -m "bla bla" project_X VENDOR RELEASE.

Note that this adds everything in the directory and its subdirectories, recursively, to CVS. (So first remove things like temporary files, object files, etc.)

VENDOR and RELEASE are "tags" that are used only for special purposes, but they must be given. We suggest you use hipe and start, respectively, as in cvs import -m "..." project_X hipe start.

After you have done this, delete or rename your original directory (you should not need it again - all files have been copied into the repository), then cd to a suitable place and type cvs checkout MODULENAME. In the previous example: cd ~, then rm -rf project_X and cvs get project_X.

The difference between the old directory and the new one is that you now have the necessary CVS information in each subdirectory.

Working with branches

If you want to use cvs to track your development, but without disturbing the files on the main branch, you can create a new branch. This is what you should do, in the following order:
  1. Check out a fresh copy, and (preferably) test that it is in fully working condition.
  2. Tag the checked-out system so you know where you started from! (This will save you a lot of trouble later. The CVS manual does not mention this.) E.g.:
        cvs tag my_new_project_root
  3. Now create the branch; this is also done with tag:
        cvs tag -b my_new_project
    (Note that CVS is too stupid to find the "root" revision for the new branch later on, even though it should be an easy thing. That's why we added our own root tag before we created the branch.)

If you now do cvs status on one of your files, you will notice that they are marked as "sticky", remembering that they belong to a particular branch. If you check in new changes, they will only be visible on this branch.

Now, you can also check out new copies of this branch, like this:

    cvs checkout -r my_new_project ...
and all the checked-out files will be "sticky".

To insert changes from the main "trunk" into your branch, use the -j flag with cvs update, as in

    cvs update -j my_new_project_root -j my_new_project_join_1
which will take the changes between the my_new_project_root point and the my_new_project_join_1 on the main trunk, and patch them into your working copies. (This might cause conflicts that you will have to resolve.) Then, (after testing...) check in the modifications on your branch. The my_new_project_join_1 version should be created just like we did with my_new_project_root, i.e., by checking out a fresh copy of the main trunk, testing it and then tagging it. Next time you join, you will use this point as the old version, as in
    cvs update -j my_new_project_join_1 -j my_new_project_join_2 
and so on.

The same method is used for taking the changes made on your branch and including them on the main trunk, when you feel that the time is ready. First test and tag the code on your branch, e.g.:

    cvs tag my_new_project_1
Then check out a fresh copy of the main trunk, and do:
    cvs update -j my_new_project -j my_new_project_1
then resolve any conflicts, test and check in. Better tag this version as well:
    cvs tag included_my_new_project_1

Note: If you screw up when setting a tag, just do cvs tag -d TAGNAME to remove the bad tag, and then try again. By default, branch tags cannot be deleted unless you give an additional flag to cvs tag -d. Deleting a branch tag by mistake can cause serious problems, so you are adviced to read the CVS manual first.

Getting rid of stickiness

If you have checked out a file with a specific tag (-r TAG) or date (-D DATE), it will remain "sticky" and will not e.g. be automatically refreshed by cvs update even if newer versions have been checked in. To get back to the "head revision" and lose the stickiness, do:
   cvs update -A FILE

Moving or renaming files/directories under CVS

This can be tricky to do right; read the CVS documentation and/or the CVS FAQ thoroughly so you know what you are doing, and don't change anything in the repository (files under $CVSROOT) without first making backups. Better still: ask someone who knows how to do it.

For just renaming a single file, an easy way is to make a copy of the file under the new name, add and check in the new file, then remove the old file (just as above) since it is not used anymore. The drawback of this is that the log of file changes remains with the old file, and the new file is regarded as, well..., a new file.

The easiest way to rename or move a file but keep the CVS log is the following: just make a copy of the *,v file that you find under $CVSROOT, to another name and/or place (remember to keep the ",v" extension on the new file). Then go back to your normal working directory and do cvs update to get the "new" file. Now you can remove the old file just like you remove any other file under cvs, with a message such as "renamed to ...".

If you rename or remove a directory in the repository this can cause havoc if other people still have this directory checked out. If you need to do this, then create a link from the old name to the new inside the repository - but note that this will prevent the lock files that cvs relies on from working - and keep the link there for a short period until everybody has had a chance to migrate to the new name. Also note that renaming/moving directories can make it impossible to check out older versions.

Richard Carlsson /, Kostis Sagonas (modified Feb 2005). Last modified: 13 Feb 07.