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

Webinar
One Click, Universal Protection: Implementing Centralized Security Policies on Linux Systems

As Linux continues to play an ever increasing role in corporate data centers and institutions, ensuring the integrity and protection of these systems must be a priority. With 60% of the world's websites and an increasing share of organization's mission-critical workloads running on Linux, failing to stop malware and other advanced threats on Linux can increasingly impact an organization's reputation and bottom line.

Learn More

Sponsored by Bit9

Webinar
Linux Backup and Recovery Webinar

Most companies incorporate backup procedures for critical data, which can be restored quickly if a loss occurs. However, fewer companies are prepared for catastrophic system failures, in which they lose all data, the entire operating system, applications, settings, patches and more, reducing their system(s) to “bare metal.” After all, before data can be restored to a system, there must be a system to restore it to.

In this one hour webinar, learn how to enhance your existing backup strategies for better disaster recovery preparedness using Storix System Backup Administrator (SBAdmin), a highly flexible bare-metal recovery solution for UNIX and Linux systems.

Learn More

Sponsored by Storix