Go to the previous, next section.

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. Some other version control systems (including RCS and SCCS) try to solve that particular problem by introducing file locking, so that only one person can edit each file at a time. Unfortunately, file locking can be very counter-productive. If two persons want to edit different parts of a file, there may be no reason to prevent either of them from doing so.

CVS does not use file locking. Instead, it allows many people to 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, and explained in this chapter.

There are many ways to organize a team of developers. CVS does not try to enforce a certain organization. It is a tool that can be used in several ways. It is often useful to inform the group of commits you have done. CVS has several ways of automating that process. See section Informing others about commits. See section Revision management, for more tips on how to use CVS.

File status

After you have checked out a file out from CVS, it is in one of these four states:

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

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

Needing update
Someone else has committed a newer revision to the repository.

Needing merge
Someone else have committed a newer revision to the repository, and you have also made modifications to the file.

You can use the status command to find out the status of a given file. See section status--Display status information on checked out files.

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 copy of the module.

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 section update--Bring work tree in sync with repository, 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

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 section The modules file. See section 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 for and remove files starting with `#cvs.tfl', `#cvs.rfl', or `#cvs.wfl' from the repository.

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--a way to prevent other developers from working on a particular file.

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'.

Mechanisms to track who is editing files

For many groups, use of CVS in its default mode is perfectly satisfactory. Users may sometimes go to check in a modification only to find that another modification has intervened, but they deal with it and proceed with their check in. Other groups prefer to be able to know who is editing what files, so that if two people try to edit the same file they can choose to talk about who is doing what when rather than be surprised at check in time. The features in this section allow such coordination, while retaining the ability of two developers to edit the same file at the same time.

For maximum benefit developers should use cvs edit (not chmod) to make files read-write to edit them, and cvs release (not rm) to discard a working directory which is no longer in use, but CVS is not able to enforce this behavior.

Telling CVS to watch certain files

To enable the watch features, you first specify that certain files are to be watched.

Command: cvs watch on [-l] files ...

Specify that developers should run cvs edit before editing files. CVS will create working copies of files read-only, to remind developers to run the cvs edit command before working on them.

If files includes the name of a directory, CVS arranges to watch all files added to the corresponding repository directory, and sets a default for files added in the future; this allows the user to set notification policies on a per-directory basis. The contents of the directory are processed recursively, unless the -l option is given.

If files is omitted, it defaults to the current directory.

Command: cvs watch off [-l] files ...

Do not provide notification about work on files. CVS will create working copies of files read-write.

The files and -l arguments are processed as for cvs watch on.

Telling CVS to notify you

You can tell CVS that you want to receive notifications about various actions taken on a file. You can do this without using cvs watch on for the file, but generally you will want to use cvs watch on, so that developers use the cvs edit command.

Command: cvs watch add [-a action] [-l] files ...

Add the current user to the list of people to receive notification of work done on files.

The -a option specifies what kinds of events CVS should notify the user about. action is one of the following:

edit
Another user has applied the cvs edit command (described below) to a file.

unedit
Another user has applied the cvs unedit command (described below) or the cvs release command to a file, or has deleted the file and allowed cvs update to recreate it.

commit
Another user has committed changes to a file.

all
All of the above.

none
None of the above. (This is useful with cvs edit, described below.)

The -a option may appear more than once, or not at all. If omitted, the action defaults to all.

The files and -l option are processed as for the cvs watch commands.

Command: cvs watch remove [-a action] [-l] files ...

Remove a notification request established using cvs watch add; the arguments are the same. If the -a option is present, only watches for the specified actions are removed.

When the conditions exist for notification, CVS calls the `notify' administrative file. Edit `notify' as one edits the other administrative files (see section The administrative files). This file follows the usual conventions for administrative files (see section The common syntax), where each line is a regular expression followed by a command to execute. The command should contain a single ocurrence of `%s' which will be replaced by the user to notify; the rest of the information regarding the notification will be supplied to the command on standard input. The standard thing to put in the notify file is the single line:

ALL mail %s -s \"CVS notification\"

This causes users to be notified by electronic mail.

Note that if you set this up in the straightforward way, users receive notifications on the server machine. One could of course write a `notify' script which directed notifications elsewhere, but to make this easy, CVS allows you to associate a notification address for each user. To do so create a file `users' in `CVSROOT' with a line for each user in the format user:value. Then instead of passing the name of the user to be notified to `notify', CVS will pass the value (normally an email address on some other machine).

How to edit a file which is being watched

Since a file which is being watched is checked out read-only, you cannot simply edit it. To make it read-write, and inform others that you are planning to edit it, use the cvs edit command.

Command: cvs edit [options] files ...

Prepare to edit the working files files. CVS makes the files read-write, and notifies users who have requested edit notification for any of files.

The cvs edit command accepts the same options as the cvs watch add command, and establishes a temporary watch for the user on files; CVS will remove the watch when files are unedited or committed. If the user does not wish to receive notifications, she should specify -a none.

The files and -l option are processed as for the cvs watch commands.

Normally when you are done with a set of changes, you use the cvs commit command, which checks in your changes and returns the watched files to their usual read-only state. But if you instead decide to abandon your changes, or not to make any changes, you can use the cvs unedit command.

Command: cvs unedit [-l] files ...

Abandon work on the working files files, and revert them to the repository versions on which they are based. CVS makes those files read-only for which users have requested notification using cvs watch on. CVS notifies users who have requested unedit notification for any of files.

The files and -l option are processed as for the cvs watch commands.

When using client/server CVS, you can use the cvs edit and cvs unedit commands even if CVS is unable to succesfully communicate with the server; the notifications will be sent upon the next successful CVS command.

Information about who is watching and editing

Command: cvs watchers [-l] files ...

List the users currently watching changes to files. The report includes the files being watched, and the mail address of each watcher.

The files and -l arguments are processed as for the cvs watch commands.

Command: cvs editors [-l] files ...

List the users currently working on files. The report includes the mail address of each user, the time when the user began working with the file, and the host and path of the working directory containing the file.

The files and -l arguments are processed as for the cvs watch commands.

Using watches with old versions of CVS

If you use the watch features on a repository, it creates `CVS' directories in the repository and stores the information about watches in that directory. If you attempt to use CVS 1.6 or earlier with the repository, you get an error message such as

cvs update: cannot open CVS/Entries for reading: No such file or directory

and your operation will likely be aborted. To use the watch features, you must upgrade all copies of CVS which use that repository in local or server mode. If you cannot upgrade, use the watch off and watch remove commands to remove all watches, and that will restore the repository to a state which CVS 1.6 can cope with.

Go to the previous, next section.