The Tutorial

Version 1.0 - February 13, 1996


This tutorial will lead you through the basics of RCS usage.

Preface

I'll try to remember to say this in class before we start the tutorial, but please don't be afraid to call my attention to any parts of this tutorial that are too long, too short; too complex, too simple, too confusing, or that just plain don't work. I've tried to catch and fix all errors, but some may have crept through despite my best efforts.

Conventions

The following styles will be used for different things to do or read during the tutorial.
Now on to the tutorial...

A Beginning

The traditional first thing to do when learning a new programming language is to write a program that will print out "Hello world". We're trying to learn how to use a new configuration management tool, so this tutorial will start out by placing a "Hello world" program under version control. Fire up your favorite text editor and create a file helloworld.c that reads:
  #include <stdio.h>
  void main(void)
  {
    printf("Hello, world!\n");
  }
(If you aren't familiar with C, it'll do just as well to do this with a simple text file instead of a Hello World program. Just use the name of your file instead of helloworld.c whenever it is referred to.)

Now that you have the file you want to maintain version control of (you can of course compile and run it if you want to assure that it works), it's time to enter it into an RCS baseline file. Type:
   ci helloworld.c
to create the baseline. ci will prompt you for a comment to be entered, type in something to the effect of "hello world program, first checkin". Verify for yourself that ci really did do what it should have: list your current directory and find the RCS file helloworld.c,v that was just created.
  ls -sl | grep hello*
Note that when ci checked the file into the baseline ,v file, it got rid of the original source code file.

Take a look at the RCS file helloworld.c,v to see what RCS did to the file you checked in.
  more helloworld.c,v
You will see some lines that are mostly empty. These do come into use by the RCS tools, but so far aren't required as nothing really complicated has been done. Down at the bottom of the file, though, you will see:
  1.1
  log
  @Initial revision
  @
  text
  @#include 
  void main(void)
  {
    printf("Hello, world!\n")
  }
  @

More about the World

Now say you realized you wanted to make some changes to your Hello World program. You've heard that there's a program to check files out of an RCS baseline to complement the check-in process, so you type co helloworld.c and make your changes to it. When you finish editing the file and try to save it, you notice there's a problem. The file was checked out of RCS with read-only UNIX file permissions, therefore you aren't allowed to write to it. Type
   co -l helloworld.c
to check the file out locked so that you can make changes to it.

Say you had gotten bored with a simple "Hello, world!", and wanted it to read instead, "Hello, world! This program really works great!". Make this change to the helloworld.c file, and check it back into the baseline with the ci helloworld.c command. You will be prompted for a comment message, again, and notice while you enter one that the checkin program displays a notification such as the following:
  helloworld.c,v  <--  helloworld.c
  new revision: 1.2; previous revision: 1.1
  enter log message, terminated with single '.' or end of file:
  >> hello world, second checkin.
  >> .
  done
To set the new revision number of a checked in file to something other than the default, use the -r option, such as:
    ci -r2.1 helloworld.c
to assign 2.1 instead of 1.2 as the number of the new revision.

Now, look at the actual RCS file again.
    more helloworld.c,v
What did checking in the new revision do? You'll notice that it created a new section 1.2 which contains all of the newly checked-in source file. The text portion of the 1.1 revision, on the other hand, looks nothing like it did before:
  1.1
  log
  @Initial revision
  @
  text
  @d4 1
  a5 1
    printf("Hello, world!\n")
  @
That's rather cryptic, isn't it? What does it mean to say "d4 1" and "a5 1"? These are known as deltas, and are how RCS stores revisions of modified files.

Deltas

Notice that the section of baseline with the delta entries is the section for revision 1.1. The section for 1.2 contains the full text for that revision.

Question:


Different Ways To Specify Revisions

Release numbering based selection

The co command by default checks out the latest revision of the baselines specified by the user. For instance, you can check the latest revision of helloworld.c out of your helloworld.c,v baseline by typing any of the following commands:
    co helloworld.c
    co hello*
    co *,v

If, however, you want to check a specific revision out, you can specify which revision. This command would check out your first revision of the file:
    co -r1.1 helloworld.c
You can also make RCS check out the latest revision of the specified release or branch number. This command would check out the latest revision of release 1:
    co -r1 helloworld.c
But what about the situations where release-based selection just isn't clear enough? With many baseline files, each undergoing many stages of development, keeping track of which of the dozens of revision numbers are compatible can be a nightmare. Luckily, RCS offers other means of revision selection.

State and author based selection

Users can also specify revisions to be checked out based on the settings of the RCS files' state and author (These can be set by the rcs utility, discussed later). An example to check out the latest release of helloworld.c which I had written would be:
    co -sRel -wdspencer helloworld.c

Date-based selection

If a project release was known to have happened at a certain date and time, for example, RCS selection can be made based on the "cut-off date" of that release. Date-based selection will check out the revision which is closest to - but not later than - the specified date.

Example:
    co -d"January 13, 12:00 PM" hellowor*

Name-based selection

