What's GNU?

This month's column discusses RCS, the Revision Control System.
Comparing Versions of a File

You can compare any two versions of a file using the rcsdiff command. This command accepts all the options that the regular diff command does. However, it usurps the -r option for providing revision numbers. By default, rcsdiff compares the current version of the working file with the most recently checked-in version. With one -r option, it compares the current file against the specified previous version. You can supply two instances of the -r option to make it compare two different revisions, neither of which is the current version. Here's an example of the default (and most common) case:

$ rcsdiff -c hello.c
==================================================
RCS file: RCS/hello.c,v
retrieving revision 1.1
diff -c -r1.1 hello.c
*** 1.1 1994/11/06 03:36:45
--- hello.c     1994/11/06 03:54:49
***************
*** 1,6 ****
   #include <stdio.h>
!  int main(void)
   {
        printf("hello, world\n");
--- 1,12 ----
   #include <stdio.h>
+  #include <string.h>
!  int main(int argc, char **argv)
   {
+       if (argc > 1 && strcmp(argv[1], "-advice") == 0) {
+           printf("Don't Panic!\n");
+           exit(42);
+       }
        printf("hello, world\n");
+       exit(0);
   }

This generates a “context diff”, showing the surrounding context of what was changed, not just the changes themselves. The lines marked with ! indicate a changed line from the old to the new version, and the lines marked with + indicate lines that were added.

The rcsdiff program makes it easy to generate updates that can be applied with patch. When a program is finished, simply check in all the files that make it up with a new, higher level revision number, such as 3.0. Then, for the next release, run rcsdiff against revision 3.0 for all files.

$ rcsdiff -c -r3.0 RCS/* > myprog-3.0-4.0.patch 2>&1

(This doesn't catch the case of brand new files added in 4.0, or deleted files that were in 3.0, but you get the idea.)

As a side note, in order to build and install the RCS software, you need to have the GNU version of diff. Linux systems have this already. If you don't have GNU diff, you should get it anyway, since it is very full- featured and noticeably faster than the standard Unix version of diff.

Automatically Tracking Interesting Information

It is often useful to be able to look at the contents of a source file and tell what version of the file it is. RCS allows you to do this by performing “keyword substitutions” on the contents of your file when it is checked out. There are a large number of these keywords; the co man page documents them in full. The most common ones are $Id$ and $Log$.

The $Id$ keyword is replaced with text describing the filename, revision, date and time of checkout, the author, and the state (e.g., Exp, for experimental). Usually, this is embedded in a C string constant so that a binary, generated from the file, can be identified with the ident command.

The $Log$ keyword is replaced with the text of the most recent log message. This is usually placed inside a comment, so that the source file is self-documenting, showing what was changed and when. This is useful, but should be used with caution: if a file is changed frequently, this log can grow quite a lot.

We'll now add the keywords and show the state of the file, both before and after checking in the changed version.

$ sam hello.c
$ cat hello.c
#include <stdio.h>
#include <string.h>
static const char rcsid[] = "$Id$";
/*
 * $Log$
 */
int main(int argc, char **argv)
{
   if (argc > 1 && strcmp(argv[1], "-advice") == 0) {
        printf("Don't Panic!\n");
        exit(42);
}
   printf("hello, world\n");
   exit(0);
}
$ ci -l hello.c
RCS/hello.c,v  <-  hello.c
new revision: 1.3; previous revision: 1.2
enter log message, terminated with single `.' or end of file:
>> add id and log keywords.
>> .
done
$ cat hello.c
#include <stdio.h>
#include <string.h>
static const char rcsid[] = "$Id: hello.c,v 1.3 1994/11/07 03:41:32
arnold Exp arnold $";
/*
 * $Log: hello.c,v $
 * Revision 1.3  1994/11/07  03:41:32  arnold
 * add id and log keywords.
 *
 */
int main(int argc, char **argv)
{
   if (argc > 1 && strcmp(argv[1], "-advice") == 0) {
        printf("Don't Panic!\n");
        exit(42);
}
   printf("hello, world\n");
   exit(0);
}

We see that RCS has filled in the information for both keywords. When the program is compiled, the ident command will give us information about all the files used to compile the program that have RCS ids in them.

$ gcc -O hello.c -o hello
$ ident hello
hello:
   $Id: hello.c,v 1.3 1994/11/07 03:41:32 arnold Exp arnold $
______________________

Geek Guide
The DevOps Toolbox

Tools and Technologies for Scale and Reliability
by Linux Journal Editor Bill Childers

Get your free copy today

Sponsored by IBM

Upcoming Webinar
8 Signs You're Beyond Cron

Scheduling Crontabs With an Enterprise Scheduler
11am CDT, April 29th
Moderated by Linux Journal Contributor Mike Diehl

Sign up now

Sponsored by Skybot