Keyword expansion: why RCS rewrites files when you commit them
Given my previous entry, you might wonder why RCS does such a crazy thing as deleting and recreate files when you just make a commit (in RCS terms, a checkin) when modern version control systems don't do this. The answer turns out to be pretty simple: keyword expansion. Specifically, that RCS supports keyword expansion and modern version control systems don't.
RCS has a feature where you can embed magic keywords in your source code that are automatically expanded to various pieces of information when RCS checks out your file. The classical example is various identification of the file version; the traditional use for this is embedding it in C source as a static string, so that it will appear in the binary and can later be extracted to determine which source version was used to build some random binary version.
(Assuming, that is, that the binary was built from unedited source files, with no uncommitted edits. You may be starting to see the problems here.)
This sounds like a very convenient feature, but it has a cost; it means that the file's proper contents change every time you commit it. Thus, every time you commit a file you (may) need to update the checked out version in order to make its keyword expansions have their proper value. Which means deleting and recreating files a lot, at least if you are RCS.
(In theory RCS could notice that the committed file does not have any keywords to expand and thus doesn't need to be recreated, which is the usual case these days. In practice it is not that smart.)
This also complicates various other aspects of RCS; the obvious one is checking for differences between live files and the repository. This needs to scan the live file for keywords and de-expand them in order to avoid spurious differences, which naturally slows down and complicates the process.
These complications are a large part of why modern version control systems have by and large strongly rejected keyword expansion (cf Mercurial or git). Not having keyword expansion is occasionally inconvenient for users, but it makes modern VCSes significantly faster and more attractive.
One aspect of getting used to modern version control
I've spent a very long time using RCS as a sysadmin. In that time, certain things about how it works have just gotten ingrained in my hindbrain, to the level where I don't think about them consciously; they just are. Now that we're slowly moving away from RCS and to modern version control systems, I sometimes wind up running into bits of this that are no longer true, where I have to let how stuff works in modern version control gradually soak into my mind until old reflexive assumptions get dissolved.
One of them is the idea that committing things does not change the files that I am committing. Some of you may be going 'well of course it doesn't', but this is not how it works in RCS; when you commit a file in RCS, RCS removes and then recreates the file. For developers this may not be something that's very important, but it can really matter for sysadmins; among other things, anything that modifies live files makes us nervous.
(This also means that committing a file can change the file ownership,
which is important when you absently
ci a file as root or are working
in a shared directory with group permissions.)
Modern version control systems don't do this; making a commit may change the repository, but it does not change the live file itself. This makes commits much less twitch inducing to sysadmins and much more like actual backups. Forgetting this difference makes me more twitchy about making commits than I should be and leads to occasional embarrassing mistakes.
(It also means that it is much less of an impact to set up an initial repository than it is to do the equivalent in RCS; with a modern VCS, it is effectively the same as making a tar or rsync or whatever backup of the files.)