Release selection, state, author, and date-based selection are all very useful. These still may not be enough for large projects, however. To allow a user to specify a truly arbitrary group of revision items in a related set, RCS includes name-based selection. For instance, say a user wished to associate revision 2.1 of program1.c with revision 5.3 of program2.c. By checking both in with a new symbolic name, they can in the future use that symbolic name to represent the known versions of each program file.
    co -r2.1 program1.c
    co -r5.3 program2.c
    ci -n"My New Name" program1.c
    ci -n"My New Name" program2.c

    co -r"My New Name" program*.c,v
This feature lends powerful force to the use of RCS across an entire project. A utility program called rcsfreeze can be used to "freeze" a certain configuration of all project elements by assigning the selected revisions the same symbolic name. Now, spend a while getting comfortable with the different ways you can check in and check out program items. Reference the manual pages for ci and co for specific details about how they operate. Here are some exercises to use as starting points:

Branches, Splitting and Merging Trees

Branches

Strictly linear version trees are what most of us are probably used to from academic experiences. You create revision 1.1 of a program, fix it up a bit for revision 1.2, add some more features for version 1.3, actually get them working right for version 1.4, et cetera. By version 2.1, you consider it to actually be done, so you call it version 2, but then you find one last detail to fix - revision 2.2 becomes your newest.
  (1.1) -> (1.2) -> (1.3) -> (1.4) -> (2.1) -> (2.2)
In the "real world," these trees actually tend to grow various branches at different points.
  (1.1) -> (1.2) -> (1.3) -> (1.4) -> (2.1) -> (2.2)
                      \
                       ----> (1.3.1.1)

Typical branching situations

Branching situations might arise in situations of:

Branches and Deltas

Digging back into the actual implementation of RCS for just a minute, how would you choose to actually represent the text changes - deltas - for side (forward) branches? The standard revision tree is done with reverse deltas, but reverse deltas won't quite work for forward branches. It would be wasteful of space to store a complete copy of the branch revision for each branch tip, so RCS also implements forward deltas from the branch point off of the trunk.

Merging

You'll notice that the last two examples of branching situations speak pointedly about "reintegrating", reattaching branches to the trunk of the revision tree after both have stabilized. Luckily, RCS provides facilities to do this automatically where possible.
An example of how to use rcsmerge. Note that you must have checked out and locked the revision file which you will be merging, and that the output of rcsmerge goes to standard output, so it must be redirected into a new file that does not exist.
  [~/csc441] 82: co -l helloworld.c
  helloworld.c,v  -->  helloworld.c
  revision 1.3 (locked)
  done
  [~/csc441] 83: rcsmerge -p -r1.2.1.1 -r1.3 helloworld.c,v > helloworld.merged.c
  RCS file: helloworld.c,v
  retrieving revision 1.2.1.1
  retrieving revision 1.3
  Merging differences between 1.2.1.1 and 1.3 into helloworld.c; result to stdout
  [~/csc441] 84:


Play around a little with branching. If you can get rcsmerge to work right (I've found that it's a little finicky), see what happens when you try to merge a modified branch back onto the trunk of your revision tree.

The RCS Baseline Directory and make(1)

This tutorial has so far shown you how to use the basic RCS features to check items in and out of the database. This is useful in and of itself if you want to simply create multiple versions of a file, but it can also be extended to be of much greater use in a multi-person project.

If you create a central directory where your RCS baselines are to be stored, all people on the project can then create symbolic directory links such as "~/work/RCS/" to it. It would be slightly too chaotic for this tutorial for everyone to attempt to checkout and lock files from a single central directory, so create a directory named RCS of your own which isn't a symbolic link, and experiment with putting your baseline files in there. Many of you have probably also used make(1). Make is a UNIX tool which will compile a group of source files in a particular way based on compilation rules written down by the user in a file named "Makefile". Using make makes it much, much easier to compile large projects. Because RCS is also so useful in large project situations, the make tool has been extended to support "auto-checkout" features for RCS files. If a target file that it is looking for is not available in the current or specified directory, make will search both the current directory and the RCS subdirectory for a checked-in version of that file. If one exists, it will be checked out, used in the compilation, and deleted when no longer needed. (If make finds the file before needing to look for RCS files, of course, it uses the checked-out working file rather than overwriting it with a possibly older version.)

Questions For Thought and/or Things To Try:


Access Lists

UNIX file permissions aren't very helpful sometimes. They can be incorrectly set, or a situation can exist that UNIX permissions just don't help with. RCS implements its own access lists. By default, the access list to an RCS baseline is empty, and everyone who has UNIX permissions to access that file is allowed to do so. If the access list is non-empty, then only the people listed in it are allowed to perform update operations on that file (e.g, allowed to check in modified revisions). The access lists can be set with the utility program rcs.

If you want to use RCS for a project, experiment with adding an access list to your baseline items. Reflect on the earlier security-implications question.

Appendix: A Little About Some Of The Auxiliary RCS Programs: rcs, rcsdiff, (rcsfreeze?), rlog

(Adapted, in abbreviated form, from the appendix of [TIC85]) More details on the various RCS programs can be (and probably should be) found in the manual pages for your local installation:

This concludes the tutorial.. happy version controlling!






Post Mortem

Possible changes that could be made to a future version of this tutorial, most of which were not gotten to due to time constraints, include: © 1996 [David L. Spencer] [mailto:dspencer@galaxy.csc.calpoly.edu]
Permission hereby granted for any non-profit use.