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 $
______________________

White Paper
Linux Management with Red Hat Satellite: Measuring Business Impact and ROI

Linux has become a key foundation for supporting today's rapidly growing IT environments. Linux is being used to deploy business applications and databases, trading on its reputation as a low-cost operating environment. For many IT organizations, Linux is a mainstay for deploying Web servers and has evolved from handling basic file, print, and utility workloads to running mission-critical applications and databases, physically, virtually, and in the cloud. As Linux grows in importance in terms of value to the business, managing Linux environments to high standards of service quality — availability, security, and performance — becomes an essential requirement for business success.

Learn More

Sponsored by Red Hat

White Paper
Private PaaS for the Agile Enterprise

If you already use virtualized infrastructure, you are well on your way to leveraging the power of the cloud. Virtualization offers the promise of limitless resources, but how do you manage that scalability when your DevOps team doesn’t scale? In today’s hypercompetitive markets, fast results can make a difference between leading the pack vs. obsolescence. Organizations need more benefits from cloud computing than just raw resources. They need agility, flexibility, convenience, ROI, and control.

Stackato private Platform-as-a-Service technology from ActiveState extends your private cloud infrastructure by creating a private PaaS to provide on-demand availability, flexibility, control, and ultimately, faster time-to-market for your enterprise.

Learn More

Sponsored by ActiveState