Many people have written programs to augment CVS. I call these third-party tools because they have their own maintainers, separate from the CVS development team. Most of these programs are not distributed with CVS, although some are. This chapter covers third-party tools that I have found useful, but that are not distributed with CVS.
Although there are some very popular and widely used non-command-line or non-Unix interfaces to CVS (download sites are listed in section Repository Administration), this chapter does not discuss most of them. Their popularity makes it easy to find out more about them from mailing lists and newsgroups. One exception to this is the Emacs pcl-cvs interface, which is very useful, but sometimes tricky to install.
Depends on: Emacs, Elib
Authors: Per Cederqvist and Stefan Monnier (current maintainer)
pcl-cvs is one of two Emacs/CVS interfaces. The other is the
native VC (Version Control) interface built into Emacs. I prefer
pcl-cvs because it was written exclusively for CVS and, therefore, works
smoothly with the CVS way of doing things. VC, on the other hand, was
designed to work with several different back-end version control systems
-- RCS and SCCS, as well as CVS -- and is not really "tuned" for CVS.
For example, VC presents a file-based rather than a directory-based
interface to revision control.
The advantages of pcl-cvs are strong enough that many people choose to download and install it rather than use VC. Unfortunately, pcl-cvs has two disadvantages: It can be a bit tricky to install (much of this section is devoted to overcoming possible installation hurdles), and its recent releases are a bit unstable.
The latter problem is likely to be temporary, but it does raise the question of which version to use. Stefan Monnier has just recently taken over the pcl-cvs maintainership; the latest release, 2.9.6 (available from the first URL in the preceding list), was a bit bumpy when I tried it. No doubt the problems will be smoothed out soon, but in the meantime, you might want to use an older version. Because I've been using Version 1.05 daily for a long time now and it's performed quite well, I'm going to document that version here. Fortunately, the installation procedures don't change much from version to version. If you decide to use pcl-cvs, I suggest that you check Monnier's download site for a version newer than 2.9.6; if there is one, try it out before regressing all the way to 1.05.
You'll notice that two URLs are given for Version 1.05. The first is Per Cederqvist's site, where he still makes available an old archive of pcl-cvs. However, since I'm not sure how much longer his archive will stay around, I'm also making the 1.05 distribution available from ftp.red-bean.com.
Although the rest of these instructions use examples from a Version 1.05 distribution, they should apply to later versions as well.
If you don't normally deal with Emacs installation and site-maintenance issues, the pcl-cvs installation procedure may seem a bit daunting. A little background on how Emacs works may help.
Most higher-level Emacs features are written in a language called "Emacs
Lisp" (Emacs itself is essentially an interpreter for this language).
People add new features to Emacs by distributing files of Emacs Lisp
pcl-cvs is written in this language, and it depends on a
library of useful, generic Emacs Lisp functions called Elib (also
written in part by Per Cederqvist, but distributed separately from
Elib is not included in the regular Emacs distribution (at least not FSF Emacs; I don't know about XEmacs), so you may have to download and install it yourself before you can use pcl-cvs. You can get it from ftp://ftp.lysator.liu.se/pub/emacs/elib-1.0.tar.gz. Installation instructions are contained within the package.
Once Elib is installed, you're ready to build and install pcl-cvs. These instructions applies both to Version 1.05 and the 2.x series (although you should check the NEWS and INSTALL files in newer distributions to see what's changed).
First, unpack pcl-cvs (I'm using Version 1.05, but it could just as easily have been 2.9.6)
floss$ zcat pcl-cvs-1.05.tar.gz | tar xvf - pcl-cvs-1.05/ pcl-cvs-1.05/README pcl-cvs-1.05/NEWS pcl-cvs-1.05/INSTALL pcl-cvs-1.05/ChangeLog pcl-cvs-1.05/pcl-cvs.el pcl-cvs-1.05/pcl-cvs.texinfo pcl-cvs-1.05/compile-all.el pcl-cvs-1.05/pcl-cvs-lucid.el pcl-cvs-1.05/pcl-cvs-startup.el pcl-cvs-1.05/pcl-cvs.info pcl-cvs-1.05/Makefile pcl-cvs-1.05/texinfo.tex
and go into the source tree's top level:
floss$ cd pcl-cvs-1.05/
A Makefile is supplied there. According to the instructions in the INSTALL file, you're supposed to edit a few paths at the top of the Makefile and then run:
floss$ make install
If that works, great. However, this sometimes results in an error (the pcl-cvs code itself is very portable, but its installation procedures sometimes are not). Do this if you get an error:
floss$ make clean floss$ make
If all goes well, these commands accomplish a significant part of the installation by byte-compiling all of the Emacs Lisp files. (Byte-compiling converts a file of human-readable Emacs Lisp code -- an .el file -- into a more compact and efficient representation -- an .elc file. Emacs can load and run an .elc file with better performance than it can a plain .el file.)
I'll proceed as though the byte-compilation stage has succeeded. If the byte compilation does not appear to succeed, don't worry: The .elc files are a luxury, not a necessity. They improve performance slightly, but you can run pcl-cvs from the raw .el files with no problem.
If the make install failed, the next step is to get the Emacs Lisp (whether .el or .elc) into a directory where Emacs can load it automatically. Emacs has a designated directory on the system for locally installed Lisp. To find this directory -- it will have a file named `default.el' in it -- check the following locations, in this order:
Once you've found your site-lisp directory, copy all of the Lisp files to it (you may have to be root to do this):
floss# cp -f *.el *.elc /usr/share/emacs/site-lisp/
The last step is to tell Emacs about the entry points to pcl-cvs (the main one being the function cvs-update), so it will know to load the pcl-cvs code on demand. Because Emacs always reads the default.el file when it starts up, that's where you need to list the pcl-cvs entry points.
Fortunately, pcl-cvs provides the necessary content for default.el. Simply put the contents of pcl-cvs-startup.el into default.el (or perhaps into your .emacs, if you're just installing this for yourself) and restart your Emacs.
You may also want to copy the .info files into your info tree and add pcl-cvs to the table of contents in the dir file.
Once installed, pcl-cvs is very easy to use. You just run the function cvs-update, and pcl-cvs brings up a buffer showing what files in your working copy have been modified or updated. From there, you can commit, do diffs, and so on.
Because cvs-update is the main entry point, I suggest that you bind it to a convenient key sequence before going any further. I have it bound to Ctrl+c v in my .emacs:
(global-set-key "\C-cv" 'cvs-update)
Otherwise, you can run it by typing M-x cvs-update (also known as Esc-x cvs-update).
When invoked, cvs-update runs cvs update as if in the directory of the file in the current buffer -- just as if you typed cvs update on the command line in that directory. Here's an example of what you might see inside Emacs:
PCL-CVS release 1.05 from CVS release $Name: $. Copyright (C) 1992, 1993 Per Cederqvist Pcl-cvs comes with absolutely no warranty; for details consult the manual. This is free software, and you are welcome to redistribute it under certain conditions; again, consult the TeXinfo manual for details. Modified ci README.txt Modified ci fish.c ---------- End ----
Two files have been locally modified (some versions of pcl-cvs show the subdirectories where the files are located). The next logical action is to commit one or both of the files, which is what the ci on each line means. To commit one of them, go to its line and type c. You are brought to a log message buffer, where you can type a log message as long as you want (real log message editing is the major advantage of pcl-cvs over the command line). Type Ctrl+c Ctrl+c when done to complete the commit.
If you want to commit multiple files at once, sharing a log message, first use m to mark the files that you intend to commit. An asterisk appears next to each file as you mark it:
PCL-CVS release 1.05 from CVS release $Name: $. Copyright (C) 1992, 1993 Per Cederqvist Pcl-cvs comes with absolutely no warranty; for details consult the manual. This is free software, and you are welcome to redistribute it under certain conditions; again, consult the TeXinfo manual for details. * Modified ci README.txt * Modified ci fish.c ---------- End ----
Now when you type c anywhere, it applies to all (and only) the marked files. Write the log message and commit them with Ctrl+c Ctrl+c as before.
You can also type d to run cvs diff on a file (or on marked files) and f to bring a file into Emacs for editing. Other commands are available; type Ctrl+h m in the update buffer to see what else you can do.
The pcl-cvs program has historically had an odd way of dealing with error and informational messages from CVS (although this may be corrected in the latest versions). When it encounters a message from CVS that it doesn't know about, it gets hysterical and throws you into a mail buffer, ready to send a pregenerated bug report to the author of pcl-cvs. Unfortunately, among the CVS messages that pcl-cvs may not know about are the ones associated with conflicting merges, which, although not common, certainly do occur from time to time.
If pcl-cvs suddenly dumps you into a mail buffer, don't panic. Read over the contents of the buffer carefully -- the offending CVS output should be in there somewhere. If it looks like a merge, you can just get rid of the mail buffer and rerun cvs-update. It should now succeed, because CVS won't output any merge messages (because the merge has already taken place).
(Update: this problem appears to have been fixed in more recent versions of pcl-cvs, so very probably you can ignore this entire warning.)
Although I may be giving you the impression that pcl-cvs is barely maintained and a risky investment, the instability appears to be temporary. Stefan Monnier is a responsive maintainer (I contacted him several times during the writing of this chapter, and he always answered right away; he is already making headway on some of the bugs in Version 2.9.6). Very likely by the time this is published, you will be able to download Version 2.9.7 or later with confidence.
In fact, I just now got an encouraging email on this topic from Greg Woods, a former maintainer of pcl-cvs, reprinted here with his permission:
From: email@example.com (Greg A. Woods) Subject: Re: pcl-cvs maintenance status, stability of recent "release"s? To: firstname.lastname@example.org Date: Sun, 29 Aug 1999 18:59:19 -0400 (EDT) [...] I've been using Stefan's releases for some time now, and indeed I have abandoned my own branch of it. He's done a lot of really good work on PCL-CVS and except for a few odd quirks in the 2.9.6 version I'm using daily now it is quite usable (and is approximately infinitely more usable with modern CVS than the one that was in the CVS distribution! ;-). I've added a pcl-cvs.README file to my FTP site to point out that the files there are indeed quite old (at least in Internet time! ;-) and to give a pointer to Stefan's FTP site too. [...]
In a later email, Greg said that the FSF is considering including pcl-cvs in their next release of Emacs (20.5), which would render most of the preceding installation advice obsolete. Sigh. It's hard to keep up with free software, sometimes.
Depends on: Perl
Authors: Tom Tromey (original author) and Pavel Roskin (current maintainer)
The suite of small programs called
cvsutils generally (although
not always) performs offline operations in the CVS working copy.
Offline operations are those that can be done without contacting the
repository, while still leaving the working copy in a consistent state
for the next time the repository is contacted. Offline behavior can be
extremely handy when your network connection to the repository is slow
The README file in Version 0.1.4 states:
The homepage of CVSU is http://www.typhoon.spb.ru/~proski/cvsu/ This address will change by the end of the year 1999.
I have placed a copy of cvsutils on the
red-bean.com FTP site
listed at the beginning of this section. When a new home address for
cvsutils is publicized, I'll include it there as well.
The cvsutils programs are listed below in approximate order of usefulness (according to my opinion), with the more useful ones coming first. Coincidentally, this also arranges them by safety. Safety is an issue because some of these utilities can, in their normal course of operation, cause you to lose local modifications or files from your working copy. Therefore, read the descriptions carefully before using these utilities.
This documentation is accurate as of Version 0.1.4. Be sure to read the README file in any later versions for more up-to-date information.
Danger level: None
Contacts repository: No
This does an offline cvs update by comparing the timestamps of files on
disk with their timestamps recorded in CVS/Entries. You can thus tell
which files have been locally modified and which files are not known to
be under CVS control. Unlike
cvs update, cvsu does not bring
down changes from the repository.
Although it can take various options, cvsu is most commonly invoked without any options:
floss$ cvsu ? ./bar ? ./chapter-10.html M ./chapter-10.sgml D ./out ? ./safe.sh D ./tools
The left-side codes are like the output of cvs update, except that
D means directory. This example shows that chapter-10.sgml has
been modified locally. What the example doesn't show is that cvsu ran
instantly, whereas a normal cvs update would have required half a minute
or so over my slow modem line. Run
floss$ cvsu --help
to see a list of options.
Danger level: Low to none
Contacts repository: No
This can simulate the working copy effects of cvs add and cvs remove, but without contacting the repository. Of course, you'd still have to commit the changes to make them take effect in the repository, but at least the add and remove commands themselves can be sped up this way. Here's how to use it
floss$ cvsdo add FILENAME
floss$ cvsdo remove FILENAME
To see a list of further options, run:
floss$ cvsdo --help
Danger level: Low
Contacts repository: No
This deals with a repository move by tweaking the working copy to point to the new repository. This is useful when a repository is copied en masse to a new location. When that happens, none of the revisions are affected, but the CVS/Root (and possibly the CVS/Repository) file of every working copy must be updated to point to the new location. Using cvschroot is a lot faster than checking out a new copy. Another advantage is that it doesn't lose your local changes.
floss$ cvschroot NEW_REPOS
floss$ cvschroot :pserver:email@example.com:/home/cvs/myproj
Danger level: Low to medium
Contacts repository: No
This removes all of the CVS/ administrative subdirectories in your working copy, leaving behind a tree similar to that created by cvs export.
Although you won't lose any local changes by using cvsrmadm, your working copy will no longer be a working copy.
Use with caution.
Danger level: Medium
Contacts repository: No
This removes all non-CVS-controlled files in your working copy. It does not undo any local changes to CVS-controlled files.
Use with caution.
Danger level: Medium to high
Contacts repository: Maybe
This is the complement of cvspurge. Instead of removing unknown files but keeping your local changes, cvsdiscard undoes any local changes (replacing those files with fresh copies from the repository), but keeps unknown files.
Use with extreme caution.
Danger level: High
Contacts repository: Maybe
This is the union of cvspurge and cvsdiscard. It undoes any local changes and removes unknown files from the working copy.
Use with truly paranoid caution.
This script is apparently incomplete and possibly may never be finished. (See the README file for details.)
Depends on: Perl
cvs2cl.pl condenses and reformats the output of cvs log to create a GNU-style ChangeLog file for your project. ChangeLogs are chronologically organized documents showing the change history of a project, with a format designed specifically for human-readability (see the following examples).
The problem with the
cvs log command is that it presents its
output on a per-file basis, with no acknowledgement that the same log
message, appearing at roughly the same time in different files, implies
that those revisions were all part of a single commit. Thus, reading
over log output to get an overview of project development is a hopeless
task -- you can really only see the history of one file at a time.
In the ChangeLog produced by cvs2cl.pl, identical log messages are unified, so that a single commit involving a group of files shows up as one entry. For example:
floss$ cvs2cl.pl -r cvs log: Logging . cvs log: Logging a-subdir cvs log: Logging a-subdir/subsubdir cvs log: Logging b-subdir floss$ cat ChangeLog ... 1999-08-29 05:44 jrandom * README (1.6), hello.c (2.1), a-subdir/whatever.c (2.1), a-subdir/subsubdir/fish.c (2.1): Committing from pcl-cvs 2.9, just for kicks. 1999-08-23 22:48 jrandom * README (1.5): [no log message] 1999-08-22 19:34 jrandom * README (1.4): trivial change ... floss$
The first entry shows that three files were committed at once, with the log message, "Committing from pcl-cvs 2.9, just for kicks.". (The -r option was used to show the revision number of each file associated with that log message.)
Like CVS itself, cvs2cl.pl takes the current directory as an implied argument but acts on individual files if given file name arguments. Following are a few of the most commonly used options.
--helpShow usage (including a complete list of options).
--revisionsShow revision numbers in output. If used in conjunction with -b, branches are shown as BRANCHNAME.N, where N is the revision on the branch.
--tagsShow tags (symbolic names) for revisions that have them.
--branchesShow the branch name for revisions on that branch. (See also -r.)
--global-opts OPTSPass OPTS as global arguments to cvs. Internally, cvs2cl.pl invokes cvs to get the raw log data; thus, OPTS are passed right after the cvs in that invocation. For example, to achieve quiet behavior and compression, you can do this:
floss$ cvs2cl.pl -g "-Q -z3"
--log-opts OPTSSimilar to -g, except that OPTS are passed as command options instead of global options. To generate a ChangeLog showing only commits that happened between July 26 and August 15, you can do this:
floss$ cvs2cl.pl -l "'-d1999-07-26<1999-08-15'"Notice the double-layered quoting -- this is necessary in Unix because the shell that invokes cvs log (inside cvs2cl.pl) interprets the
<as a shell redirection symbol. Therefore, the quotes have to be passed as part of the argument, making it necessary to surround the whole thing with an additional set of quotes.
--distributedPut an individual ChangeLog in each subdirectory, covering only commits in that subdirectory (as opposed to building one ChangeLog that covers the directory where cvs2cl.pl was invoked and all subdirectories underneath it).
Depends on: C compiler for installation; nothing for runtime
This program locks a CVS repository (either for reading or writing) in the same way that CVS does, so that CVS will honor the locks. This can be useful when, for example, you need to make a copy of the whole repository and want to avoid catching parts of commits or other people's lockfiles.
The cvslock distribution is packaged extremely well and can be installed according to the usual GNU procedures. Here's a transcript of an install session:
floss$ zcat cvslock-0.1.tar.gz | tar xvf - cvslock-0.1/ cvslock-0.1/Makefile.in cvslock-0.1/README cvslock-0.1/COPYING cvslock-0.1/Makefile.am cvslock-0.1/acconfig.h cvslock-0.1/aclocal.m4 cvslock-0.1/config.h.in cvslock-0.1/configure cvslock-0.1/configure.in cvslock-0.1/install-sh cvslock-0.1/missing cvslock-0.1/mkinstalldirs cvslock-0.1/stamp-h.in cvslock-0.1/cvslock.c cvslock-0.1/cvslock.1 cvslock-0.1/snprintf.c cvslock-0.1/cvslssh cvslock-0.1/VERSION floss$ cd cvslock-0.1 floss$ ./configure ... floss$ make gcc -DHAVE_CONFIG_H -I. -I. -I. -g -O2 -c cvslock.c gcc -g -O2 -o cvslock cvslock.o floss$ make install ... floss$
(Note that you may have to do the make install step as root).
Now, cvslock is installed as /usr/local/bin/cvslock. When you invoke it, you can specify the repository with -d or via the $CVSROOT environment variable, just as with CVS itself (the following examples use -d). Its only required argument is the name of the directory to lock, relative to the top of the repository. That directory and all of its subdirectories will be locked. In this example, there are no subdirectories, so only one lockfile is created:
floss$ ls /usr/local/newrepos/myproj/b-subdir/ random.c,v floss$ cvslock -d /usr/local/newrepos myproj/b-subdir floss$ ls /usr/local/newrepos/myproj/b-subdir/ #cvs.rfl.cvslock.floss.27378 random.c,v floss$ cvslock -u -p 27378 -d /usr/local/newrepos myproj/b-subdir floss$ ls /usr/local/newrepos/myproj/b-subdir/ random.c,v floss$
Notice that when I cleared the lock (-u for
unlock), I had to
-p 27378. That's because cvslock uses Unix process
IDs when creating lockfile names to ensure that its locks are unique.
When you unlock, you have to tell cvslock which lock instance to remove,
even if there's only one instance present. Thus, the -p flag tells
cvslock which previous instance of itself it's cleaning up after (you
can use -p with or without -u, though).
If you're going to be working in the repository for a while, doing
various operations directly in the file system, you can use the -s
option to have cvslock start up a new shell for you. It then consults
$SHELL environment variable in your current shell to
determine which shell to use:
floss$ cvslock -s -d /usr/local/newrepos myproj
The locks remain present until you exit the shell, at which time they are automatically removed. You can also use the -c option to execute a command while the repository is locked. Just as with -s, the locks are put in place before the command starts and removed when it's finished. In the following example, we lock the repository just long enough to display a listing of all of the lockfiles:
floss$ cvslock -c 'find . -name "*cvslock*" ' -d /usr/local/newrepos myproj cvslock: '/usr/local/newrepos/myproj' locked successfully. cvslock: Starting 'find . -name "*cvslock*" -print'... ./a-subdir/subsubdir/#cvs.rfl.cvslock.floss.27452 ./a-subdir/#cvs.rfl.cvslock.floss.27452 ./b-subdir/#cvs.rfl.cvslock.floss.27452 ./#cvs.rfl.cvslock.floss.27452 floss$ find /usr/local/newrepos/myproj -name "*cvslock*" -print floss$
The command (the argument to the -c option) is run with the specified repository directory as its working directory.
By default, cvslock creates read-locks. You can tell it to use write-locks instead by passing the -W option. (You can pass -R to specify read-locks, but that's the default anyway.) Always remove any locks when you're finished, so that other users' CVS processes don't wait needlessly.
Note that cvslock must be run on the machine where the repository
resides -- you cannot specify a remote repository. (For more
man cvslock, which is a manual page
installed when you ran
Many other third-party packages are available for CVS. Following are pointers to some of these.
CVSUp is an efficient generic mirroring tool with special built-in support for mirroring CVS repositories. The FreeBSD operating system uses it to distribute changes from their master repository, so users can keep up to date conveniently.
For more information on CVSUp in general, check out http://www.polstra.com/projects/freeware/CVSup/.
For its use in FreeBSD in particular, see http://www.freebsd.org/handbook/synching.html#CVSUP.
CVSWeb provides a Web interface to browsing CVS repositories. A more accurate name might be "RCSWeb", because what it actually does is allow you to browse revisions directly in a repository, viewing log messages and diffs. Although I've never found it to be a particularly compelling interface myself, I have to admit that it is intuitive enough and a lot of sites use it.
Although the software was originally written by Bill Fenner, the version most actively under development right now seems to be Henner Zeller's, at http://linux.fh-heilbronn.de/~zeller/cgi/cvsweb.cgi/.
You may also want to visit Fenner's original site at http://www.freebsd.org/~fenner/cvsweb/ and possibly Cyclic Software's summary of the CVSWeb scene at http://www.cyclic.com/cyclic-pages/web-cvsweb.html.
Finally, if you'd like to see CVSWeb in action, a good example can be browsed at http://sourceware.cygnus.com/cgi-bin/cvsweb.cgi/.
As mentioned in section Repository Administration, a number of third-party tools are shipped with CVS and are collected in the contrib/ directory. Although I'm not aware of any formal rule for determining which tools are distributed with CVS, an effort may be in process to gather most of the widely used third-party tools and put them in contrib/ so people know where to find them. Until that happens, the best way to find such tools is to look in contrib/, look at various CVS Web sites, and ask on the mailing list.
CVS can at times seem like a bewildering collection of improvised standards. There's RCS format, various output formats (history, annotate, log, update, and so on), several repository administrative file formats, working copy administrative file formats, the client/server protocol, the lockfile protocol.... (Are you numb yet? I could keep going, you know.)
Fortunately, these standards remain fairly consistent from release to release -- so if you're trying to write a tool to work with CVS, you at least don't have to worry about hitting a moving target. For every internal standard, there are usually a few people on the firstname.lastname@example.org mailing list who know it extremely well (several of them helped me out during the writing of this book). There is also the documentation that comes with the CVS distribution (especially doc/cvs.texinfo, doc/cvsclient.texi, and doc/RCSFILES). Finally, there is the CVS source code itself, the last word on any question of implementation or behavior.
With all of this at your disposal, there's no reason to hesitate. If you can think of some utility that would make your life with CVS easier, go ahead and write it -- chances are other people have been wanting it, too. Unlike a change to CVS itself, a small, standalone external utility can get wide distribution very quickly, resulting in quicker feedback for its author and faster bug fixes for all of the users.
Go to the first, previous, next, last section, table of contents.