This section describes some basic CVS operations, then follows with a sample session covering typical CVS usage. As the guided tour progresses, we'll also start to look at how CVS works internally.
Each part of the tour may make use of knowledge introduced in previous parts. Therefore, if this is your first time, I recommend that you simply start at the beginning and take the tour sequentially, without skipping over anything.
CVS is one program, but it can perform many different actions: updating, committing, branching, diffing, and so on. When you invoke CVS, you must specify which action you want to perform. Thus, the format of a CVS invocation is:
floss$ cvs command
For example, you can use
floss$ cvs update floss$ cvs diff floss$ cvs commit
and so on. (Don't bother to try running any of those particular commands yet, though; they won't do anything until you're in a working copy, which we'll get to shortly.)
Both CVS and the command can take options. Options that affect the behavior of CVS, independently of the command being run, are called global options; command-specific options are just called command options. Global options always go to the left of the command; command options, to its right. So in
floss$ cvs -Q update -p
-Q is a global option, and -p is a command option. (If you're curious, -Q means "quietly"-that is, suppress all diagnostic output, and print error messages only if the command absolutely cannot be completed for some reason; -p means to send the results of update to standard output instead of to files.)
Previously, I've talked about updating as a way of bringing changes down from the repository into your working copy - that is, as a way of getting other people's changes. However, update is really a bit more complex; it compares the overall state of the working copy with the state of the project in the repository. Even if nothing in the repository has changed since checkout, something in the working copy may have, and update will show that, too:
floss$ cvs update cvs update: Updating . M hello.c cvs update: Updating a-subdir cvs update: Updating a-subdir/subsubdir cvs update: Updating b-subdir
The M next to hello.c means the file has been modified since it was last checked out, and the modifications have not yet been committed to the repository.
Sometimes, merely knowing which files you've edited is all you need. However, if you want a more detailed look at the changes, you can get a full report in diff format. The diff command compares the possibly modified files in the working copy to their counterparts in the repository and displays any differences:
floss$ cvs diff cvs diff: Diffing . Index: hello.c =================================================================== RCS file: /usr/local/cvs/myproj/hello.c,v retrieving revision 1.1.1.1 diff -r1.1.1.1 hello.c 6a7 > printf ("Goodbye, world!\n"); cvs diff: Diffing a-subdir cvs diff: Diffing a-subdir/subsubdir
That's helpful, if a bit obscure, but there's still a lot of cruft in the output. For starters, you can ignore most of the first few lines. They just name the repository file and give the number of the last checked-in revision. These are useful pieces of information under other circumstances (we'll look more closely at them later), but you don't need them when you're just trying to get a sense of what changes have been made in the working copy.
A more serious impediment to reading the diff is that CVS is announcing its entry as it goes into each directory during the update. This can be useful during long updates on large projects, as it gives you a sense of how much longer the command will take, but right now it's just getting in the way of reading the diff. Let's tell CVS to be quiet about where it's working, with the -Q global option:
floss$ cvs -Q diff Index: hello.c =================================================================== RCS file: /usr/local/cvs/myproj/hello.c,v retrieving revision 1.1.1.1 diff -r1.1.1.1 hello.c 6a7 > printf ("Goodbye, world!\n");
In each of the CVS commands so far, you may have noticed that no files were specified on the command line. We ran
floss$ cvs diff
instead of
floss$ cvs diff hello.c
and
floss$ cvs update
instead of
floss$ cvs update hello.c
The principle at work here is that if you don't name any files, CVS acts on all files for which the command could possibly be appropriate. This even includes files in subdirectories beneath the current directory; CVS automatically descends from the current directory through every subdirectory in the tree. For example, if you modified b-subdir/random.c and a-subdir/subsubdir/fish.c, running update may result in this:
floss$ cvs update cvs update: Updating . M hello.c cvs update: Updating a-subdir cvs update: Updating a-subdir/subsubdir M a-subdir/subsubdir/fish.c cvs update: Updating b-subdir M b-subdir/random.c floss$
or better yet:
floss$ cvs -q update M hello.c M a-subdir/subsubdir/fish.c M b-subdir/random.c floss$
Note: The -q flag is a less emphatic version of -Q. Had we used -Q, the command would have printed out nothing at all, because the modification notices are considered nonessential informational messages. Using the lowercase -q is less strict; it suppresses the messages we probably don't want, while allowing certain, more useful messages to pass through.
You can also name specific files for the update:
floss$ cvs update hello.c b-subdir/random.c M hello.c M b-subdir/random.c floss$
and CVS will only examine those files, ignoring all others.
In truth, it's more common to run update without restricting it to certain files. In most situations, you'll want to update the entire directory tree at once. Remember, the updates we're doing here only show that some files have been locally modified, because nothing has changed yet in the repository. When other people are working on the project with you, there's always the chance that running update will pull some new changes down from the repository and incorporate them into your local files. In that case, you may find it slightly more useful to name which files you want updated.
The same principle can be applied to other CVS commands. For example, with diff, you can choose to view the changes one file at a time
floss$ cvs diff -c b-subdir/random.c