I recently received an email requesting that I write an article about CVS and how to use it with Sourceforge.
Hmmm, well...I'd been planning to write something about CVS anyway, but more in the way of a developer's guide for the website.
Still, those plans had been sitting idle for many weeks while I worked on other stuff, so maybe a newsletter article
wouldn't be such a bad idea after all -- at least it would get me to finally put something down on the subject.
There's lots of information out there about CVS, so I don't intend to write a full treatise on the subject. But I do
want to cover the basics of getting it running and using common commands. By no means am I a CVS expert (to put it mildly),
but, in a way, that's a good thing as far as this article goes -- it means that I won't bowl you over with technical mumbo jumbo
or try to impress you with some deviously subtle tricks. Nope, I just want to explain the major points and, hopefully, get
some people up and running on this valuable tool. Maybe even convince you why it's a good idea.
Most of what I've written here comes from a combination of trial and error and reading online CVS docs and tutorials. One of the best,
and a good source for alot of what I've learned is Red Bean's CVS Book.
Use this doc for a truly thorough explanation of CVS. I would consider it the ultimate reference for any questions you might have.
As many points as this article covers, it really only scratches the surface of this large topic.
While writing this piece, I assumed the target audience would be largely BeOS developers who are on or plan to be on a
Sourceforge project. Some of the info, however, especially on anonymous CVS, can be used by anyone. The OpenBeOS project and its CVS repository
is used as an example for many points (including many of the sample command lines), but most of the info presented here is not specific to any
CVS is a program for tracking and controlling the content of a group of related files. Consider that you have a program consisting of several
dozen source code files. How would you go about making changes to that code base -- for example, adding a new feature that would
require altering multiple files? If you had either brains or bitter experience (or both) on your side, you'd
create a new copy of the source code tree and edit that one. Only when the new code appeared to be in good shape would you
replace (or merge with) the older code.
CVS is also based on that simple idea. There is one master directory of files that contains the best or most up-to-date version
of all files. It is called the repository. From this repository you can checkout individual files or entire directories. Checking out
just means making a temporary copy elsewhere so that you can edit safely. No matter what bungled-up-of-a-mess you make of the
working copy, the repository remains unharmed. Whenever the new versions are in good shape and working correctly, you can check them into the
repository -- which just copies back the updated versions.
Repository Working Copy
+--------------+ ===> Checkout ===> +--------------+
| /FooDir | | /FooDir |
| /SubDir1 | | /SubDir1 |
| /SubDir2 | | /SubDir2 | (Edit Here)
| /SubDir3 | | /SubDir3 |
| . . . | | . . . |
+--------------+ <=== Checkin <=== +--------------+
The initial working copy is almost a clone of the directory from the repository. The difference is that the repository stores version
info inside the files themselves. The file names are altered as well, to reflect this. For example, when
imported into the repository, it becomes
file.c,v and contains embedded version info at the top and bottom of the file.
But when you checkout the file, it becomes the regular
file.c again inside the working copy, without the embedded info.
Naturally, you can have many different working copies checked out from the same repository. This is usually done for the purpose
of working independently on different features. It may be one programmer working on several branches, or multiple programmers each working
on their own copy, or a mix of the above.
+==> CopyA (working on feature A)
+==> CopyB (working on feature B)
+==> CopyC (working on feature C)
You can use CVS to manage your own programming projects locally on your machine -- i.e. the repository and the working copy are
just different directories on your computer. There are many advantages to this, some of which I'll discuss later in this
article. But the real power of CVS comes from using it in a collaborative way with others across a network. For this, you
will also need a program called SSH. Sourceforge requires SSH in order to checkin files to the repository on the server.
SSH handles the login to the server and then encrypts/decrypts the data sent along the network for security.
First, you will need to get BeOS versions of CVS and SSH. There are several of these available. I don't want to list all the
URLs for these here as the info may quickly become outdated -- refer to the 'Resources' section of the website for the
latest on this. However, in the interest of disclosure, I'll tell you which versions of these programs that I am using:
(Version 1.10.7 from Be)
(Andreas Bobaks port of ssh-1.2.26 )
Mind you, I'm not saying that you have to use these versions or that they're better than the others ones available.
These are simply the ones that I've used and so I know that they work just fine.
Once you have installed these programs, be sure and copy the binaries 'cvs' and 'ssh' (or at least a link to them) to your
/boot/home/config/bin directory. This is to make your life easier -- you don't want to spell out the full path
to these programs every time you type a command.
Next, you'll need to register with Sourceforge. That is, you'll need to setup a username/password. Once you've done this, you
can join any number of Sourceforge projects. If you don't already have a user account with Sourceforge, go to their home page
and click on the 'Register' link. It's simple and takes just a few minutes.
Now you will need to get added to a project. This is handled by the project admin(s). For OpenBeOS, this is Michael Phipps.
New members to OpenBeOS will need to contact Michael and have him add their username to Sourceforge's internal list of members
for the project. Once this is done, you'll have CVS write access and will be able to checkin source code to the OpenBeOS
There is one final step, however, before you can start using SSH with CVS. You must login once to the Sourceforge
CVS server. Use the following command:
Of course, put your Sourceforge username in the command. The first time you attempt to ssh into a new server, you'll receive
Host key not found from the list of known hosts.
Are you sure you want to continue connecting (yes/no)?
Type in "yes" and press ENTER. SSH will store "cvs.open-beos.sf.net" as one of the known hosts in the file
Then you'll be prompted for your password. Enter that and you'll be logged onto
the CVS server, receive an error message (about not having access rights to the files), and then logged off. Don't worry about
the error message -- it's simply stating that you can't alter the files in the repository directly via a shell. That's fine,
because you'll only be making changes to the repository via CVS. The point of this is that the very act of trying to log in causes
Sourceforge to create a
/users/username entry for you on the server. This will allow you to perform CVS checkins
later (that is, provided you have been added to the project member list).
Probably the first thing you would like to do is checkout some code. You'll need to specify the directory that you want to fetch.
Let's say that you want to checkout the game kit from the OpenBeOS repository. It is located in a folder called 'game_kit',
so you should be able to run the following command:
cvs checkout game_kit
Notice that I said "should be able". You can make the command above work, but not until you've taken care of some details
regarding the repository path. In order to checkout from a repository, CVS needs to know where the repository is. You specify
that with the "-d" option. For example:
cvs -d /boot/home/repos checkout my_file
This would work if you happen to have a repository on your local
/boot/home/repos directory. But for grabbing
the files from the Sourceforge CVS server, you need to specify its network name. This takes the form of:
There are several network access methods available for CVS. The two most common are 'pserver' and 'ext'. Pserver stands for
"password authentication server". This program is already resident on the CVS server, so you don't need to obtain it.
The trouble with pserver is that is uses a relatively unsafe method of storing passwords on the server, so it is not recommended
for anything but anonymous logins. But for that purpose, it's very useful. That is, anyone, with a CVS client can login
anonymously to any Sourceforge project repository using pserver and checkout the source code.
One curiosity about pserver is that you must login first. No other network access method requires this. If you are logging on
as an anonymous user, you don't need to enter any password -- just hit ENTER at the password prompt. Here are the commands for
checking out the game kit from the OpenBeOS repository:
cvs -d :pserver:email@example.com:/cvsroot/open-beos login
cvs -d :pserver:firstname.lastname@example.org:/cvsroot/open-beos checkout game_kit
Eek! That's alot of text to type in. Fortunately you can save yourself some work. You can specify the location of the
CVS repository using the CVSROOT environment variable. When you open a new Terminal window, type in the following command:
Now you can use the simple '
cvs checkout game_kit' command from above.
You can get simpler still -- you can use "co" instead of "checkout".
Just specify a different directory name to checkout something else.
If you want to checkout the entire repository, just use "." for the path.
Here's a simple shell script that I use to checkout the entire repository and store
it in a local directory called "cvsall" in my
# check out the entire CVS repository for OpenBeOS
cvs co .
Anonymous CVS is fine if you just want to checkout files. But to checkin files as well, you'll need SSH.
SSH stands for secure shell. This is because it is most commonly used as a remote shell client, similar to telnet,
but with better security. But it can also be used by CVS to handle secure communications with a server.
Sourceforge requires SSH in order to checkin files to their CVS server, so it's a necessity.
SSH logs into the server, delivers the password (after prompting you for it), does some handshaking for setting
up the encryption method, then sends/receives the CVS commands across the network in encrypted format. There are a
number of encryption techniques that any SSH client will have available. The default one is triple DES (3DES) -- i.e.
every SSH client is required to support 3DES as a fallback in case no other encryption technique is available.
Sourceforge's CVS server uses 3DES, so this should not be an issue.
Whenever you use SSH to access the CVS server, you need to use the 'ext' access method. Ext stands for "external program".
In this case, the external program is SSH. To let CVS know it should use SSH for the remote shell, set the CVS_RSH
environment variable. While you're at it, set the CVSROOT environment variable as well, but, unlike
the sample shell script above, remove the ":pserver:" at the front. You could replace it with ":ext:" -- however, the
'ext' access method is the default method for CVS, so if you don't specify one, 'ext' will be used anyway. Here are the
commands for setting the environment:
Of course, put in your own username in the text above.
Typing in these two lines every time you open a Terminal window is not going to be alot of fun, so save yourself the effort.
Put these into your ".profile" file. If you don't already have a file called
/boot/home/.profile then create it.
It is simply a text file. Add the commands above, and you are set.
There are a couple of annoyances in using SSH with CVS that you should be aware of.
First, you need to use the "-z3" command option for accessing remote servers. This is a compression flag that is used for
transmitting the data across a network. I'm not sure that other compression settings such as "-z4" or "-z5" won't work as well,
but "-z3" is the one recommended by Sourceforge, so that's what I use. For example:
cvs -z3 co app_kit
If you don't use this flag, the command will still get executed, but SSH never returns control to the CVS program, and thus
you don't ever get back to a command prompt. You have to kill the process (Control-C) to continue. So you definitely want
to use it. But typing in "-z3" before every CVS command gets tiresome very quickly. So it's ".profile" to the rescue again.
Add the following line to
/boot/home/.profile and you're saved from all that icky typing:
alias cvs="cvs -z3"
The other annoyance, though a minor one, is that SSH uses a pty (pseudo-terminal) for communicating with CVS. This in itself
is no big deal, but it creates a somewhat irritating side-effect. When you resize the Terminal window while doing remote CVS,
a 'resize window' command is sent to SSH which then gets confused (probably mistakes it for bogus encrypted data) and loses
the connection to the server. I'm bad about this because I tend to 'futz' around, resizing windows while waiting for the transfer
to finish. The lesson here is, resize the window *between* executing CVS commands.
The CVS Development Cycle
Now that you have CVS and SSH, initialized these programs, created your Sourceforge account, secured CVS write access, and set your
local .profile, you are finally ready to start using CVS for real work. After all the preliminary stuff from above, it's pretty
simple from here on out.
The basic pattern of using CVS is this: checkout, edit, checkin.
This is the development cycle you will use over and over while
working on a project. You checkout the files/folders relating to the work that you are
assigned to. You then edit local copies on your computer. Whenever you've got a good working new version, you checkin the
source code to the CVS repository.
CVS will keep track of what changes were made and when. It will allow you to back up to a
previous version if you find out you didn't like the changes after all. All of your new work is marked with version info and
tagged with comments (by you) explaining the changes.
We've already covered checking out files. So how do you check them back in? You use the "commit" command if the file already
exists in the repository. If it's a new file, first "add" the file, then "commit" it. For example:
cvs add my_new_file
cvs commit -m "initial checkin" my_new_file
How does CVS know where to put the file? Because it knows the directory structure of the folder you checked out. Consider the
diagram at the top of this article. The working copy you checkout is a clone (minus the embedded tracking info) of the
directory tree from the repository. If you create several new files, or even a new directory with files, the "add" command
will copy the structure from your working copy back to the repository to make it match your local setup.
I already mentioned that you can use "co" as an abbreviation for "checkout" command. Well, you can also use "ci" as the
short form for "commit". This is fairly clean and symmetrical -- "co" to checkout, "ci" to checkin. So the CVS development
cycle will basically be:
cvs co your_assignment
(... edit/test/debug like a madman ...)
cvs ci -m "added feature X" your_assignment
Whenever you checkin files, you must make some kind of comment about the change. You could just put in "blah, blah, blah", but
don't do that. It is truly a useful feature to have additions/fixes/updates marked with meaningful explanations. If the file
is new, the phrase "initial checkin" is somewhat standard (saves you from having to think up something every time). But for
updated files, type in something descriptive and useful.
The "-m" option precedes the comment text for any commits. If you forget to use this option (or don't want to), you will be
automatically thrown into a vi session. Vi is a prehistoric Unix text editor dating from the early Jurassic period (hehe, couldn't resist).
I'm sure there are fans of vi out there... but I'm not one of them. However, you don't need to know much in order to enter
a few lines of text and then exit. So here is my *very* brief summary of using vi to edit text:
Vi operates in two modes: command, and insert. Insert mode is where you type in the text normally. Command mode will interpret
keystrokes as commands. When you first enter vi, you will be in command mode. To get to insert mode, type 'a'. Now you can
type in your comments and edit your little heart out. When you're through, hit the ESC key to go back to command mode. Now type
'ZZ' (i.e. hold down the shift key and type 'Z' twice)... this will save your work and exit. That's not too bad.
Here's the world's smallest vi primer again, in summary:
Enter Vi Session:
a ==> change to insert mode
...edit away until finished...
ESC ==> change back to command mode
ZZ ==> save work and exit
Btw, you can specify a different editor for putting in comments. Just use the "-e" option and specify the editor path. This may or
may not be worth it. For me, using the few simple keystrokes above to edit with vi is sufficient to get my comments down. You're
not writing a novel, after all.
If you type in:
You will see all the available commands you can use in CVS.
This will show you all the shortened, abbreviated forms you can use for those commands.
Also, particularly useful is:
cvs -H command
This will show you all the options that can be used with that particular command.
By far the most common commands you are likely to use are "co" and "ci", since checking out and checking in files
is the main activity. But a few others are useful.
The "update" command updates your working copy to the latest version from the repository. But then again, this is
what "co" does anyway: if there is no working copy, one is created, otherwise that copy is updated. In other words,
the "checkout" command does everything the "update" command does plus it handles creating new working copies.
For this reason, I never use "update" -- "co" handles all your updating needs.
The "diff" command will let you see the difference between your local file in the working copy and the original in
the repository. As such, it will show what changes you have made to files since the last checkout.
The "log" command is very useful. It will show you every checkin made to the repository for the directory which you
have checked out: who made it, on what date, the revision number, the checkin comments. It's a complete history of
activity for the source tree.
The "import" command is used to put files into a new repository. It can also be used to create a new branch of an
existing repository. You can always use "add" to add files, but "import" handles large numbers of new files more systematically.
The "remove" command, naturally, is used to remove files. What if you want to remove an entire directory? Well, you
can do so for your working copy, but not for the repository itself. More on this later.
There are other commands, some covering more esoteric functions and some relating to admin tasks. I won't cover these
in this article.
When you first checkout a file from the repository, it is an exact copy of the original (well, excepting, of course,
the embedded version info). But as you edit the file, making changes, your working copy and the repository are no longer in synch.
If you try to checkout the file again, you'll get a merge conflict.
Here's a simple test: checkout one of the OpenBeOS kits. Then load one of the files into your editor and make a minor
change and save. Now checkout this same kit again. You'll notice that, for the edited file, instead of the usual 'U'
at the beginning of the status line, there is an 'M' instead. This lets you know there is a merge conflict between the
version of the file on your working copy and the repository. This conflict will remain until you checkin the new version
of your file (or revert to the previous one locally).
If you run "diff" on the file in question, you can see your changes. For example:
cvs diff edited_file
This will display all the lines in the file that you changed.
This is how CVS works. It doesn't fix problems for you. It merely keeps very accurate records on what you (and others)
have done and reports any conflicts it finds. It's not an artificial intelligence agent that attempts to work out
remedies for you. It's just a flawless bookkeeper, or better yet, a tireless secretary, constantly taking notes and
letting you know when there's a problem. But it's up to you to decide how to handle the conflict. You are in charge.
If several developers are working on the same source tree of the project and checkin different versions of the same file,
CVS does not try to "fix" the problem itself or attempt to decide which is better. It merely combines the two versions.
The next time either of the developers checks out the file again, they will get the merge conflict. By running the
"diff" command as above, they can both see where they have deviated from each other. They can then contact each other
and hash out what changes should be made, whose version is best, etc.
Removing files and directories
The question always comes up shortly after someone starts working with CVS, "how do I get rid of files?"
Well, it's easy enough, in a way, using the "remove" (or "rm") command. For example:
cvs rm some_file
This will remove '
some_file' from the repository. As always, the location of the file is based on its
relative location within the working copy -- e.g. if you're working on the
/src/lib/foo subdirectory of
the working copy, then it will remove
/src/lib/foo/some_file from the repository source tree.
Did I say that it will remove the file from the repository? Well, that's almost true. Actually, the file is moved
into an "attic". This is like a trash bin directory. When browsing the CVS repository, you'll notice that deleted
files are actually still there, but tucked away in an
Attic/ subdirectory. At least that makes sense
because it makes it possible to recover the files later. Besides, the next time you do a checkout, a deleted file
sitting in the attic is not copied over. So for all appearances, the file is really gone.
But it's not so clean for directories. CVS stores tracking/version info for files, but not for directories. It's true
that it knows about and understands the directory structure where the files reside, but there is no actual version info
for directories themselves. The effect of this is that you can't remove directories from the repository using just CVS
commands. You can remove them from your working copy. That's as close as you can get.
To remove a directory from your working copy, you must delete all the files in it. You don't have to do this
manually, because there is a "-f" option that will delete the contained files for you before removing the directory.
Combine this with the "-R" option for recursing thru subdirectories and you can swat an entire directory with one
cvs rm -fR some_dir
All the files within '
some_dir' and every subdirectory below it will be removed (i.e. put in the attic), but
the directories and subdirectories below are all still there. They're empty but still there.
You can use the "-P" option when checking out: this will prune empty directories -- i.e. not put them into the working copy.
some_dir' will not appear in a checked out working copy. But it's still
really there in the repository. This means anyone else who checks out a copy will still see '
some_dir' unless they
also use "-P" when checking out. And even if everyone always uses the prune option when doing checkouts, you can
still see the directories when using the online CVS browser that Sourceforge provides. It really is quite annoying.
Mind you, it's not impossible to get rid of directories. You just can't do it using CVS commands. If you really wanted to
kill a directory very badly, you could ask the project admin to handle this for you. For example, an OpenBeOS developer could
email Michael Phipps and ask him to please axe directory_foo. Michael can't remove the directory himself -- he doesn't have
any more access to the server files than anyone else. But as project admin, he could send an email to Sourceforge tech support
and say "excuse me, could you please kill 'directory_foo' in the OpenBeOS CVS repository". This isn't something that the CVS
maintainers at Sourceforge want to get alot of requests for, and Michael does not really want to make the request either. So
don't expect him to cover for you.
The moral here is: be very careful before adding any subdirectories to the CVS repository. CVS commands make it easy to create
new directories, but practically impossible to get rid of them once created. Think about your directory structure carefully and make
sure it will expand with usage and time. And don't be surprised if, nevertheless, you get stuck with empty, 'dead' directories
somewhere down the line.
Testing with a local repository
Ok, we've covered alot of the basic ground so far. You know enough to start using CVS and getting into the CVS development cycle.
However, perhaps you're still a bit concerned about messing with the "real" repository at Sourceforge while trying to get
familiar with how CVS works. Well, in that case, you should create a local repository.
If you have a CVS program, you can create your own CVS repository just a surely as Sourceforge does for other projects. And since you
don't have to make the files available on a server, it's very easy to administer... it's just local files on your computer.
You won't even have to worry about the problem of removing directories, because you own all the files and can
prune the repository to your heart's content. It's a pretty easy and safe way to become familiar with CVS. You'll be able to see
all the changes from both sides of the fence: repository and working copy. Try it, you'll like it!
Ok, before you start, decide where you would like to put the repository. As an example, let's assume you decide to put it in
/boot/home/test/repos. Now open a Terminal window and type in the following:
There, you now have your very own spanking new repository. Of course, it doesn't have much yet... just the CVSROOT folder with stub
versions of the basic admin files. All you need now is to import some files.
You could import files from any directory on your computer. But I don't know what you have on your computer.
Since we've played around with sample command lines for checking out the OpenBeOS game kit, let's assume that this has been done.
And assume that this has been checked out into the home directory, i.e. you have a
This gives you a code base to work with and play around. So enter the following into the Terminal window:
cvs import -m "initial checkin" game_stuff mybranch game_stuff_1_0
This assumes that you're in the same Terminal window as above and thus the CVSROOT environment variable still points to
/boot/home/test/repos. If not, retype the export command or use the "-d" option to set the repository path in the
The last three parameters (after the comment text) of the import command are not obvious. First is the name of the folder in the
repository where the imported files will be stored. The next is a tag designating this particular branch of the source tree.
Since this is just a test repository, you could name it just about anything. The last param is a release version tag. To be honest,
I'm not really sure what its purpose is. I think it's meant to be a symbolic tag containing something about the release version that
this branch designates. Again, since
this is only a test repository, you can use about anything. Just don't use the '.' character in tag names.
There, now you have a repository full of source code. You can continue to add/import more files if you like. You can checkout/checkin
files to/from working copies located elsewhere on your computer. In nearly all respects, you can treat it the same as you would the remote
repository at Sourceforge. Only this one is totally in your control.
If you want to test with this repository over a period of time, it may be useful to add another alias in your ".profile" to avoid
constantly specifying the repository location. You could use:
alias tcvs="cvs -d ~/test/repos"
This uses a slightly different command name, tcvs, to let you know you are working with your local test repository.
Here's a recap of all the commands so far that I've recommended for your ".profile":
alias tcvs="cvs -d ~/test/repos"
alias cvs="cvs -z3"
The 'tcvs' alias is placed before the 'cvs' alias so that the aliased version isn't substituted first. This would cause the tcvs
command to use the "-z3" flag as well, which isn't needed for local file copying. Probably wouldn't hurt though.
With a local test repository in place, you can truly have fun and try every command with reckless abandon. You can clearly see what
effects each command actually produces. Once you've become familiar with how CVS operates, doing the "real" updates on the
Sourceforge repository will be a piece of cake.
Getting into the CVS habit
Before I finish this article, I'd like to make some final comments...
You may be surprised to hear this, but using CVS to regularly checkin code is good for you. It belongs right up there with
exercising, brushing your teeth, and eating green leafy vegetables.
But why is this? What's so great about CVS? Well, it's not so much CVS itself as any good source control system, but we're
talking about CVS in this article. The point is, using CVS causes you to be a better administrator of your code.
Programmers know that they should routinely do certain things such as: make regular backups, comment all changes,
develop and test incrementally, plan carefully for future directions, separate new experimental code from proven tested code,
document and communicate the progress to others, etc.
These practices are the lore of many seasoned programmers and have been written about extensively. Most
programmers know that they should do these things, because it will make them more professional, more reliable, possibly even
speedier in their craft. But knowing you should do this and actually doing it are two different things (just like exercising,
brushing your teeth, and eating green leafy vegetables).
But using CVS will force you to attend to many of these items. By continually checking in code, you don't have to worry such much
about backups, because the repository will store previous versions. When you checkin the code, you are forced to comment the
changes. The cycle of checkout/edit/checkin encourages you to develop in an incremental style where you tackle problems in
little bites. Because you share the repository with others who are working on similar tasks, you must think more carefully
about your design and how it meets future needs. The very process of checking out code helps separate the development of
new code from the existing, solid base. And all the features just listed combined with the open availabililty of the
repository makes documentation and communication of the progress almost a built-in side effect of using source control.
I think that some (many?) programmers on the OpenBeOS project have been timid about using CVS because they have the idea
that only finished, polished, ready-to-distribute source code should be checked in. This means that they will spend alot of
time slaving away in secret on their local computer without any of the benefits just mentioned. Then, finally, after much
time has passed, when they judge the code ready for public inspection, they will checkin to the repository. Unfortunately,
this is as wrong as you can get. If you only use the repository as a final resting place for source code, then CVS itself has been
rendered totally useless.
You see, the whole point of source control is to assist you in the process of developing quality code. Think about it:
no one sits down and types out the final version of their source code files on their first attempt. Hardly.
Software construction is an iterative process: you create an initial version, test it, make fixes, and test again.
Then you add more features and repeat the process over. Source control was created precisely to help assist in this very
cycle; to help automate the drudgery tasks while keeping the code well managed. If you don't use CVS and the project repository
for developing the code, you are missing out on precisely the benefits it was designed to produce.
Even if a programmer is working on a really experimental, off-the-beaten path prototype, he can still use CVS to assist with
the development. Experimental or prototype subdirectories can be created in the repository for storing and working on this type
of code. As it matures, it can be moved to more stable sections of the repository. The nature of the work should not hinder
using CVS. It can be useful for any software development because the process is always the same, regardless of the content or
purpose of the source code.
So don't lightly dismiss the idea of using CVS to assist with program development. Don't be afraid to regularly checkin files
to the repository. The process will become fairly painless, even second nature after awhile. Then you can reap the benefits of
doing things the smart way.