# CVS Minimal Help

## David L. Levine

Last modified Monday, 30-Sep-2002 11:15:16 CDT.

##

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!

Contents:

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:

- Repository: The master store of all versions of all controlled files.

- Workspace: A user's collection of controlled files. The user may modify these files at will.

- Check out: Retrieve one or more files from the repository, and place them in a workspace. Any version of any file may be retrieved; typically, that will be the latest version.

- Check in, or commit: Update the latest version of one or more files in the repository. This is done from a workspace.

- Module: Directory.

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:

             d:\utilities\cvs;D:\utilities\gnuwin32\b18\H-i386-cygwin32\bin

4. Add to your environment:
   `LOGNAME =` username
   `CVSROOT = ace.cs.wustl.edu:/project/cvs-repository`

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:

- `U` the file was brought up-to-date, so now it agrees with what is in the repository
- `P` same as `U`, except used by CVS server when it sends a patch instead of the entire file
- `M` the file is modified in your workspace with respect to the repository; without any other message, it means that the file was not modified by this update operation. If changes were successfully merged (without conflict), then cvs will note on the previous lines.
- `C` the file needs to be updated, but a conflict was detected. The file now contains the differences, demarcated with `<<<<<<<` and `>>>>>>>`. The unmodified file was moved to .#file.revision. You'll need to edit the file to resolve the differences. I get a lot of false positives on files that I know I didn't modify locally: for those cases, I just remove the file and rerun update.
- `A` or `R` The file has been added or removed to/from your workspace, but the add or remove has not yet been committed.
- `?` the file is private to your workspace: it does not exist in the repository

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 <jxh@cs.wustl.edu> 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 "cs.wustl.edu")

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:

- The easiest way to abandon your changes in your workspace is to use the emacs command `C-x v u` (vc-revert-buffer). Or from the shell, you could remove the file and update it with `cvs update file`.

- Do not remove a revision from the cvs repository directly. To revert a revision that you made, use the following command to revert the change in your workspace and check in the reverted version:

          % cvs update -jafter_change -jbefore_change file

  For example, if the version containing the version you want to revert is 4.10, then, after_change should be `4.10` and before_change should be `4.9`.

  NOTE: this doesn't seem to work with CVS version 1.10.

  Make sure the patch succeeded (if you are not reverting a change you made long time ago, most likely it will succeed) before checking in the reverted version.

  Also make sure the you add a ChangeLog entry explaining why you reverted the change.

### 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:

        % cd $CVSROOT/MODULE
        % 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:

        Add ChangeLog entry containing:
        merged main trunk changes
        % cvs update -jHEAD file(s)/directori(es)
        % cvs commit -m "ChangeLogTag: `head -1 ChangeLog`" file(s)/directori(es) ChangeLog
        % cvs tag merged_foo_branch file(s)/directori(es)

AFTER MERGING, APPLY A LABEL TO THE SOURCE BRANCH, as shown above. For example, if you merged from the main trunk to a branch, apply a new label to the main trunk. 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:

        Add ChangeLog entry containing:
        merged main trunk changes
        % cvs update -jmerged_foo_branch -jHEAD file(s)/directori(es)
        % cvs commit -m "ChangeLogTag: `head -1 ChangeLog`" file(s)/directori(es) ChangeLog
        % cvs tag merged_foo_branch_again file(s)/directori(es)

Note that any files created on the branch won't be visible on the main trunk, even after the merge. I'm not sure of right way to take care of this, but I follow these steps for each file created on the branch:

1. In the repository, move the RCS file from the Attic directory up to its parent directory.
2. Edit the RCS file, replacing the "dead" state with "Exp".
3. Merge from the branch to the main trunk:

             Add ChangeLog entry containing:
             merged branch_tag
             % cvs update -Aj branch_tag file
             % cvs commit -m "ChangeLogTag: `head -1 ChangeLog`" file ChangeLog

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 `-d` option to `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:

            :pserver:your_user_id@ace.cs.wustl.edu:/project/cvs-repository

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++ 2.7.2.1 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:

- David Discher's Quick N Dirty CVS HOW-TO is really helpful.

- Please check out David G. Grubbs' great, comprehensive "The CVS FAQ".

- CVS Bubbles is a collection of useful CVS information and links.

- Commercial support for CVS is available from SourceGear Corporation. Their web pages are very helpful.

- Terris Linenbach has an interesting, brief discussion of source code management on-line at Programmers' Canvas. Programmers' Canvas is a pattern language, also quite interesting.

Back to David L. Levine's home page.

Last modified 11:15:16 CDT 30 September 2002.
[an error occurred while processing this directive] [an error occurred while processing this directive]