One of the strong points about CVS is that it not only lets you retrieve old versions of specific files, you can collect files (or directories of files) into ``modules'' and operate on an entire module at once.
The RCS history files of all modules are kept at a central place in the file system hierarchy. When someone wants to work an a certain module he just types cvs checkout malloc which causes the directory malloc to be created and populated with the files that make up the malloc project.
With cvs tag malloc-1.0 you can give the symbolic tag malloc-1.0 to all the versions of the file in the malloc module. Later on, you can do cvs checkout -r malloc-1.0 malloc to retrieve the files that make up the 1.0 release of malloc. You can even do things like cvs diff -c -r malloc-1.0 -r malloc-1.5 to get a context diff of all files that have changed between release 1.0 and release 1.5! No locking
If you work in a group of programmers you have probably often wanted to edit the function realloc() in alloc.c, but Joe had locked alloc.c because he is editing free().
CVS does not lock files. Instead, both you and Joe can edit alloc.c. The first one to check in it won't realize that the other have been editing it. (So if you are quicker than Joe you wont have any trouble at all). Poor Joe just have to do cvs update alloc.c to merge in your changes in his copy of the file. As long as you changing different sections of the file the merge is totally automatic. If you change the same lines you will have to resolve the conflicts manually.
Friendlier user interface
If you don't remember the syntax of cvs diff you just type cvs -H diff and you will get a short description of all the flags. Just cvs -H lists all the sub-commands. I find the commands less cryptic than the RCS equivalents. Compare cvs checkout module (which can be abbreviated to cvs co module) with co -l RCS/*,v (or whatever it is you are supposed to say -- it's a year since I used RCS seriously).