CVS (with TkCVS)

This is a quick mini-tutorial to help you use CVS successfully, using TkCVS as a front end. The CVS commands are in bold type, and the small graphic with each command is the icon on TkCVS's corresponding button.

CVS (Concurrent Versioning System) is a venerable open-source revision control system that was built on the even more venerable RCS, and to this day CVS and RCS can read each other's history files.  No GUI can be a replacement for understanding what CVS does.  Executing cvs --help from the command line will give you much useful information.  There is a detailed manpage for CVS, but you'll want to use a searchable manpage reader to navigate it.

TkCVS helps visualize the versioning process and executes CVS commands for you.  The pictures on this page were captured from its various browsing tools.  To use it, make sure you can run wish8.4 and then invoke tkcvs.  Its documentation is available from its Help menu.


The Repositorymodbrowse_cvs

To access a repository, you usually set your CVSROOT environment variable.   It can point to a directory on a filesystem that's directly accisible to you, such as /wv/pete/cvsroot, to a cvs pserver such as :pserver:wvcalcvs:/wv/pete/cvsroot, or to a location that's reachable by rsh or ssh.

CVS TreeA CVS repository consists of directories under $CVSROOT, plus the $CVSROOT/CVSROOT directory of administrative files.  To facilitate browsing, the CVSROOT/modules file can be populated with a nested listing of the directory structure, possibly creating something like the diagram at right in the TkCVS Module Browser.

The idea of the modularity is that you may wish to have only part of a project checked out in your "sandbox" to work on.  For instance, you may want only the TDopc module.

To check out a module you create a new directory (something like myname_myproduct_branch is common), cd into it, and use cvs to check out one or more modules.  For example, to check out the TDOPC directory shown in the diagram at right:
cvs co -P calibre/TDopc Module Checkout

Always use the -P (prune) option when you check out, or you may get empty directories left over from obsoleted items.  This happens because CVS cannot version directories.

To check out a branch version, you use the -r (revision) option:
cvs co -P -rcal2004_2 calibre/TDopc Module Checkout



The Checked-out Working Directory (the "Sandbox") Working Directory Browser

CVS is designed to allow several people to work on a project at once without bothering each other (that's the "Concurrent" in Concurrent Versioning System) so it doesn't perform locking the way older systems such as RCS do.

As an example of the typical use of CVS, here is a directory that was checked out and fiddled with awhile ago, but another person has made changes in the meantime.
cvs status | grep '^File' Re-read
gives this output:
File: app.c           Status: Up-to-date
File: cleanup_tst Status: Locally Modified
File: compare Status: Up-to-date
File: dofile Status: Needs Patch
File: litho.in Status: Needs Merge
File: litho.svrf Status: Up-to-date
File: mkbaseline Status: Up-to-date
File: setup_tst Status: Needs Patch
File: test.oas Status: Up-to-date
File: xor.svrf Status: Up-to-date


cvs -n -q update Check
gives the short form:

M cleanup_tst
U dofile
M litho.in
U setup_tst
? litho.transcript
? xor.transcript
? xor_result.oas

In TkCVS, it looks like this:
Out of date #1

Let's look at what the different statuses mean.
Needs Patch:  dofile and setup_tst have changed in the repository.  All that's needed is to update them, which will put the latest version in the current "sandbox."
Needs Merge:  litho.in has changed in one way in the repostiory, and it has been edited a different way, but not committed, in the current directory.  An update is needed here, too.  When updating, CVS will merge both sets of changes into the local file.
Locally Modified: cleanup_tst has changed in the local "sandbox" but not in the repository.

After doing  cvs update we have
cvs status | grep '^File' Re-read
File: app.c           Status: Up-to-date
File: cleanup_tst Status: Locally Modified
File: compare Status: Up-to-date
File: dofile Status: Up-to-date
File: litho.in Status: File had conflicts on merge
File: litho.svrf Status: Up-to-date
File: mkbaseline Status: Up-to-date
File: setup_tst Status: Up-to-date
File: test.oas Status: Up-to-date
File: xor.svrf Status: Up-to-date


cvs -n -q update Check
M cleanup_tst
C litho.in
? litho.transcript
? xor.transcript
? xor_result.oas


Out of date #2

The "Needs Patch" files are up-to-date now, but CVS could not automatically merge the two sets of edits to litho.in, because the same line was changed in different ways by the two edits.  The "common ancestor" of the two files has been saved as the hidden file .#litho.in.1.1, and the current litho.in contains conflict markers, ie.
<<<<<<< litho.in
aspect 4.0
siteinfo AERIAL -num 8
=======
siteinfo AERIAL -num 10
>>>>>>> 1.2

Unless you simply want to abandon your changes (cvs update -C litho.in Revert) you must edit the file and resolve the conflict manually.  An easy way to do it is with tkdiff:
tkdiff -conflict litho.in tkdiff -conflict
tkdff -conflict

After resolving the conflict and saving the file, litho.in has a status of "Locally Modified."  Now you can check in (commit) the changes you want to keep:
cvs ci cleanup_tst litho.in Checkin, Commit
Then "cvs status" will show everything up-to-date.


Important

CVS helps you checkpoint revisions, but the best policy to head off problems is old-fashioned communication.  If you check in changes to a suite you know someone else also works on, it's common courtesy to inform them when you make substantial changes.  That's especially important if you add or remove directories, because the other person won't be alerted to that by CVS. You'll have to notify them that they should do
cvs update -d -P Update with Options
to get the new directories (-d) and remove the obsolete ones  (-P).


Branching and Merging


New FileFor this tutorial, I'm assuming that new files are added on the trunk. To create a branch from the trunk, go to your trunk area and make sure it's up-to-date.  CVS will not allow you to create the branch if it isn't.  It may not be obvious from the cvs status commands that directories have been added or removed.  You can update by doing
cvs update -d -P
to make sure the directory structure is up-to-date.



Newly branched fileA branch marker is a special kind of tag. The command to create a branch is
cvs tag -b cal2007_2
When it's first branched, the diagram looks like this, since no changes have yet  been made to either the trunk or the branch versions.


After creating a branch, it's possible to update your current sandbox to be on the branch, but I recommend checking it out into a fresh tree and also checking out a fresh trunk sandbox.  You may find that you've made mistakes during branching, merging, and various updates, and it's better to learn that now than six months from now when you're in a hurry to check out an old branch and your changes aren't fresh in your mind.

File on branchTo check out the branch version, you use the -r option of cvs checkout to specify the branch tag.  Supposing you want the calibre/TDopc module as in the example:
cvs co -P -r cal2007_2 calibre/TDopc



Now suppose we have a new, improved version on the trunk that we want to copy to the branch.  We could just copy the files, but CVS has a "merge" function to automate it.
Changes on TrunkFirst, notice that you always merge from somewhere else, to where you are.  To merge, you use the cvs update command with the -j (join) option. Since we are merging from the latest (head) revision on the trunk, we specify HEAD as our merge-from branch:
cvs update -d -jHEAD
This operation does not change the repository.  It only copies the files which have changed on the trunk into your branch sandbox.  You must examine what it has done, and resolve any conflicts which may have resulted. When you're finished doing this, you commit the changed files in the usual way, with cvs commit


After merge
Now the branch is the same as the trunk.