CVS Minimal Help

David L. Levine

Last modified .


This page contains the minimum (and then some) commands necessary to access and update ACE through CVS version control. The intended audience is local ACE developers, so it's not by any means a general introduction to CVS. And some HTML links and other references are local only.

The information here is based on CVS versions 1.9 and 1.10.5 and later.

Notes to emacs users: the emacs Tools/Version Control (or vc) pulldown has CVS commands: it's well worth checking out. And, see the Preliminaries section for a handy addition to your .emacs file.

If you'd like to update your CVS workspace remotely, see Nanbor Wang's   CVSup  page.

Please email me any corrections or suggestions!


  1. The Model
  2. Preliminaries
  3. Getting started with ACE on CVS
  4. Windows NT setup
  5. Checking in changes
  6. Workspace update
  7. Adding/removing files/directories
  8. Modules
  9. ChangeLog updates
  10. File revisions
  11. File reversion
  12. Renaming a file
  13. Local version control
  14. Branches
  15. Remote repositories
  16. Exporting from CVS
  17. ACE_wrappers-frozen workspace
  18. ACE release bug-fix branch
  19. Warning messages/problems
  20. For more info on CVS

1. The Model

The following terms are used in the discussion in this web page:
Our use of CVS fits into the ACE development process.

2. Preliminaries

The CVSROOT environment variable listed below is required. If you want to use CVS from within emacs, you'll have to restart it from a shell that has CVSROOT defined.

Emacs users might want to add (setq vc-follow-symlinks t) to your .emacs file to instruct emacs to follow symlinks to version-controlled plain files.

For lack of a better place to put the following, I'll put it here. It's a good idea to insert a CVS/RCS keyword string at the top of every file that you place under CVS control. This includes source files, Makefiles, config files, etc. It will embed in the file a concise record of the filename, last update time, revision number, and last user who updated it. For C++ files, the keyword string is:

  // $Id$
It's not necessary to fill in the fields of the keyword string, or modify them when you edit a file that already has one. CVS does that automatically when you checkout or update the file.

On Unix systems, you might want to create a file called .cvsrc in your home directory with the following contents:

co -P
update -P
That will cause CVS to prune empty directories on checkout or update.

3. Getting started with ACE on CVS

Note: the first three steps are for UNIX platforms. See the Windows NT setup section for setup information for Windows NT.
  1. % setenv CVSROOT /project/cvs-repository #### site-specific location

  2. cd to the directory that you want your ACE_wrappers workspace to be under.

  3. % setenv ACE_ROOT `pwd` #### to set the ACE_ROOT environment

  4. Change your umask to something like 022 if you want others to be able to view your workspace.

  5. % cvs checkout ACE_wrappers

  6. Add the ace/config.h and include/makeinclude/platform_macros.GNU symlinks. For example, for Sun C++ on SunOS 5.5:
          % ln -s config-sunos5.5.h ace/config.h
          % ln -s platform_sunos5_sunc++.GNU include/makeinclude/platform_macros.GNU

  7. Hack away in your own workspace. All files have user write permission.

4. Windows NT setup

Thanks to Darrell Brunsch and Irfan Pyarali for providing this NT setup information. (It contains a site-specific CVSROOT.)

You can use the CVS client under Windows NT to keep a local repository of ACE. To set it up, follow these steps:

  1. Find or create a directory in your path (I just created a utils directory and added it to my path).

  2. Download the files cvs.exe, patch.exe, and win32gnu.dll. They're in a zip file on Cyclic Software's download site. (Cyclic Software hsa been acquired by SourceGear Corporation.)

    Alternatively, WinCVS provides a graphical front-end on Windows. NOTE: if you use WinCVS, beware that it enables read-only checkout by default. So be sure not to check out that way if you want to edit files.

    Thanks to Steve Huston for that note.

  3. Be sure that the SourceGear cvs utilities precede any Cygnus GNU-Win32 utilities in your path, something like this:

  4. Add to your environment:
    LOGNAME = username
Please note that this approach uses a remote shell. So, your account must be able to rsh to the server machine.

