Magic branch numbers
====================

   This section describes a CVS feature called "magic branches".  For
most purposes, you need not worry about magic branches; CVS handles
them for you.  However, they are visible to you in certain
circumstances, so it may be useful to have some idea of how it works.

   Externally, branch numbers consist of an odd number of dot-separated
decimal integers.  See Revision numbers.  That is not the whole
truth, however.  For efficiency reasons CVS sometimes inserts an extra 0
in the second rightmost position (1.2.4 becomes 1.2.0.4, 8.9.10.11.12
becomes 8.9.10.11.0.12 and so on).

   CVS does a pretty good job at hiding these so called magic branches,
but in a few places the hiding is incomplete:

   * The magic branch number appears in the output from `cvs log'.

   * You cannot specify a symbolic branch name to `cvs admin'.

   You can use the `admin' command to reassign a symbolic name to a
branch the way RCS expects it to be.  If `R4patches' is assigned to the
branch 1.4.2 (magic branch number 1.4.0.2) in file `numbers.c' you can
do this:

     $ cvs admin -NR4patches:1.4.2 numbers.c

   It only works if at least one revision is already committed on the
branch.  Be very careful so that you do not assign the tag to the wrong
number.  (There is no way to see how the tag was assigned yesterday).

Merging an entire branch
========================

   You can merge changes made on a branch into your working copy by
giving the `-j BRANCHNAME' flag to the `update' subcommand.  With one
`-j BRANCHNAME' option it merges the changes made between the greatest
common ancestor (GCA) of the branch and the destination revision (in
the simple case below the GCA is the point where the branch forked) and
the newest revision on that branch into your working copy.

   The `-j' stands for "join".

   Consider this revision tree:

     +-----+    +-----+    +-----+    +-----+
     ! 1.1 !----! 1.2 !----! 1.3 !----! 1.4 !      <- The main trunk
     +-----+    +-----+    +-----+    +-----+
                     !
                     !
                     !   +---------+    +---------+
     Branch R1fix -> +---! 1.2.2.1 !----! 1.2.2.2 !
                         +---------+    +---------+

The branch 1.2.2 has been given the tag (symbolic name) `R1fix'.  The
following example assumes that the module `mod' contains only one file,
`m.c'.

     $ cvs checkout mod               # Retrieve the latest revision, 1.4

     $ cvs update -j R1fix m.c        # Merge all changes made on the branch,
                                      # i.e. the changes between revision 1.2
                                      # and 1.2.2.2, into your working copy
                                      # of the file.

     $ cvs commit -m "Included R1fix" # Create revision 1.5.

   A conflict can result from a merge operation.  If that happens, you
should resolve it before committing the new revision.  See Conflicts example.

   If your source files contain keywords (see Keyword substitution),
you might be getting more conflicts than strictly necessary.  See
Merging and keywords, for information on how to avoid this.

   The `checkout' command also supports the `-j BRANCHNAME' flag.  The
same effect as above could be achieved with this:

     $ cvs checkout -j R1fix mod
     $ cvs commit -m "Included R1fix"

   It should be noted that `update -j TAGNAME' will also work but may
not produce the desired result.  See Merging adds and removals, for
more.

Merging from a branch several times
===================================

   Continuing our example, the revision tree now looks like this:

     +-----+    +-----+    +-----+    +-----+    +-----+
     ! 1.1 !----! 1.2 !----! 1.3 !----! 1.4 !----! 1.5 !   <- The main trunk
     +-----+    +-----+    +-----+    +-----+    +-----+
                     !                           *
                     !                          *
                     !   +---------+    +---------+
     Branch R1fix -> +---! 1.2.2.1 !----! 1.2.2.2 !
                         +---------+    +---------+

where the starred line represents the merge from the `R1fix' branch to
the main trunk, as just discussed.

   Now suppose that development continues on the `R1fix' branch:

     +-----+    +-----+    +-----+    +-----+    +-----+
     ! 1.1 !----! 1.2 !----! 1.3 !----! 1.4 !----! 1.5 !   <- The main trunk
     +-----+    +-----+    +-----+    +-----+    +-----+
                     !                           *
                     !                          *
                     !   +---------+    +---------+    +---------+
     Branch R1fix -> +---! 1.2.2.1 !----! 1.2.2.2 !----! 1.2.2.3 !
                         +---------+    +---------+    +---------+

and then you want to merge those new changes onto the main trunk.  If
you just use the `cvs update -j R1fix m.c' command again, CVS will
attempt to merge again the changes which you have already merged, which
can have undesirable side effects.

   So instead you need to specify that you only want to merge the
