Feedback
Help

Features


Features

Working Model

The CVS model assumes that there is one central official master copy of everything. It is called "the CVS repository." This copy is managed by CVS and is not meant to be touched directly.

Instead, when you wish to work on a CVS-managed project, you "check out" your own private copy. Since work on a program is an ongoing process, and other people may be working on the same program at the same time, you generally want changes in the official master copy to appear in your private copy. To facilitate this, the private copy is connected back to the master copy. Some people think of this as a "subscription" -the private copy is signed up to receive copies of updates that are made to the master copy.

Note, however, that these updates do not happen automatically. You must explicitly update your private copy when the master copy changes.

When you transfer ("commit") changes in your private copy to the master copy, the master copy is updated and other developers will then see those changes when they update. Changes you make in your private copy that you do not commit do not officially exist and will not be seen by anyone else until you commit them.

You can have as many working trees (private copies connected to the master copy) as you want. Often you will have only one, but circumstances may arise in which it is more convenient to have two, or to make temporary ones, or whatever. Just remember that they are all independent: while they're all connected back to the master copy, they are not connected to each other except through the master copy.

Repository

The official master copy is known as the "CVS repository". It is a directory tree that must be kept in a place where all participating programmers can access it. (CVS has various remote access features which will be described briefly later on.) CVS uses the environment variable $CVSROOT to locate the repository. Always be sure that this variable is set and that it points to the correct CVS repository before invoking CVS.

The CVS repository contains one CVS file for each file in your project, laid out in a directory tree that mirrors your project organization. These files have a ",v" suffix and contain control information and version history as well as the latest version of each file. (While in emergencies these files can be edited by hand, doing so is strongly discouraged.)

The CVS repository also contains a directory CVSROOT that holds various CVS configuration data. When you create a repository, you get default versions of all these files that include comments briefly explaining the purpose and syntax of each. If you want to edit these files, check out "CVSROOT" as if it were another project, edit the files, and commit them. See below for a couple of simple examples.

Note: do not confuse the CVSROOT directory with the $CVSROOT environment variable. The CVSROOT directory is really $CVSROOT/CVSROOT.

Back up your CVS repository occasionally, just in case. If you lose your working tree, you should only lose a small amount of work; but if you lose your CVS repository, you lose everything.

Merging

Unlike many (most?) source control systems, CVS does not lock files for modification. Instead, CVS works from a model where everybody edits freely and changes to the same file are merged. CVS does not support locks at all.

In the merge-based model, anyone can edit any file at any time. This is both an advantage and a disadvantage: if two people have small unrelated changes to make in the same file, they can do so without any difficulty. On the other hand, if two people make sweeping changes to the same file at once, the resulting merge becomes a nightmare.

(Another major advantage of merging is that when there are no locks, nobody can hold up development by leaving on vacation while holding a lock on a critical file.)

The way CVS merging works is as follows: when you check out a working tree, CVS remembers what version of each file you got. When you update your working tree, it updates these versions. When you go to commit, if the version your changes are based on is not the latest one, CVS aborts and tells you to update first.

Then, when you update, CVS notices that you have changed your copy and the master copy has changed as well. It then tries to merge the two sets of changes. If the changes are to unrelated areas of the file, this usually succeeds. If the changes overlap, or the merge program gets confused, CVS will say "conflicts during merge". The resulting file will contain blocks that look like this:

  int foo(void) {
<<<<<<< foo.c
    bar();
=======
    baz()
>>>>>>> 1.2
}

This means that your copy of foo.c changed function foo to call bar, but that the official master copy, in version 1.2, changed foo in the same place so it calls baz.

When you get merge conflicts like this, you need to resolve them before committing your new versions. You might pick your version, or the latest version from the repository, or some combination of the two, or whatever. When doing this, it's up to you to make sure you do the right thing.

Some notes:

  1. Even when there are conflicts, the conflict blocks do not necessarily reflect all the changes associated with the merge. Some may have merged successfully. If in doubt, look at diffs.
  2. It is also not always the case that everything that may be involved in resolving a conflict correctly is contained within the conflict block delimiters. The merge program is only a program, not an omnipotent human being.
  3. While the merge system is reasonably robust, once in a while it makes a mistake, particularly if some but not all of the changes merged. It's prudent to look at diffs after an automatic merge, just in case.
  4. Merging is painful. Merging a big change is a lot more painful than merging the same amount of change a bit at a time. Update early and often. Commit early and often.

If you are planning to make huge changes to a file, like reordering all the functions or moving large blocks of code into if clauses (which changes the indent, making CVS think everything changed), it's a good idea to coordinate manually with anyone else who might have pending changes to the file.