For an alternative approach that uses CVS pserver instead of rsh, please see Darrell's CVS pserver page for Win32.

5. Checking in changes

By convention, any repository change should be documented in an appropriate ChangeLog. The ChangeLog entry should start with a line of this form:
  ChangeLogTag: date  name  <email address>

In all examples below, ChangeLog refers to appropriate ChangeLog.

5.1. Command line

To enter your workspace changes into the master repository from the command line::

    % cvs commit -m "ChangeLogTag: `head -1 ChangeLog`" file(s)/directori(es) ChangeLog

5.2. From emacs

To checkin one file or directory to the repository:

  1. C-x v v (vc-next-action) to check the file or directory in

  2. Insert the ChangeLogTag, using the first line of your ChangeLog entry

  3. C-c C-c to finish checkin

6. Workspace update

To update your workspace from the master repository, to pick up changes by others:

% cvs update ACE_wrappers

cvs will print out a line for each directory that it enters (by default, it will recurse through the directory tree; to disable this and only update one directory, add -l after update).

cvs will print out a line for each file that differs from what is in the repository. This first character indicates the file status:

To show what update would do to the currently directory (recursively), without actually doing it:
% cvs -n update .
The -q option to update suppresses the ``Updating'' message for each directory:
% cvs -nq update .
To get the status of the current directory (recursively) with respect to the repository:
% cvs status .
To get the status of a single file with respect to the repository, with symbolic tags displayed:
% cvs status -v file
To show local (in current workspace) changes to one or more files, relative to the versions that they were checked out from:
% cvs diff file(s)/directori(es)
To show local (in current workspace) changes to one or more files, relative to the latest versions in the repository:
% cvs diff -rHEAD file(s)/directori(es)

7. Adding/removing files/directories

Adding one or more text files requires two steps:
    % cvs add file . . .
    % cvs commit file . . .

The commit may be done later, on the entire directory, etc. Note that cvs add is not recursive, so that the files in each directory of a hierarchy must be added in separate commands. Also, only files in the current directory can be added.

Binary files require the -kb option to cvs add:

    % cvs add -kb file . . .
    % cvs commit file . . .

If not applied during the add operation, -kb can be applied using cvs admin -kb.

Removing files is similar, except the cvs remove command is used instead of the add command:

    % cvs remove file . . .
    % cvs commit file . . .

An add of an empty directory doesn't require a commit.

Removing a directory is more problematic. There is no CVS command to remove (or rename) a directory: it has to be done behind CVS' back, directly in the repository. This is by design; a CVS command can't be used to irrevocably destroy information. Therefore, never remove a directory. You can safely remove all of the files in it, using the above steps. To just remove a directory from a workspace (without removing it from the repository): first, remove the directory and all of its files using usual OS commands. Second, run

    % cvs update -P directory-path 

to prune the directory from the workspace.

8. Modules

Instead of referring to ``ACE_wrappers'' above, you can refer to a module, such as ace, tests, performance-tests, and so on. To get a list of known modules, use the -c option to checkout:
% cvs checkout -c

IMPORTANT: if a subdirectory is added to ACE, it must be added to the list of known modules in $CVSROOT/CVSROOT/modules! If you don't want to edit that file, please tell David. The CVSROOT files are under RCS control. emacs' VC tools handle them the same way that they handle CVS-controlled files. So, you can check them out and back in with C-x v v.

To add an entirely new module:

  1. Create the directories/files.

  2. Add the module to $CVSROOT/CVSROOT/modules, as mentioned above.

  3. Create a new directory in $CVSROOT, owned by the appropriate group and with sufficient (probably group write+setuid) permissions.

  4. Change to the directory just above the top-level directory for the module in your workspace.

  5. cvs checkout new module name

  6. Add all of the new directories/files in the module, as described above, then commit.

9. ChangeLog updates

To automatically update the ChangeLog, use the emacs command:
  C-u C-x v a
Thanks to James Hu <> for this useful tidbit.