changes on the branch which have not yet been merged into the trunk.
To do that you specify two `-j' options, and CVS merges the changes from
the first revision to the second revision.  For example, in this case
the simplest way would be

     cvs update -j 1.2.2.2 -j R1fix m.c    # Merge changes from 1.2.2.2 to the
                                           # head of the R1fix branch

   The problem with this is that you need to specify the 1.2.2.2
revision manually.  A slightly better approach might be to use the date
the last merge was done:

     cvs update -j R1fix:yesterday -j R1fix m.c

   Better yet, tag the R1fix branch after every merge into the trunk,
and then use that tag for subsequent merges:

     cvs update -j merged_from_R1fix_to_trunk -j R1fix m.c

Merging differences between any two revisions
=============================================

   With two `-j REVISION' flags, the `update' (and `checkout') command
can merge the differences between any two revisions into your working
file.

     $ cvs update -j 1.5 -j 1.3 backend.c

will undo all changes made between revision 1.3 and 1.5.  Note the
order of the revisions!

   If you try to use this option when operating on multiple files,
remember that the numeric revisions will probably be very different
between the various files.  You almost always use symbolic tags rather
than revision numbers when operating on multiple files.

   Specifying two `-j' options can also undo file removals or
additions.  For example, suppose you have a file named `file1' which
existed as revision 1.1, and you then removed it (thus adding a dead
revision 1.2).  Now suppose you want to add it again, with the same
contents it had previously.  Here is how to do it:

     $ cvs update -j 1.2 -j 1.1 file1
     U file1
     $ cvs commit -m test
     Checking in file1;
     /tmp/cvs-sanity/cvsroot/first-dir/file1,v  <--  file1
     new revision: 1.3; previous revision: 1.2
     done
     $

Merging can add or remove files
===============================

   If the changes which you are merging involve removing or adding some
files, `update -j' will reflect such additions or removals.

   For example:
     cvs update -A
     touch a b c
     cvs add a b c ; cvs ci -m "added" a b c
     cvs tag -b branchtag
     cvs update -r branchtag
     touch d ; cvs add d
     rm a ; cvs rm a
     cvs ci -m "added d, removed a"
     cvs update -A
     cvs update -jbranchtag

   After these commands are executed and a `cvs commit' is done, file
`a' will be removed and file `d' added in the main branch.

   Note that using a single static tag (`-j TAGNAME') rather than a
dynamic tag (`-j BRANCHNAME') to merge changes from a branch will
usually not remove files which were removed on the branch since CVS
does not automatically add static tags to dead revisions.  The
exception to this rule occurs when a static tag has been attached to a
dead revision manually.  Use the branch tag to merge all changes from
the branch or use two static tags as merge endpoints to be sure that
all intended changes are propagated in the merge.

Merging and keywords
====================

   If you merge files containing keywords (see Keyword substitution),
you will normally get numerous conflicts during the
merge, because the keywords are expanded differently in the revisions
which you are merging.

   Therefore, you will often want to specify the `-kk' (see
Substitution modes) switch to the merge command line.  By
substituting just the name of the keyword, not the expanded value of
that keyword, this option ensures that the revisions which you are
merging will be the same as each other, and avoid spurious conflicts.

   For example, suppose you have a file like this:

            +---------+
           _! 1.1.2.1 !   <-  br1
          / +---------+
         /
        /
     +-----+    +-----+
     ! 1.1 !----! 1.2 !
     +-----+    +-----+

and your working directory is currently on the trunk (revision 1.2).
Then you might get the following results from a merge:

     $ cat file1
     key $Revision: 1.2 $
     . . .
     $ cvs update -j br1
     U file1
     RCS file: /cvsroot/first-dir/file1,v
     retrieving revision 1.1
     retrieving revision 1.1.2.1
     Merging differences between 1.1 and 1.1.2.1 into file1
     rcsmerge: warning: conflicts during merge
     $ cat file1
     <<<<<<< file1
     key $Revision: 1.2 $
     =======
     key $Revision: 1.1.2.1 $
     >>>>>>> 1.1.2.1
     . . .

   What happened was that the merge tried to merge the differences
between 1.1 and 1.1.2.1 into your working directory.  So, since the
keyword changed from `Revision: 1.1' to `Revision: 1.1.2.1', CVS tried
to merge that change into your working directory, which conflicted with
the fact that your working directory had contained `Revision: 1.2'.

   Here is what happens if you had used `-kk':

     $ cat file1
     key $Revision: 1.2 $
     . . .
     $ cvs update -kk -j br1
     U file1
     RCS file: /cvsroot/first-dir/file1,v
     retrieving revision 1.1
     retrieving revision 1.1.2.1
     Merging differences between 1.1 and 1.1.2.1 into file1
     $ cat file1
     key $Revision$
     . . .

   What is going on here is that revision 1.1 and 1.1.2.1 both expand
as plain `Revision', and therefore merging the changes between them
into the working directory need not change anything.  Therefore, there
is no conflict.

   *WARNING: In versions of CVS prior to 1.12.2, there was a major
problem with using `-kk' on merges.  Namely, `-kk' overrode any default
keyword expansion mode set in the archive file in the repository.  This
could, unfortunately for some users, cause data corruption in binary
files (with a default keyword expansion mode set to `-kb').  Therefore,
when a repository contained binary files, conflicts had to be dealt
with manually rather than using `-kk' in a merge command.*

   In CVS version 1.12.2 and later, the keyword expansion mode provided
on the command line to any CVS command no longer overrides the `-kb'
keyword expansion mode setting for binary files, though it will still
override other default keyword expansion modes.  You can now safely
merge using `-kk' to avoid spurious conflicts on lines containing RCS
keywords, even when your repository contains binary files.

Recursive behavior
******************

   Almost all of the subcommands of CVS work recursively when you
specify a directory as an argument.  For instance, consider this
directory structure:

           `$HOME'
             |
             +--tc
             |   |
                 +--CVS
                 |      (internal CVS files)
                 +--Makefile
                 +--backend.c
                 +--driver.c
                 +--frontend.c
                 +--parser.c
                 +--man
                 |    |
                 |    +--CVS
                 |    |  (internal CVS files)
                 |    +--tc.1
                 |
                 +--testing
                      |
                      +--CVS
                      |  (internal CVS files)
                      +--testpgm.t
                      +--test2.t

If `tc' is the current working directory, the following is true:

   * `cvs update testing' is equivalent to

          cvs update testing/testpgm.t testing/test2.t

   * `cvs update testing man' updates all files in the subdirectories

   * `cvs update .' or just `cvs update' updates all files in the `tc'
     directory

   If no arguments are given to `update' it will update all files in
the current working directory and all its subdirectories.  In other
words, `.' is a default argument to `update'.  This is also true for
most of the CVS subcommands, not only the `update' command.

   The recursive behavior of the CVS subcommands can be turned off with
the `-l' option.  Conversely, the `-R' option can be used to force
recursion if `-l' is specified in `~/.cvsrc' (see ~/.cvsrc).

     $ cvs update -l         # Don't update files in subdirectories

Adding, removing, and renaming files and directories
****************************************************

   In the course of a project, one will often add new files.  Likewise
with removing or renaming, or with directories.  The general concept to
keep in mind in all these cases is that instead of making an
irreversible change you want CVS to record the fact that a change has
taken place, just as with modifying an existing file.  The exact
mechanisms to do this in CVS vary depending on the situation.

Adding files to a directory
===========================

   To add a new file to a directory, follow these steps.

   * You must have a working copy of the directory.  See Getting the source.

   * Create the new file inside your working copy of the directory.

   * Use `cvs add FILENAME' to tell CVS that you want to version
     control the file.  If the file contains binary data, specify `-kb'
     (see Binary files).

   * Use `cvs commit FILENAME' to actually check in the file into the
     repository.  Other developers cannot see the file until you
     perform this step.

   You can also use the `add' command to add a new directory.

   Unlike most other commands, the `add' command is not recursive.  You
have to expcicitly name files and directories that you wish to add to
the repository.  However, each directory will need to be added
separately before you will be able to add new files to those
directories.

     $ mkdir -p foo/bar
     $ cp ~/myfile foo/bar/myfile
     $ cvs add foo foo/bar
     $ cvs add foo/bar/myfile

 - Command: cvs add [`-k' kflag] [`-m' message] files ...
     Schedule FILES to be added to the repository.  The files or
     directories specified with `add' must already exist in the current
     directory.  To add a whole new directory hierarchy to the source
     repository (for example, files received from a third-party
     vendor), use the `import' command instead.  See import.

     The added files are not placed in the source repository until you
     use `commit' to make the change permanent.  Doing an `add' on a
     file that was removed with the `remove' command will undo the
     effect of the `remove', unless a `commit' command intervened.
     See Removing files, for an example.

     The `-k' option specifies the default way that this file will be
     checked out; for more information see Substitution modes.

     The `-m' option specifies a description for the file.  This
     description appears in the history log (if it is enabled, see
     history file).  It will also be saved in the version history
     inside the repository when the file is committed.  The `log'
     command displays this description.  The description can be changed
     using `admin -t'.  See admin.  If you omit the `-m
     DESCRIPTION' flag, an empty string will be used.  You will not be
     prompted for a description.

   For example, the following commands add the file `backend.c' to the
repository:

     $ cvs add backend.c
     $ cvs commit -m "Early version. Not yet compilable." backend.c

   When you add a file it is added only on the branch which you are
working on (see Branching and merging).  You can later merge the
additions to another branch if you want (see Merging adds and removals).

Removing files
==============

   Directories change.  New files are added, and old files disappear.
Still, you want to be able to retrieve an exact copy of old releases.

   Here is what you can do to remove a file, but remain able to
retrieve old revisions:

   * Make sure that you have not made any uncommitted modifications to
     the file.  See Viewing differences, for one way to do that.
     You can also use the `status' or `update' command.  If you remove
     the file without committing your changes, you will of course not
     be able to retrieve the file as it was immediately before you
     deleted it.

   * Remove the file from your working copy of the directory.  You can
     for instance use `rm'.

   * Use `cvs remove FILENAME' to tell CVS that you really want to
     delete the file.

   * Use `cvs commit FILENAME' to actually perform the removal of the
     file from the repository.

   When you commit the removal of the file, CVS records the fact that
the file no longer exists.  It is possible for a file to exist on only
some branches and not on others, or to re-add another file with the same
name later.  CVS will correctly create or not create the file, based on
the `-r' and `-D' options specified to `checkout' or `update'.

 - Command: cvs remove [options] files ...
     Schedule file(s) to be removed from the repository (files which
     have not already been removed from the working directory are not
     processed).  This command does not actually remove the file from
     the repository until you commit the removal.  For a full list of
     options, see Invoking CVS.

   Here is an example of removing several files:

     $ cd test
     $ rm *.c
     $ cvs remove
     cvs remove: Removing .
     cvs remove: scheduling a.c for removal
     cvs remove: scheduling b.c for removal
     cvs remove: use 'cvs commit' to remove these files permanently
     $ cvs ci -m "Removed unneeded files"
     cvs commit: Examining .
     cvs commit: Committing .

   As a convenience you can remove the file and `cvs remove' it in one
step, by specifying the `-f' option.  For example, the above example
could also be done like this:

     $ cd test
     $ cvs remove -f *.c
     cvs remove: scheduling a.c for removal
     cvs remove: scheduling b.c for removal
     cvs remove: use 'cvs commit' to remove these files permanently
     $ cvs ci -m "Removed unneeded files"
     cvs commit: Examining .
     cvs commit: Committing .

   If you execute `remove' for a file, and then change your mind before
you commit, you can undo the `remove' with an `add' command.

     $ ls
     CVS   ja.h  oj.c
     $ rm oj.c
     $ cvs remove oj.c
     cvs remove: scheduling oj.c for removal
     cvs remove: use 'cvs commit' to remove this file permanently
     $ cvs add oj.c
     U oj.c
     cvs add: oj.c, version 1.1.1.1, resurrected

   If you realize your mistake before you run the `remove' command you
can use `update' to resurrect the file:

     $ rm oj.c
     $ cvs update oj.c
     cvs update: warning: oj.c was lost
     U oj.c

   When you remove a file it is removed only on the branch which you
are working on (see Branching and merging).  You can later merge
the removals to another branch if you want (see Merging adds and removals).

Removing directories
====================

   In concept removing directories is somewhat similar to removing
files--you want the directory to not exist in your current working
directories, but you also want to be able to retrieve old releases in
which the directory existed.

   The way that you remove a directory is to remove all the files in
it.  You don't remove the directory itself; there is no way to do that.
Instead you specify the `-P' option to `cvs update' or `cvs checkout',
which will cause CVS to remove empty directories from working
directories.  (Note that `cvs export' always removes empty directories.)
Probably the best way to do this is to always specify `-P'; if you want
an empty directory then put a dummy file (for example `.keepme') in it
to prevent `-P' from removing it.

   Note that `-P' is implied by the `-r' or `-D' options of `checkout'.
This way CVS will be able to correctly create the directory or not
depending on whether the particular version you are checking out
contains any files in that directory.

Moving and renaming files
=========================

   Moving files to a different directory or renaming them is not
difficult, but some of the ways in which this works may be non-obvious.
(Moving or renaming a directory is even harder.  See Moving directories.).

   The examples below assume that the file OLD is renamed to NEW.

The Normal way to Rename
------------------------

   The normal way to move a file is to copy OLD to NEW, and then issue
the normal CVS commands to remove OLD from the repository, and add NEW
to it.

     $ mv OLD NEW
     $ cvs remove OLD
     $ cvs add NEW
     $ cvs commit -m "Renamed OLD to NEW" OLD NEW

   This is the simplest way to move a file, it is not error-prone, and
it preserves the history of what was done.  Note that to access the
history of the file you must specify the old or the new name, depending
on what portion of the history you are accessing.  For example, `cvs
log OLD' will give the log up until the time of the rename.

   When NEW is committed its revision numbers will start again, usually
at 1.1, so if that bothers you, use the `-r TAG' option to commit.  For
more information see Assigning revisions.

Moving the history file
-----------------------

   This method is more dangerous, since it involves moving files inside
the repository.  Read this entire section before trying it out!

     $ cd $CVSROOT/DIR
     $ mv OLD,v NEW,v

Advantages:

   * The log of changes is maintained intact.

   * The revision numbers are not affected.

Disadvantages:

   * Old releases cannot easily be fetched from the repository.  (The
     file will show up as NEW even in revisions from the time before it
     was renamed).

   * There is no log information of when the file was renamed.

   * Nasty things might happen if someone accesses the history file
     while you are moving it.  Make sure no one else runs any of the CVS
     commands while you move it.

Copying the history file
------------------------

   This way also involves direct modifications to the repository.  It
is safe, but not without drawbacks.

     # Copy the RCS file inside the repository
     $ cd $CVSROOT/DIR
     $ cp OLD,v NEW,v
     # Remove the old file
     $ cd ~/DIR
     $ rm OLD
     $ cvs remove OLD
     $ cvs commit OLD
     # Remove all tags from NEW
     $ cvs update NEW
     $ cvs log NEW             # Remember the non-branch tag names
     $ cvs tag -d TAG1 NEW
     $ cvs tag -d TAG2 NEW
     ...

   By removing the tags you will be able to check out old revisions.

Advantages:

   * Checking out old revisions works correctly, as long as you use `-r
     TAG' and not `-D DATE' to retrieve the revisions.

   * The log of changes is maintained intact.

   * The revision numbers are not affected.

Disadvantages:

   * You cannot easily see the history of the file across the rename.

Moving and renaming directories
===============================

   The normal way to rename or move a directory is to rename or move
each file within it as described in Outside.  Then check out
with the `-P' option, as described in Removing directories.

   If you really want to hack the repository to rename or delete a
directory in the repository, you can do it like this:

  1. Inform everyone who has a checked out copy of the directory that
     the directory will be renamed.  They should commit all their
     changes, and remove their working copies, before you take the
     steps below.

  2. Rename the directory inside the repository.

          $ cd $CVSROOT/PARENT-DIR
          $ mv OLD-DIR NEW-DIR

  3. Fix the CVS administrative files, if necessary (for instance if
     you renamed an entire module).

  4. Tell everyone that they can check out again and continue working.

   If someone had a working copy the CVS commands will cease to work
for him, until he removes the directory that disappeared inside the
repository.

   It is almost always better to move the files in the directory
instead of moving the directory.  If you move the directory you are
unlikely to be able to retrieve old releases correctly, since they
probably depend on the name of the directories.

History browsing
****************

   Once you have used CVS to store a version control history--what
files have changed when, how, and by whom, there are a variety of
mechanisms for looking through the history.

Log messages
============

   Whenever you commit a file you specify a log message.

   To look through the log messages which have been specified for every
revision which has been committed, use the `cvs log' command (see
log).

The history database
====================

   You can use the history file (see history file) to log various
CVS actions.  To retrieve the information from the history file, use
the `cvs history' command (see history).

   Note: you can control what is logged to this file by using the
`LogHistory' keyword in the `CVSROOT/config' file (see config).

User-defined logging
====================

   You can customize CVS to log various kinds of actions, in whatever
manner you choose.  These mechanisms operate by executing a script at
various times.  The script might append a message to a file listing the
information and the programmer who created it, or send mail to a group
of developers, or, perhaps, post a message to a particular newsgroup.
To log commits, use the `loginfo' file (see loginfo), and to log
tagging operations, use the `taginfo' file (see taginfo).

   To log commits, checkouts, exports, and tags, respectively, you can
also use the `-i', `-o', `-e', and `-t' options in the modules file.
For a more flexible way of giving notifications to various users, which
requires less in the way of keeping centralized scripts up to date, use
the `cvs watch add' command (see Getting Notified); this command is
useful even if you are not using `cvs watch on'.

Handling binary files
*********************

   The most common use for CVS is to store text files.  With text
files, CVS can merge revisions, display the differences between
revisions in a human-visible fashion, and other such operations.
However, if you are willing to give up a few of these abilities, CVS
can store binary files.  For example, one might store a web site in CVS
including both text files and binary images.

The issues with binary files
============================

   While the need to manage binary files may seem obvious if the files
that you customarily work with are binary, putting them into version
control does present some additional issues.

   One basic function of version control is to show the differences
between two revisions.  For example, if someone else checked in a new
version of a file, you may wish to look at what they changed and
determine whether their changes are good.  For text files, CVS provides
this functionality via the `cvs diff' command.  For binary files, it
may be possible to extract the two revisions and then compare them with
a tool external to CVS (for example, word processing software often has
such a feature).  If there is no such tool, one must track changes via
other mechanisms, such as urging people to write good log messages, and
hoping that the changes they actually made were the changes that they
intended to make.

   Another ability of a version control system is the ability to merge
two revisions.  For CVS this happens in two contexts.  The first is
when users make changes in separate working directories (see Multiple developers).
The second is when one merges explicitly with the
`update -j' command (see Branching and merging).

   In the case of text files, CVS can merge changes made independently,
and signal a conflict if the changes conflict.  With binary files, the
best that CVS can do is present the two different copies of the file,
and leave it to the user to resolve the conflict.  The user may choose
one copy or the other, or may run an external merge tool which knows
about that particular file format, if one exists.  Note that having the
user merge relies primarily on the user to not accidentally omit some
changes, and thus is potentially error prone.

   If this process is thought to be undesirable, the best choice may be
to avoid merging.  To avoid the merges that result from separate
working directories, see the discussion of reserved checkouts (file
locking) in Multiple developers.  To avoid the merges resulting
from branches, restrict use of branches.

How to store binary files
=========================

   There are two issues with using CVS to store binary files.  The
first is that CVS by default converts line endings between the
canonical form in which they are stored in the repository (linefeed
only), and the form appropriate to the operating system in use on the
client (for example, carriage return followed by line feed for Windows
NT).

   The second is that a binary file might happen to contain data which
looks like a keyword (see Keyword substitution), so keyword
expansion must be turned off.

   The `-kb' option available with some CVS commands insures that
neither line ending conversion nor keyword expansion will be done.

   Here is an example of how you can create a new file using the `-kb'
flag:

     $ echo '$Id$' > kotest
     $ cvs add -kb -m"A test file" kotest
     $ cvs ci -m"First checkin; contains a keyword" kotest

   If a file accidentally gets added without `-kb', one can use the
`cvs admin' command to recover.  For example:

     $ echo '$Id$' > kotest
     $ cvs add -m"A test file" kotest
     $ cvs ci -m"First checkin; contains a keyword" kotest
     $ cvs admin -kb kotest
     $ cvs update -A kotest
     # For non-unix systems:
     # Copy in a good copy of the file from outside CVS
     $ cvs commit -m "make it binary" kotest

   When you check in the file `kotest' the file is not preserved as a
binary file, because you did not check it in as a binary file.  The `cvs
admin -kb' command sets the default keyword substitution method for
this file, but it does not alter the working copy of the file that you
have.  If you need to cope with line endings (that is, you are using
CVS on a non-unix system), then you need to check in a new copy of the
file, as shown by the `cvs commit' command above.  On unix, the `cvs
update -A' command suffices.  (Note that you can use `cvs log' to
determine the default keyword substitution method for a file and `cvs
status' to determine the keyword substitution method for a working
copy.)

   However, in using `cvs admin -k' to change the keyword expansion, be
aware that the keyword expansion mode is not version controlled.  This
means that, for example, that if you have a text file in old releases,
and a binary file with the same name in new releases, CVS provides no
way to check out the file in text or binary mode depending on what
version you are checking out.  There is no good workaround for this
problem.

   You can also set a default for whether `cvs add' and `cvs import'
treat a file as binary based on its name; for example you could say
that files who names end in `.exe' are binary.  See Wrappers.
There is currently no way to have CVS detect whether a file is binary
based on its contents.  The main difficulty with designing such a
feature is that it is not clear how to distinguish between binary and
non-binary files, and the rules to apply would vary considerably with
the operating system.

Multiple developers
*******************

   When more than one person works on a software project things often
get complicated.  Often, two people try to edit the same file
simultaneously.  One solution, known as "file locking" or "reserved
checkouts", is to allow only one person to edit each file at a time.
This is the only solution with some version control systems, including
RCS and SCCS.  Currently the usual way to get reserved checkouts with
CVS is the `cvs admin -l' command (see admin options).  This is not
as nicely integrated into CVS as the watch features, described below,
but it seems that most people with a need for reserved checkouts find
it adequate.

   As of CVS version 1.12.10, another technique for getting most of the
effect of reserved checkouts is to enable advisory locks.  To enable
advisory locks, have all developers put "edit -c", "commit -c" in their
.cvsrc file, and turn on watches in the repository.  This prevents them
from doing a `cvs edit' if anyone is already editting the file.  It
also may be possible to use plain watches together with suitable
procedures (not enforced by software), to avoid having two people edit
at the same time.

   The default model with CVS is known as "unreserved checkouts".  In
this model, developers can edit their own "working copy" of a file
simultaneously.  The first person that commits his changes has no
automatic way of knowing that another has started to edit it.  Others
will get an error message when they try to commit the file.  They must
then use CVS commands to bring their working copy up to date with the
repository revision.  This process is almost automatic.

   CVS also supports mechanisms which facilitate various kinds of
communication, without actually enforcing rules like reserved checkouts
do.

   The rest of this chapter describes how these various models work,
and some of the issues involved in choosing between them.

File status
===========

   Based on what operations you have performed on a checked out file,
and what operations others have performed to that file in the
repository, one can classify a file in a number of states.  The states,
as reported by the `status' command, are:

Up-to-date
     The file is identical with the latest revision in the repository
     for the branch in use.

Locally Modified
     You have edited the file, and not yet committed your changes.

Locally Added
     You have added the file with `add', and not yet committed your
     changes.

Locally Removed
     You have removed the file with `remove', and not yet committed
     your changes.

Needs Checkout
     Someone else has committed a newer revision to the repository.
     The name is slightly misleading; you will ordinarily use `update'
     rather than `checkout' to get that newer revision.

Needs Patch
     Like Needs Checkout, but the CVS server will send a patch rather
     than the entire file.  Sending a patch or sending an entire file
     accomplishes the same thing.

Needs Merge
     Someone else has committed a newer revision to the repository, and
     you have also made modifications to the file.

Unresolved Conflict
     A file with the same name as this new file has been added to the
     repository from a second workspace.  This file will need to be
     moved out of the way to allow an `update' to complete.

File had conflicts on merge
     This is like Locally Modified, except that a previous `update'
     command gave a conflict.  If you have not already done so, you
     need to resolve the conflict as described in Conflicts example.

Unknown
     CVS doesn't know anything about this file.  For example, you have
     created a new file and have not run `add'.

   To help clarify the file status, `status' also reports the `Working
revision' which is the revision that the file in the working directory
derives from, and the `Repository revision' which is the latest
revision in the repository for the branch in use.  The `Commit
Identifier' reflects the unique commitid of the `commit'.

   The options to `status' are listed in Invoking CVS.  For
information on its `Sticky tag' and `Sticky date' output, see
Sticky tags.  For information on its `Sticky options' output, see the
`-k' option in update options.

   You can think of the `status' and `update' commands as somewhat
complementary.  You use `update' to bring your files up to date, and you
can use `status' to give you some idea of what an `update' would do (of
course, the state of the repository might change before you actually run
`update').  In fact, if you want a command to display file status in a
more brief format than is displayed by the `status' command, you can
invoke

     $ cvs -n -q update

   The `-n' option means to not actually do the update, but merely to
display statuses; the `-q' option avoids printing the name of each
directory.  For more information on the `update' command, and these
options, see Invoking CVS.

Bringing a file up to date
==========================

   When you want to update or merge a file, use the `update' command.
For files that are not up to date this is roughly equivalent to a
`checkout' command: the newest revision of the file is extracted from
the repository and put in your working directory.

   Your modifications to a file are never lost when you use `update'.
If no newer revision exists, running `update' has no effect.  If you
have edited the file, and a newer revision is available, CVS will merge
all changes into your working copy.

   For instance, imagine that you checked out revision 1.4 and started
editing it.  In the meantime someone else committed revision 1.5, and
shortly after that revision 1.6.  If you run `update' on the file now,
CVS will incorporate all changes between revision 1.4 and 1.6 into your
file.

   If any of the changes between 1.4 and 1.6 were made too close to any
of the changes you have made, an "overlap" occurs.  In such cases a
warning is printed, and the resulting file includes both versions of
the lines that overlap, delimited by special markers.  See update,
for a complete description of the `update' command.

Conflicts example
=================

   Suppose revision 1.4 of `driver.c' contains this:

     #include <stdio.h>

     void main()
     {
         parse();
         if (nerr == 0)
             gencode();
         else
             fprintf(stderr, "No code generated.\n");
         exit(nerr == 0 ? 0 : 1);
     }

Revision 1.6 of `driver.c' contains this:

     #include <stdio.h>

     int main(int argc,
              char **argv)
     {
         parse();
         if (argc != 1)
         {
             fprintf(stderr, "tc: No args expected.\n");
             exit(1);
         }
         if (nerr == 0)
             gencode();
         else
             fprintf(stderr, "No code generated.\n");
         exit(!!nerr);
     }

Your working copy of `driver.c', based on revision 1.4, contains this
before you run `cvs update':

     #include <stdlib.h>
     #include <stdio.h>

     void main()
     {
         init_scanner();
         parse();
         if (nerr == 0)
             gencode();
         else
             fprintf(stderr, "No code generated.\n");
         exit(nerr == 0 ? EXIT_SUCCESS : EXIT_FAILURE);
     }

You run `cvs update':

     $ cvs update driver.c
     RCS file: /usr/local/cvsroot/yoyodyne/tc/driver.c,v
     retrieving revision 1.4
     retrieving revision 1.6
     Merging differences between 1.4 and 1.6 into driver.c
     rcsmerge warning: overlaps during merge
     cvs update: conflicts found in driver.c
     C driver.c

CVS tells you that there were some conflicts.  Your original working
file is saved unmodified in `.#driver.c.1.4'.  The new version of
`driver.c' contains this:

     #include <stdlib.h>
     #include <stdio.h>

     int main(int argc,
              char **argv)
     {
         init_scanner();
         parse();
         if (argc != 1)
         {
             fprintf(stderr, "tc: No args expected.\n");
             exit(1);
         }
         if (nerr == 0)
             gencode();
         else
             fprintf(stderr, "No code generated.\n");
     <<<<<<< driver.c
         exit(nerr == 0 ? EXIT_SUCCESS : EXIT_FAILURE);
     =======
         exit(!!nerr);
     >>>>>>> 1.6
     }

Note how all non-overlapping modifications are incorporated in your
working copy, and that the overlapping section is clearly marked with
`<<<<<<<', `=======' and `>>>>>>>'.

   You resolve the conflict by editing the file, removing the markers
and the erroneous line.  Suppose you end up with this file:
     #include <stdlib.h>
     #include <stdio.h>

     int main(int argc,
              char **argv)
     {
         init_scanner();
         parse();
         if (argc != 1)
         {
             fprintf(stderr, "tc: No args expected.\n");
             exit(1);
         }
         if (nerr == 0)
             gencode();
         else
             fprintf(stderr, "No code generated.\n");
         exit(nerr == 0 ? EXIT_SUCCESS : EXIT_FAILURE);
     }

You can now go ahead and commit this as revision 1.7.

     $ cvs commit -m "Initialize scanner. Use symbolic exit values." driver.c
     Checking in driver.c;
     /usr/local/cvsroot/yoyodyne/tc/driver.c,v  <--  driver.c
     new revision: 1.7; previous revision: 1.6
     done

   For your protection, CVS will refuse to check in a file if a
conflict occurred and you have not resolved the conflict.  Currently to
resolve a conflict, you must change the timestamp on the file.  In
previous versions of CVS, you also needed to insure that the file
contains no conflict markers.  Because your file may legitimately
contain conflict markers (that is, occurrences of `>>>>>>> ' at the
start of a line that don't mark a conflict), the current version of CVS
will print a warning and proceed to check in the file.

   If you use release 1.04 or later of pcl-cvs (a GNU Emacs front-end
for CVS) you can use an Emacs package called emerge to help you resolve
conflicts.  See the documentation for pcl-cvs.

Informing others about commits
==============================

   It is often useful to inform others when you commit a new revision
of a file.  The `-i' option of the `modules' file, or the `loginfo'
file, can be used to automate this process.  See modules.  See
loginfo.  You can use these features of CVS to, for instance,
instruct CVS to mail a message to all developers, or post a message to
a local newsgroup.

Several developers simultaneously attempting to run CVS
=======================================================

   If several developers try to run CVS at the same time, one may get
the following message:

     [11:43:23] waiting for bach's lock in /usr/local/cvsroot/foo

   CVS will try again every 30 seconds, and either continue with the
operation or print the message again, if it still needs to wait.  If a
lock seems to stick around for an undue amount of time, find the person
holding the lock and ask them about the cvs command they are running.
If they aren't running a cvs command, look in the repository directory
mentioned in the message and remove files which they own whose names
start with `#cvs.rfl', `#cvs.wfl', or `#cvs.lock'.

   Note that these locks are to protect CVS's internal data structures
and have no relationship to the word "lock" in the sense used by
RCS--which refers to reserved checkouts (see Multiple developers).

   Any number of people can be reading from a given repository at a
time; only when someone is writing do the locks prevent other people
from reading or writing.

   One might hope for the following property:

     If someone commits some changes in one cvs command, then an update
     by someone else will either get all the changes, or none of them.

but CVS does _not_ have this property.  For example, given the files

     a/one.c
     a/two.c
     b/three.c
     b/four.c

if someone runs

     cvs ci a/two.c b/three.c

and someone else runs `cvs update' at the same time, the person running
`update' might get only the change to `b/three.c' and not the change to
`a/two.c'.