Log Messages

When you commit changes to the CVS repository, CVS gives you the opportunity to provide a message explaining the change. These messages get saved in the CVS file and can be reviewed later using cvs log. This can be quite useful when trying to reconstruct the thinking that led to some piece of code you wrote months previously.

These messages can also be logged centrally or mailed out to the people working on the project. We recommend that you set up your CVS repository to mail commit messages to you and your partner. (See below.) While the volume of mail thus generated can be irritating, there's no better way to stay in touch with what's going on.

The commit message should thus describe (briefly) what you did and why. There's no need to report the exact changes, as they can be retrieved using cvs diff.

When to commit

The general rule for commits is that any change should be committed as soon as you're reasonably certain that it's correct and appropriate in the long term, subject to the proviso that committing many small changes in quick succession will probably annoy everyone working with you.

Remember that your partner won't see anything you don't commit, so get bug fixes in quickly and hold back a little on new features that might still have problems.

Ideally you and your partner should keep track of which tests you expect to work at any particular time, and before committing check to make sure that they all still do work.

In most cases, one should try to avoid committing changes that cause the program to stop working properly (or, even, stop compiling at all.) This rule can sometimes be profitably bent when you know your partner will not be affected by the errors introduced.

Tags

CVS inherited part of its view of the world from an earlier toolset known as "RCS", mentioned briefly below. One of the consequences of this is that every file has its own private version number. Thus, while it is possible to do things like look at version 1.5 of every file, it is not very useful to do so.

Instead, CVS supports a concept known as a "tag". A tag is a symbolic name (like asst4-debugged) that you attach to a particular version of some set of files. You can then refer to that version of those files with the name.

A tag is normally used to identify a single consistent version of an entire project. For instance, the directions for each assignment (after assignment 0) tell you to create one tag before starting and another tag after you're done. These tags then identify the versions of all your files that were current before and after you did the assignment. This lets you, for example, ask CVS to show you all the changes in the entire system between those two points.

Tags are more or less arbitrary alphanumeric text, but, to disambiguate them from file version numbers, they may not begin with digits or contain dots. Since tags are frequently used for program version numbers, and version numbers regularly contain dots, it is conventional to use an underscore (`_') in place of each dot.

See below for specific directions for manipulating tags with CVS.

Branches

Sometimes you might have more than one "line of development" in your program. For instance, when you ship release 1.0 to customers, you might have one team working on release 2.0, and another team making minor bug fixes to the release 1.0 code for release 1.01.

In this case, most changes made for release 2.0 should not be incorporated into release 1.01, and while many fixes made for release 1.01 should be incorporated into release 2.0, some probably shouldn't be.

This sort of situation is handled using "branches". Each branch is a (mostly) separate line of development, diverging from some common ancestor version. (This divergence is where the term "branch" arose.)

Using branches in CVS can be fairly painful and is beyond the scope of this document. The vendor branch functionality is an exception and is discussed briefly below along with cvs import.

Use CVS Effectively

CVS is a tool, not a panacea. It helps you organize and maintain a project, but it doesn't do it by itself. It requires that you use it in a manner that makes it useful.

In order for the repository to be a useful tool for keeping track of what is really part of the project and what is not, you have to actively maintain the set of files CVS knows about. Don't add or commit temporary files, editor backups, object files, and the like to the CVS repository. Do remove files you're not using any more. (Even after telling CVS to remove them, you can still get them back later, because removing them is just a change that CVS tracks.)

In order for the version history to be useful, you have to add tags at important points in development, like releases. You also have to write at least minimally useful commit messages so you can look at them later and be reminded of the circumstances.

In order for the merging features to be useful, you have to avoid making sweeping changes without warning your partner, you have to update and commit regularly but not insanely often, and you have to take the trouble to merge correctly by hand when conflicts occur.

If you don't do these things, you will eventually end up in a hole, and CVS will not save you from yourself.

RCS

Some of you may have seen RCS, the Revision Control System. RCS is an ancestor of CVS; in fact, RCS more or less serves as the "back end" of CVS.

If you have used RCS, think of CVS as like a super-RCS that works on whole directory trees instead of single files. It also, as noted above, does not support file locking, but uses merging instead. There are some other minor differences as well.

If you haven't used RCS or don't know what it is, don't worry about it.

MyCVS


CVS allows many developers to work on large projects concurrently.

Wikipedia
The Free Encyclopedia
– Copyright © 2003-2012 Top Freelance LLC. All rights reserved.