To set a specific host address in your ChangeLog entries, add a line like this to your ~/.emacs:

  (setq mail-host-address "")

To set a specific name in your ChangeLog entries, add a line like this to your ~/.emacs:

  (setq user-full-name "my full name")
Otherwise, CVS uses the name (GECOS field) from your passwd entry.

10. File revisions

File revisions in and below the current directory may be tagged with:
    % cvs tag tag .

To retrieve an old revision of a file, use the -r option to cvs update:

    % cvs update -rtag file
The revision tags of a file can be viewed with the cvs log command.

Or, to retrieve the file and/or directory versions as of a certain date and time, use the -D option to cvs update, for example:

    % cvs update -D "last Saturday" OS.{h,i,cpp}
NOTE: The -r and -D options are ``sticky''; they will apply to the file(s)/directories until overwritten with another revision tag or date, or until disabled. They are disabled by using the update -A option, which also checks out the latest revision:
    % cvs update -A file

To change the log message for a particular revision of a file:

    % cvs admin -mrevision:"new message" file

11. File reversion

There are a few ways to revert a file to the last revision that is in the repository, if you want to abandon your changes to it:

12. Renaming a file

There are three ways to rename a CVS-controlled file. The first preserves the revision log, but it must be accessed by either the original or new name, depending on what you want to see. And revision numbers will start over at 1.0 unless set with the -r option. It's all done in the user's workspace:
    Add ChangeLog entry containing:
    Renamed OLD to NEW
    % mv OLD NEW
    % cvs remove OLD
    % cvs add NEW
    % cvs commit -m "ChangeLogTag: `head -1 ChangeLog`" OLD NEW ChangeLog

The second method maintains the revision log in one place and the revision number sequence. It makes fetching old releases of the module more difficult, which may be an advantage or disadvantage depending on local circumstances. It is more dangerous because the repository is modified directly; see the warning in the cvs info page about other users accessing the history file while it is being moved:
    % mv OLD,v NEW,v

The third method is to copy the history file in the repository. Instead of moving the history file, as in the second method above, copy it. It's not necessary to prevent others from accessing the file. The cvs info pages show other steps, to remove the old tags from the new history file. While technically correct, I don't think that's necessary for our purposes.

While the first method is the safest, it has the distinct disadvantage of hindering access of old versions. If that's not a problem for a particular file, then it is the preferred approach. As Carlos would probably say if you asked him, ``it's the right thing to do.''

If easy access to old versions is desired, I would use the third approach: copy the history file in the repository.

13. Local version control

