Actually, I’d love to say that I’ve moved completely to using git instead of CVS, but the truth of the matter is that, for a recent project where I’m just trying to consolidate a whole bunch of admin scripts, organize them under one (managed) roof, and (most importantly) get a bunch of admins on board using it, CVS is really probably the way to go. Besides, there’s no branching and merging going on, all of the development is internal, and for simple stuff like this, CVS is really just fine.
The one thing I used to hate about CVS is that it seemed like every time I switched gears from doing some project not involving it to one that used it heavily, I would have to read the whole manual all over again. One thing that helps me remember things is writing about them, so here’s a cheat sheet full of things that I do either regularly, or occasionally enough to be annoying ;-)
For the duration of this post, we’ll work with a project called ‘foobrew’, which lives on a remote CVS server. This isn’t meant to be a total n00b intro to CVS, so I’ll assume you know the basics like how to set your CVS_RSH environment variable, for example.
Checking out a repository, or part of one
If you just want to check out the entire project from a remote CVS server, you’d simply run this command:
cvs -d :ext:firstname.lastname@example.org:/cvs foobrew
This will download every single file in the source tree into a directory under the one you ran this command from called ‘foobrew’. One of the projects I’ve imported into CVS has various modules that are worked on by different people. If someone only wants to write code for one module, they can easily check out only one module from the repository. For example, to get the ‘malt’ module from the ‘foobrew’ repository, you could run this command:
cvs -d :ext:email@example.com:/cvs malt
Of course, maybe the module hasn’t yet been defined, but you know that there’s a directory called ‘malt’ in your repository, and that’s what you’re interested in. Well, in that case, you just alter the above command a bit:
cvs -d :ext:firstname.lastname@example.org:/cvs foobrew/malt
Both of those commands result in a directory being created locally called ‘malt’.
Adding to a repository with ‘cvs add’… or not
You don’t *have* to use ‘cvs add’ to add stuff to a repository, but sometimes it’s the easiest way to do what you need. If you have already checked out the project, and you want to add a file to the project, it’s not enough to just copy the file into the right directory. You have to tell the CVS server that you want the file to be managed using CVS, using ‘cvs add’, and then you have to actually check the file in using ‘cvs commit’. So, once you’ve copied the file into place, you would do this:
cvs add README.txt
cvs commit README.txt
If the file you want to add is a binary file, only the syntax of the ‘cvs add’ command changes:
cvs add -kb somefile.bin
Using ‘-kb’ tells the CVS server to treat this a bit differently by *not* putting identification strings in the file that could render the binary file un-runnable the next time you check it out of the repository.
The above assume that you’ve checked out the repository, which you might not want to do. For example, if you have a directory full of code you’d like to add to an existing repository, you can add it without first doing a checkout like this:
cvs -d :ext:email@example.com:/cvs import foobrew/mycode bkj start
This will create the ‘mycode’ directory under our top-level project directory on the remote server. The ‘bkj’ and ‘start’ arguments are a vendor tag and release tag, respectively, and are required whether you make use of them or not. The use of these tags is out of the scope of this document, but I’ll write about it in another one later :-) In general, if you need to use these tags, start looking at using git ;-P
Another option that might be easy enough is to just check out the top level directory of the project, and then use ‘cvs add’ to add your files. If you only want to check out the top level directory of the project, run this command:
cvs -d :ext:firstname.lastname@example.org:/cvs checkout -l foobrew
The ‘modules’ file
If you want to find out what modules are available, or you want to create a module, you can check out the ‘CVSROOT/modules’ file from any CVS repository, and then inspect it or edit it. Since you’d presumably inspect it before editing it, I’ll show here how to create a simple module:
cvs checkout CVSROOT/modules
- open the ‘modules’ file, and add a line like this to define a module called ‘hops’
- save the file, and run
cvs commit modulesto commit the change.
cvs release -d CVSROOTto release the CVSROOT directory and remove it from your working copy (since it isn’t of general use on a day-to-day basis).
One nice thing about CVS is that you can enforce accountability with it. You can give everyone an account on the CVS server and see who made what changes when. On one project, the code needs to be checked out to a directory where only root has write access. So create a read-only user on the server for that user so they can check out the code. But then what happens if I discover a problem in the working copy of the code? Well, generally you’d just make the edit in place and run ‘cvs commit’, but that’s not going to work in this case because by default, CVS uses the credentials that were used to check out the code, which was done in this case by a read-only user. In this case, I need to provide my *own* credentials on the command line to override the ones that were stored locally during the checkout. This is done just like any other command that requires credentials. I just put this note here to remind myself that this is possible:
cvs -d :ext:email@example.com:/cvs commit