by Bill Ball
Keeping track of changes to software and documents and organizing and controlling these changes can be a daunting task, even for experienced computer users. But thanks to the Revision Control System (RCS), you can use your computer to stay on top of your critical software and document projects. Although it is called by many names, such as code management, source control, or configuration management, revision control can help you organize your project production process.
RCS was developed by Walter F. Tichy at Purdue University in Indiana in the early 1980s, and part of its system uses programs whose origins date back to the mid- to late-1970s. Long before terms such as groupware became popular, RCS was used to automate the storage, retrieval, logging, identification, and merging of revisions to programs. It remains the most popular version control system in use today because of its simplicity, efficiency, and availability. As you'll see later in this chapter, RCS is capable of helping with much more than program development.
You can generally find the following programs on your system. They comprise the GNU version of RCS (version 5.7):
Many different revision control systems are available for UNIX. The following are some of them:
Typically, all version control systems offer a way for authors or managers to maintain different versions of source documents. In many instances, being able to retrieve original versions of programs or maintain different versions of the same program is important. By using RCS, you can keep track of all changes to a software package, maintain different versions with different features, develop new versions for different systems, and provide maintenance releases for earlier versions without possible confusion when many people work on the same files.
Part of what makes RCS so popular is its simplicity. Most of the work is done through the ci and co commands. The following simple example shows how to use RCS. First, create a directory for your project and call it myproject
# mkdir myproject, as follows:
Then use cd to change directories into myproject and create a directory call RCS:
# cd myproject # mkdir RCS
Next, type the following source in your editor, and save it in myproject as foo.c:
/* $Header$ */ #include <stdio.h> static char rcsid{} = "$Header$"; main() { printf("hello, world!\n"); }
Verify your directory's contents, as follows:
# ls RCS/ foo.c
Now, use RCS's check-in command to start tracking:
# ci foo.c
The ci command responds with the following:
RCS/foo.c,v <-- foo.c enter description, terminated with single '.' or end of file: NOTE: This is NOT the log message! >>
Type in the following:
>> a simple example >> .
Then ci displays the following:
initial revision: 1.1 done #
Now look at the contents of myproject by entering the following:
# ls RCS/
What happened? Where did the file foo.c go? To find it, look into the RCS directory:
# cd RCS # ls foo.c,v
The ci command created the RCS file foo.c,v, stored foo.c inside as version 1.1 under the RCS directory, and deleted foo.c from the myproject directory. RCS automatically starts version numbering at 1.1, but you also have the option of using a name instead of a version. See the ci man page for details.
Now, if you want to work on foo.c, type the following command:
# co -l foo.c RCS/foo.c,v --> foo.c revision 1.1 (locked) done
The check-out command shows you that foo.c has been extracted from foo.c,v in the RCS directory, and is now ready for you to work on. The -l option of the co command is important. Checking out a file without locking it extracts the file as read only:
# co foo.c RCS/foo.c,v --> foo.c revision 1.1 done # ls -l foo.c -r--r--r-- 1 root root 252 Aug 2 16:06 foo.c
If, however, you want to edit and make changes, you must lock the file. To verify that foo.c is available, enter the following:
# ls -l foo.c -rw-r--r-- 1 root root 262 Aug 2 16:09 foo.c
Note that the write permission is now enabled, but only for the owner and current user.
If you open foo.c, you see the following:
/* $Header: /root/myproject/RCS/foo.c,v 1.1 1997/08/02 18:49:08 root Exp root $ */ #include <stdio.h> static char rcsid{} = "$Header: /root/myproject/RCS/foo.c,v 1.1 1997/08/02 18:49 :08 root Exp root $"; main() { printf("hello, world!\n"); }
Note that the $Header$ keyword has been replaced with the full pathname of the RCS file, a revision number, date, time, author, state, and locker. If you include the RCS information as an embedded character string, the final or release binary of the program contains your version information. If you include the keyword inside a comment, your source documents contain updated version information.
The following are some of the RCS keywords available:
For details about these keywords, see the co man page. For details about the history of a document's changes, however, you can use the rlog command. For example, after two minor editing changes, rlog reports the following about foo.c, now version 1.3:
# rlog foo.c RCS file: RCS/foo.c,v Working file: foo.c head: 1.3 branch: locks: strict access list: symbolic names: keyword substitution: kv total revisions: 3; selected revisions: 3 description: a simple example ---------------------------- revision 1.3 date: 1997/08/02 20:29:10; author: root; state: Exp; lines: +4 -3 added another printf line ---------------------------- revision 1.2 date: 1997/08/02 19:53:13; author: root; state: Exp; lines: +3 -3 this is the second change ---------------------------- revision 1.1 date: 1997/08/02 18:49:08; author: root; state: Exp; Initial revision
Another reason for RCS's popularity is its efficiency. If you look at the foo.c,v file while it is checked in, you see the following:
head 1.3; access; symbols; locks; strict; comment @ * @; 1.3 date 97.08.02.20.29.10; author root; state Exp; branches; next 1.2; 1.2 date 97.08.02.19.53.13; author root; state Exp; branches; next 1.1; 1.1 date 97.08.02.18.49.08; author root; state Exp; branches; next ; desc @a simple example @ 1.3 log @added another printf line @ text @/* $Header: /root/myproject/RCS/foo.c,v 1.2 1997/08/02 19:53:13 root Exp root $ */ #include <stdio.h> static char rcsid{} = "$Header: /root/myproject/RCS/foo.c,v 1.2 1997/08/02 19:53:13 root Exp root $"; main() { printf("This is an example of a simple program.\n"); printf("hello, world!\n"); } @ 1.2 log @this is the second change @ text @d1 1 a1 1 /* $Header: /root/myproject/RCS/foo.c,v 1.1 1997/08/02 18:49:08 root Exp root $ */ d5 1 a5 1 static char rcsid{} = "$Header: /root/myproject/RCS/foo.c,v 1.1 1997/08/02 18:49:08 root Exp root $"; d8 2 a9 1 printf("hello, world! and goodnight!\n"); @ 1.1 log @Initial revision @ text @d1 1 a1 1 /* $Header$ */ d5 1 a5 1 static char rcsid{} = "$Header$"; d8 1 a8 1 printf("hello, world!\n"); @
As you can see, RCS records each version's changes as diff commands in the foo.c,v file. Therefore, you can successfully retrieve each version at any time by using the co -rX.X command, where X.X is the version you want. Also, because the changes are in diff format, many changes to an original document can be stored fairly efficiently (although some people might argue that compression should be used).
Sometimes you must create a "branched" version of a file, if only for a temporary or specialized fix in the middle of a version. In this case, you use the -rX.X option of the co command to create a branch.
For example, to do a special release of foo 1.2, you use the following:
# co -l -r1.2 foo.c RCS/foo.c,v --> foo.c revision 1.2 (locked) done
After making changes and when checking foo.c back in, the ci command bumps the version to 1.2.1.1 and responds with the following:
# ci foo.c RCS/foo.c,v <-- foo.c new revision: 1.2.1.1; previous revision: 1.2 enter log message, terminated with single `.' or end of file: >> a temporary fix >> . done
You can also merge different versions of your program. For example, to bring the changes from 1.1 into 1.3, you can use the rcsmerge command, but first you must check out foo.c as locked:
# co -r1.1 foo.c RCS/foo.c,v --> foo.c revision 1.1 done # rcsmerge -p -r1.1 -r1.3 foo.c >foo.merged.c RCS file: RCS/foo.c,v retrieving revision 1.1 retrieving revision 1.3 Merging differences between 1.1 and 1.3 into foo.c; result to stdout
Note the that the output of rcsmerge must be redirected to a file.
To remove a particular version of the program, use the rcs command with -oX.X option, where X.X is the version number:
# rcs -o1.2.1.1 foo.c RCS file: RCS/foo.c,v deleting revision 1.2.1.1 done
As you can see, RCS is easy to use, but each of its commands has many different features. Read the man pages for each command for details, and check some of the references listed in the section "For More Information."
You can also use RCS to handle the development and maintenance cycle of nearly any type of text document besides program source, including spreadsheets, graphics, books, manuscripts, or articles. If the project can be represented in text form, you can use RCS to control and maintain it. A newer, commercial form of RCS can be used with any data format. Read about RCE in the next section for more information.
RCS has many more features and a number of subtle logic problems with its locking mechanism. See Tichy's abstract, listed in the next section, for details.
If you're interested in the philosophy, design, and development of RCS, and you want to learn about its differences with other revision control systems, see Tichy's abstract, "RCS--A System for Version Control." Originally published in Software--Practice & Experience, July 1985, the abstract is also included in the 4.4BSD documentation. You can also find a number of copies across the Internet using your favorite search engine.
For a general introduction to RCS, see the rcsintro man page. For details about the format of an RCS file, see the rcsfile man page.
If you want to read about configuration management, find out about alternative tools, or need information to make a decision on the best tool to use for your project, see Dave Eaton's Configuration Management FAQ at the following site:
http://www.iac.honeywell.com/Pub/Tech/CM
You also can check the following newsgroup:
If you want to use RCS on a remote server, try Eric Meyer's RMTRCS package of shell scripts. This package consists of five scripts called rmtco, rmtci, rmtdiff, rmtlog, and rmtrcs. RMTRCS includes a number of nifty features, such as check in and check out on remote machines without having to log in, and automatic e-mail notification of revision logs to project teams.
You can find the source at
ftp://lifshitz.ph.utexas.edu/pub/src/rmtrcs-X.X.tar.gz
where X.X is the current version.
Finally, you should know that Walter Tichy has rewritten RCS to include a graphical user and programmable interface. Called RCE, this version control system is available for nearly a dozen or more operating systems, and also includes many new features. If you want to find out more about the commercial successor to RCS, send e-mail to
or see the FTP site at
In this chapter, we've covered just some of the basics of using RCS, a series of programs for tracking changes to versions of source documents. You've learned how to:
©Copyright,
Macmillan Computer Publishing. All rights reserved.