All version control with CVS is done through the master repository. CVS doesn't provide any facility for local checkpoints. If you want local version control in your workspace, there's nothing to stop you from using RCS or SCCS locally (but it might confuse emacs' version control). The preferred approach is to create a branch, and checkpoint as much as you want on that branch. When the time comes to make the changes public, just merge the branch. See the Branches section of this page, and the cvs man page, for instructions on creating and using a branch.

14. Branches

To create a branch, you must first create a tag to identify the branch. Then, you can checkout on that branch. There are various ways to go about doing this, but these steps show how when starting from scratch:
    % cvs rtag -b branch_tag module(s)
    % cvs checkout -r branch_tag module(s)
It's not necessary to checkout all the files in a directory or module on the branch, but it's probably the easiest and least confusing approach in the long run. Note that it's usually tricky to tag individual files on a branch because CVS won't be able to identify which module they're in. By way of example, to checkout just ace/OS.h on a branch, you'd have to do this, assuming that you're already in the ace directory:
    % cd ..
    % cvs rtag -b branch_tag ace/OS.h
    % cvs checkout -r branch_tag ace/OS.h
    % cd ace
This can be done after modifying files, and CVS will retain your modifications. However, if you don't trust CVS, it's best to backup your files first.

Checkouts on a branch are sticky, and will apply until the head version of the file(s) have been checked out with the -A option to cvs update. Presumably, this will be done after merging the branch to the main trunk. See the Old file revisions section of this page for similar discussion of sticky tags.

To merge an entire branch to the main trunk, use the -j (for join) option to cvs checkout. That just merges in your workspace; the repository can then be updated from the workspace using commit as usual:

    Add ChangeLog entry containing:
    merged branch_tag
    % cvs checkout -P -Aj branch_tag file(s)/directori(es)
    % cvs commit -m "ChangeLogTag: `head -1 ChangeLog`" file(s)/directori(es) ChangeLog
(The -A is needed if you are in the workspace that has the checkouts on the branch. It updates the workspace to the latest versions on the main trunk. So, don't use it if you want to keep working on the branch.)

To merge any changes on the main trunk to a branch, the first time:

    % cvs update -jHEAD file(s)/directori(es)
    % cvs commit -m 'Merged mainline changes to branch, first time.' file(s)/directori(es)
After that first merge, always APPLY A LABEL TO THE SOURCE BRANCH:
    % cvs rtag merged_to_foo_branch_1 module
This can also be done using cvs tag instead of rtag, but then you'd need to checkout a workspace on the source branch.

And apply a label to the source branch just before merging again. For example, if you merged from the main trunk to a branch, apply a new label to the main trunk, e.g.,

    % cvs rtag merged_to_foo_branch_2 module
You can use that label later to merge any subsequent changes on the main trunk. The cvs info pages have a good example of this. Briefly:
    % cvs update -jmerged_to_foo_branch_1 -jmerged_to_foo_branch_2 file(s)/directori(es)
    % cvs commit -m 'Merged mainline changes to branch, second time.' file(s)/directori(es)
Note that any files created on a branch won't be visible on the main trunk, even after a merge. Use cvs checkout to check them out on the main trunk.

To create a file on a branch, in a directory that has not been checked out on the branch:

  1. Add the file and commit it to the main branch
  2. Create the branch tag on the file, and check the file out on the branch.
  3. Remove the file, cvs remove the file, and commit the removal.
  4. Check the file out on the branch.
Alternatively, the recommended procedure is to simply check the entire directory out on the branch, then create the file.

In general, deleting branch tags is not recommended. But it's often necessary, especially when getting started with branches. The -dB options to cvs tag and cvs rtag can be used to delete a branch tag.

The use of a branch for maintaining a release is illustrated in the section on the ACE release bug-fix branch.

15. Remote repositories

Before setting up a repository for remote access, be sure to see the CVS documentation. There are important security considerations.

An easy way to access a remote repository is via rsh. These steps ought to get you going:

  1. Install cvs on the local system, if it doesn't already have it.

  2. Add yourself to an .rhosts file on the remote machine of a user that can access the repository.

  3. Set your CVSROOT environment variable to:
              remote user@remote host:remote repository
Then, you can issue cvs commands just as you would on the remote machine.

If you have ssh on your client machine, you can use ssh instead of rsh. Just set your CVS_RSH environment variable to ssh. You don't need to add an .rhosts entry with ssh, so it's the best alternative for remote repository access.

Another way to access to remote cvs repository is to run cvs in client-server mode. To use this feature, first check if you have your HOME environment variable set properly. Then, set your CVSROOT to:

Then, do a cvs login as

    % cvs login

Type in your password when CVS prompts you to enter your password. This will create a file call ".cvspass" in your home directory (as defined by $HOME) that contains the encripted password for the server. You can now perform regular CVS operation directly.

Notice: It's not difficult to decode the passwords in .cvspass file. Therefore, never use cvs in client-server mode in a unsafe environment. (Where others can read your .cvspass file.)

To speed up client-server mode operations, it might help to use the cvs -z option. It requires that gzip be on your search path on both the client and server. An example use is:

    % cvs -z 1 update

Thanks to Nanbor Wang and Darrell Brunsch for figuring out and providing this documentation for cvs client-server mode.

16. Exporting from CVS

There are two different strategies for exporting CVS-controlled files, such as for code releases. The first, preferred approach is to use the cvs export command to stage a version of the controlled files to a non-controlled directory. This version will not have any of the CVS files in it. THe second approach is to create a release from a user's CVS-controlled workspace.

To use cvs export, either a date or revision tag must be specified. It's usually a good idea to tag the sources with a revision tag and use that. So, the steps would be:

    % cd root of directory tree
    % cvs tag tag .
    % cd staging directory
    % cvs export -r tag
    % find . -print | cpio -o -H tar | gzip -9 > tar filename
To tag and create a release in the form of a gzip'ped tar file from a user's workspace:
    % cd root of directory tree
    % cvs tag tag .
    % find . -name CVS -prune -o -print | cpio -o -H tar | gzip -9 > tar filename
The relative advantage of the first, export approach is that you will be sure that only CVS-controlled files will be released. However, it requires the extra step and creation of the staging area.

This extra step is one reason why we don't currently stage releases of ACE. Instead, they are built from Doug's personal workspace. That workspace is visible on the web, so that ACE users can track the very latest changes without any explicit action by Doug. If we were to stage it, to make any change visible would require an explicit move to the staging area.

17. ACE_wrappers-frozen workspace

This section applies to the DOC group at Wash. U. only:

There's now a ``frozen'' ACE in /project/cvs-repository/ACE_wrappers-frozen/. It contains the latest official release of ACE.

There are complete g++ and Sun C++ 4.2 builds in the build directory below the directory noted above. To use one of these builds, set or prepend to these environment variables:

Compiler set WRAPPER_ROOT to: prepend to LD_LIBRARY_PATH:
g++ /project/cvs-repository/ACE_wrappers-frozen/build/SunOS5_g++ /project/cvs-repository/ACE_wrappers-frozen/build/SunOS5_g++/ace
Sun C++ /project/cvs-repository/ACE_wrappers-frozen/build/SunOS5_sunc++-4.2 /project/cvs-repository/ACE_wrappers-frozen/build/SunOS5_sunc++-4.2/ace

18. ACE release bug-fix branch

This section applies to the DOC group at Wash. U. only:

The ``main line'' CVS branch will (continue to) be the ``new features'' branch. If you want the very latest and greatest ACE at all times, no changes to the use of your workspace are required. Just cvs update it as usual.

Bug fixes to the official release will go on a branch. For the ACE 4.2 release, for example, this branch is name ACE-4_2. (CVS does not allow periods in branch names or any other tags.) To use it, do this in your workspace:

    % cd ..
    % cvs checkout -r ACE-4_2 ACE_wrappers
From that point on, all updates and commits in that workspace will be from/to the ACE-4_2 branch.

19. Warning messages/problems

cvs update: conflict: foo is modified but no longer in the repository
U bar
That might indicate that file foo was renamed to bar. If so, foo should be removed from the current workspace. (And that warning will not reoccur for the workspace, because its CVS will have removed foo from the workspace entries and checked out bar.)

cvs update: [time] waiting for user's lock in repository
Check for lock files and directories in the $CVSROOT/CVSROOT and lock files anywhere in the $CVSROOT hierarchy. Remove ones that no longer appear to be in use and retry. Lock files and directories have names starting with ``.#'', I think.

Why does a file in the repository not have group and/or other read permission?

Because it didn't have those permissions when it was added to the repository. To fix it, those permissions can be added to the ,v file in the repository. To avoid it, those permissions should be added to the file before it is created/committed the first time.

Why does CVS keep removing group/and or other read permission from a file in my workspace?

Because your umask is something like 7 or 77. Change it to something like 22. If you don't want to change it for everything, then alias cvs; in t/csh:
% alias cvs '(umask 22; \cvs \!*)'

Also, the file will have to have mode 644 before you commit it. So if your editor removes group/other read permission, you'll have to ``fix'' that as well.

I modified Makefile in my workspace so I don't build static or shared ACE libraries. But, I forgot about it and commited the modified Makefile to the repository. Help?

You'll have to correct the Makefile and commit your corrections.

Instead of modifying your makefile, try these commands to build the ACE static and shared libraries, respectively:

% make static_libs_only=1
% make shared_libs_only=1

20. For more info on CVS

Please see these sources for more information on CVS: