Using CVS in the QUAGENTS (Quake Agents) Project
This document describes the use of the Concurrent Version System
(CVS) in the QUAGENTS project.
The percent sign (“%”) in the examples that follow
indicates your shell prompt. You don't type the percent sign.
This information provided without explanation for CVS experts who just
want to get on with it.
- Repository for QUAGENTS :
/p/quake/cvs
cvs -d /p/quake/cvs checkout quake2
If this doesn't make sense to you, please read on!
The following is a very brief overview of CVS. For much more
detail, please see the CVS manual (a.k.a. “Cederqvist”) at
http://www.cvshome.org/docs/manual/.
- CVS relies on a repository to store all the files making
up a project.
- You access the repository to checkout the
files you want to work with into a working directory.
This does not prevent anyone else from also checking out and working
with those files.
- When you want to make your changes available to
others, you commit the changes back to the repository.
- If someone else has made changes that overlap with yours, CVS
indicates a conflict that must be resolved before the
file can be committed.
- To pick up any changes made by others, you update
your working directory.
- Every time a change is committed, CVS makes a new
version of the file. Versions can be given symbolic
names, known as tags.
- CVS supports multiple branches of development on the
same files. Changes on different branches do not affect each other,
until the branches are merged.
There are two ways to access a CVS repository: (1) on a local
filesystem, and (2) via a CVS server (known as “pserver”).
Accessing via the local filesystem is generally faster than via the
server, but means that you can only update that working directory when
it is on a local filesystem (for example, you can't package it up and
install it somewhere else). Accessing via pserver works regardless of
where the working directory is located. For people without access to
the local filesystem (i.e., people outside URCS), pserver access is
the only alternative.
In either case, you only need to specify the repository when you
initially checkout your working directory. After that, information
stored in the working directory (in the "CVS" directory, to be
precise) allows CVS to find the repository.
- To specify a local filesystem repository, give the pathname of the
repository as the -d argument of the cvs command, as
in:
cvs -d pathname checkout ...
- To specify a remote (pserver) repository, you give something that
looks like a URL but isn't as the -d argument, as in:
cvs -d :pserver:host/pathname checkout ...
Note the leading colon in “:pserver:”.
The CVS repository for QUAGENTS is:
/p/quake/cvs
There is currently no pserver access to the QUAGENTS cvs tree.
CVS supports the notion of “modules”--
a set of files and directories that get checked out together. We use
these modules to provide convenient ways to checkout various subsets
of the QUAGENTS source code for specific purposes. Note that this use of
the term “module” in CVS is not the same as what we
mean by a “QUAGENTS module”.
- To checkout the entire source tree into the current directory,
use:
cvs -d respository checkout quake2
- To checkout an individual directory (for example, an individual
QUAGENTS component or library):
cvs -d repository quake2/component
This will checkout into a directory named
quake2/component below the current directory.
Other CVS modules may be defined. The only way to know for sure is to
checkout the modules list, which is left as an exercise.
Here we walk briefly through the use of the various CVS commands that
are used most frequently.
Checking out a working directory
To start working with QUAGENTS, checkout the source tree. You should
replace repository with one of the forms listed in
the Expert section (either a pathname to a local repository or a
pserver specification for a remote repository).
% mkdir work
% cd work
% cvs -d repository checkout -P quake2
...
% cd quake2
% rm -rf [directories that you don't care about]
The -P option to checkout means to ignore
(“prune”) empty directories, which are otherwise left
behind by CVS when a directory is renamed.
Checking status
When you want to check status of your files with respect to the
repository:
% cvs status
or, less verbosely and much more readably:
% cvs -n -q update
That is, update, but don't actually do it (-n) and don't be
verbose about it (-q). This is so handy that you might want
to make an alias for it.
With no arguments, both of these commands will do the current directory
and, recursively, any sub-directories. Or you can specify specific
files for it to check by given them on the command-line following the
command.
The meanings of the various letters in the output of cvs
update is as follows:
- U
- An updated version of the file is available and will be checked
out if you do an update.
- M
- You have modified your copy of the file but not committed the
changes.
- C
- You have modified your copy of the file, and there is a
conflict between your changes and the copy currently in the
repository (ie., someone else has checked in conflicting changes).
- A
- The file has been scheduled for addition with cvs add but
the addition has not yet been committed.
- R
- The file has been scheduled for removal with cvs remove
but the removal has not yet been committed.
- ?
- The file is not under CVS control (use cvs add to add
it).
Getting other developer's changes
To put your working directory in sync with the repository:
% cvs update
- Any files changed by others but unchanged by you will be updated
(ie., the new version will be checked out).
- Any files changed by
you and by others that don't conflict will be updated also.
- Any files for which there is a conflict will be reported by CVS,
and your working copy will be marked with
>>>> and <<<< to indicate
the conflicting text. You'll
need to edit them to resolve the conflict before they are useable
(the original file will be there somewhere renamed with a leading
"." if you care to look for it).
- You may want the -d option to update, which
causes CVS to add any directories from the repository to your working
directory if they're not already there. But as the CVS documentation
points out, you may have not checked out or have deleted some
directories on purpose, and update -d will bring them back,
which is probably not what you want. In this case you will need to
checkout the new directories manually (with checkout, or do
update -d and then delete the ones you don't want again.
Throwing away your changes
If you decide that you want to discard any changes to your working
copy of some file (rather than committing them) and just want a fresh
copy of the last checked-in version:
% rm foo.lisp
% cvs update foo.lisp
CVS will warn you that “foo.lisp was lost” and get you a
new copy, which is what you wanted.
Committing your changes
Once you're ready to commit your changes to the repository and make
them available to others (when they update):
% cvs commit -m 'Message for log'
- With no additional arguments, this will commit the current
directory and, recursively, any sub-directories. Alternatively, you
can name specific files and/or directories on the command-line. This
can be useful if you want to record different log messages for
different files.
- If you don't give -m, you will be prompted for a log
message.
- You need to resolve conflicts before CVS will let you commit.
You will be left with an up-to-date tree after committing (ie., no
need for separate update).
Adding and removing files and directories
- To add (place under CVS control) a file:
% cvs add file
- To remove a file (from the current branch):
% cvs remove file
Neither of these operations takes effect until the changes are
committed.
To rename a file, just cvs remove the old name and cvs
add the new one.
To add (place under CVS control) a new directory, use cvs add
as with a file, but note that the change will take immediate effect
(you will see a "CVS" directory in your working copy of the new
directory, and the repository will have a new, empty, directory in it
also).
Removing a directory is not really supported by CVS. See the docs for
more comeplete discussion. The “solution” is to cvs
remove all the files in the diectory, and assume that people use
the -P option to cvs checkout to avoid seeing empty
directories.
Using tags
- A tag is a symbolic name which is associated with a particular version
of a file. Tags usually identify particular points or snapshots in the
development cycle, such as “stable-1” for example.
- You can use a tag name wherever a revision number is allowed, for
example to checkout a specific version of a file. With the tag, you
don't need to remember the specific version number.
- Different files can have different version numbers associated with
a given tag. That is, when you tag a collection of files with a given
name, that name refers to the appropriate version for each file. Or
put yet another way, the tag is not a shorthand for a specific version
number. Rather, it's a way of marking all the tagged files at some
specific revision, without having to remember which version number
that was for each of them. The manual actually does a good job of
explaining this.
- To tag the current directory and any subdirectories:
% cvs tag name
To tag only specific files or directories, pass them as arguments
following the tagname.
- Note: The one somewhat unintuitive thing about the cvs
tag command is that it operates immediately on the repository
versions of the files in the working directory. That is, suppose you
have checked out version 1.3 of some file. Then you modify it. Now if
you tag the file, it will tag version 1.3. If you mean to tag the
version you are working on, you need to commit the changes first, then
tag the new revision. Use the -c flag if you want to avoid
this.
- To list any tags defined for a file (or files), use the
-v flag to cvs status:
% cvs status -v file
Using branches
- Branches allow multiple versions of a file (or files) to to be
simultaneously in development. Changes made in one branch do not
affect other branches until they are merged.
- To create a branch, you need to tag the appropriate files with the
branch name, passing the -b flag to cvs tag:
% cvs tag -b branchname ...
Don't forget that this tags the repository revision corresponding to
your working copy, not whatever you are working on.
- To put your working copy “on the branch”, specify the
branch tag name with the -r argument to either cvs
checkout (for a new working copy) or cvs update (for an
existing working directory):
% cvs checkout -r branchname ...
or
% cvs update -r branchname ...
Now changes committed to those files will only be seen by other
developers who have checked out the branch, but will not affect other
branches including the main trunk.
- Once a working copy is on a branch, cvs status -v will
list it as having a “sticky tag.”
- When you want to make changes on a branch available to the main
trunk developers, you need to “merge” the branch. This
assumes that any desired changes have first been committed on the
branch. You then checkout a fresh copy of the trunk into a new working
directory:
% cvs checkout ...
And then use the -j (for join) flag to cvs update to
merge changes from a given branch (identified by the name of the
branch tag) into the freshly-checked-out trunk copy:
% cvs update -j branchname ...
CVS will identify any conflicts resulting from the merge (i.e., where
a change on the trunk overlaps with a change on the branch). You will
need to resolve conflicts before committing the changes on the trunk:
% cvs commit -m 'Merged branchname' ...
- After a merge, the branch continues to exist and can support
ongoing development independently of other branches (and the trunk).
If you want to merge again, to incorporate further changes from the
branch into the trunk, you need to use the -j flag twice in
the cvs update command. The manual has some suggestions on
how to use tags to make this easier.
Dave Costello
Last change: 15 Dec 2003