UNIX Unleashed, Internet Edition
- 26 -
Introduction to SCCS
by Eric Goebelbecker
The Source Code Control System (SCCS) was developed by AT&T as a system to control source code development. It includes features that help support a production development environment, including being able to help freeze released code, integrate into a problem-tracking system, and embed keywords into binary programs that can be viewed with the what command after the program is released.
Most systems ship with SCCS, but a few do not include the sccs command that was introduced by BSD as a convenient interface to the SCCS system. This book's CD-ROM includes a version of the sccs command as available on the free source from BSD because it simplifies use of the SCCS system. You'll learn how to use it periodically throughout the chapter.
SCCS stores changes to files in a file that is called, logically enough, an SCCS file. This file is usually stored in a directory named SCCS, which is a child of the working directory, when the simplified interface to SCCS provided by the sccs command is used. The SCCS file is named s.file, where file is the name of the file being tracked.
Changes are recorded in this file as building blocks, with each set of changes depending on the previous revision. For example, imagine if SCCS managed the file 3liner.txt, which follows:
This is a simple 3 line file
The next revision alters it to the following:
This is a simple three line file
SCCS adds only the last line to the SCCS file s.3liner.txt and records it as the next revision. This method of tracking changes individually allows you to revert to previous versions of working files quickly and easily.
Note that the actual mechanics of the file differ slightly from this abstraction, but from a conceptual level, this is all you need to worry about.
SCCS Command Summary
You use the SCCS admin command to interact with the source control system data (SCCS) files. You use it to create source control files, control availability of revisions, and change the requirements for submitting a revision.
You use the get and delta commands to retrieve revisions and create new a new delta, or revision. You use unget to cancel the creation of a delta.
SCCS uses temporary files to store internal state and track file locks. These files are stored in the SCCS directory, and should never be manipulated.
SCCS commands require the name of the SCCS file itself, as in s.3liner.txt rather than the working filename. The sccs program, which is included on the CD and most BSD systems, accepts working filenames, however.
You have to initialize SCCS files using the admin command before you can perform any other action. These files can be initialized with an empty revision or with the contents of a working file as the initial revision.
You create an SCCS file with an empty initial revision by executing
$ admin -n s.3liner.txt
This command creates s.3liner.txt with the appropriate SCCS file structure and an empty revision 1.1. You can then use the get and delta commands to add text. Unlike RCS, however, the empty revision 1.1 will always remain in the SCCS data file.
To create an SCCS file with initial contents from another file, enter the following:
$ admin -i 3liner.txt s.3liner.txt
The two occurrences of 3liner.txt do not have to agree, but it is generally useful for them to do so because other SCCS commands assume that the working file for s.3liner.txt is 3liner.txt.
The sccs command provides a simplified method for creating SCCS data files:
$ sccs create 3liner.txt
This command creates s.3liner.txt in the directory named SCCS in the current working directory.
Checking Out a File
You use the get command to retrieve copies of revisions from SCCS files. You can retrieve any version, either by number or by date, as follows:
$ get s.3liner.txt 1.1 3 lines No id keywords
Without any options, get retrieves the latest revision from the SCCS file, placing it in a read-only copy of 3liner.txt because it assumes that you are not planning to make any changes and create a new revision. The three lines following the command tell us what version was retrieved, the size of the file in number of lines, and how many keywords it expanded.
Now consider the following:
$ get -e s.3liner.txt 1.1 new delta 1.2 3 lines
The -e option here indicates that you are checking 3liner.txt out for editing. The get command supplies you with a writeable copy and creates a lock file called p.3liner.txt. This lock file prevents other users from retrieving the same version for editing until this one is checked in using delta or unget. Read-only copies can be checked out though. You can use the -e option for different versions at the same time; however, if two users are making changes to the same file at the same time, the project most likely will have branches in the revision tree (which will be covered later). (Chapter 24, "Introduction to Source Control," contains details on revision trees, branching, and other essential revision control concepts.)
You use the -p and -c options to retrieve a revision other than the latest. You can combine both options with -e.
Now look at another example:
$ get -r1.1 s.3liner.txt 1.1 3 lines No id keywords
This command retrieves version 1.1, regardless of what the latest version might be. The minor version number does not have to be specified. -r2 retrieves the high revision within version 2.
Here's another example:
$ get -c970227 s.3liner.txt 1.1 3 lines No id keywords
The -c flag allows you to specify a date in the form of YY[MM[DD[HH[MM[SS]]]]]. That is, you can specify two digits for a year, followed by an optional set of digits for month, day, hour, and second. Like other sccs commands, any optional parameters that you omit are set to their maximum. So the preceding example retrieves the latest version of 3liner.txt as of 11:59:59 p.m. on February 27, 1997.
The sccs also provides a vastly simplified interface to the get command:
$ sccs get 3liner.txt
This command retrieves a read-only copy of the latest version 3liner.txt, contained in s.3liner.txt, in the SCCS subdirectory. You can pass all the command-line options that apply to get to this subcommand. (All the output you receive with the get command appears also; it is just not shown here.)
The following retrieves a read-only copy of version 1.3:
$ sccs get -r1.3 3liner.txt
The edit subcommand executes a get -e, as follows:
$ sccs edit 3liner.txt
It also accepts all the get flags.
The sccs command generally allows you to use any SCCS command, without specifying the SCCS control file.
get has quite a few more command-line options than the ones covered here. I'll get to them as they become relevant.
Checking In a File
You use the delta command to submit changed revisions. This process is also called creating a delta. Here's how:
$ delta s.3liner.txt comments? Added fourth line. No id keywords (cm7) 1.3 1 inserted 0 deleted 3 unchanged
This delta command checks in the previous checked-out working copy of 3liner.txt. delta examines the control file, s.3liner.txt, and the lock file, p.3liner.txt, to figure out where the working copy of 3liner.txt should be and what version it will be checked in as.
delta prompts you for comments on the changes you made. These comments, which are called log messages, can be viewed with the prs command, which I cover in the next section of this chapter. It also gives you an idea of the changes it noted by listing the number of inserted, deleted, and changed lines.
delta also defaults to removing the writeable version of the working file. You can override this action by using the -n flag. If more than one version is checked out, you use the -r flag, just as the -r flag works for get.
The sccs command works as a wrapper for delta in the same manner that is does for get.
Examining Revision Details and History
The prs command enables you to print reports from information in the SCCS file. It also produces custom reports by enabling you to supply a format specification by specifying SCCS keywords.
Look at this example:
$ prs s.3liner.txt s.3liner.txt: D 1.2 97/04/29 10:34:38 eric 2 1 00001/00000/00003 MRs: COMMENTS: Added fourth line D 1.1 97/04/29 10:33:34 eric 1 0 00003/00000/00000 MRs: COMMENTS: date and time created 97/04/29 10:33:34 by eric
This report shows the information for versions 1.1 and 1.2. For each version, you see the date, time, user, and the line information (number added/deleted/unchanged). You also see the comment input to the delta command. For revision 1.1, the report displays 3 lines added, and the comment is a date-and-time-created statement inserted by the sccs create command. (The MRs line is for an advanced feature that is beyond the scope of this chapter. See the manual pages for details.)
The -d option controls the printing of information about the SCCS file. You can use it to create customized reports by specifying a formatting string, as follows:
$ prs -d "File: :M: version: :I: created: :D:" s.3liner.txt File: 3liner.txt version: 1.2 created: 97/04/29
This command gives you a formatted one-line entry, by providing prs with a formatting string. prs accepts keywords similar to the ones you can embed in working files; some of them are as follow:
:M:--Module (working file) name
:I:--ID (version) number
:C:--Comments for delta
See the prs man page for more. Many of the more than 40 different keywords are shorthand for combinations of keywords.
SCCS uses a keyword substitution method for working files that is a little bit different from the method used for prs. Module keywords are of the form %x% and are expanded when you use get (without the -k or -e options) to retrieve the file.
These expanded keyboards have the same advantages and disadvantages of the C/C++ preprocessor. Because the keywords are expanded inline, they need no additional processing to be human readable. (For example, printf("Revision %I%\n"); in a C source file code prints out as Revision 1.1 for revision 1.1 if the program is checked out with the keywords expanded prior to being compiled and linked.) However, expanded keywords are difficult to recover after a file is checked out and distributed because they are completely replaced with the appropriate text. Therefore, standardizing on a specific location or at least the syntax for their use is a good idea.
Some of the module keywords are as follow:
%E%--Date of newest delta
%C%--Current line number
%U%--Time newest delta was applied
%Z%--String recognized by what command
%W%--Abbreviation for %Z%%M%(tab)%I%
See the get man page entry for a full list of keywords.
SCCS provides a few other utilities for managing projects.
The unget command, for example, cancels a get operation, preventing a new delta from being created and erasing any lock associated with the previous get. Another command, rmdel, is provided for removing deltas from the SCCS file after they are applied.
You can use cdc to change the comment associated with a delta.
For combining two deltas, SCCS offers the comb command. This command is intended for reducing the size of SCCS data files, not for resolving conflicts. It produces a shell script, which is then run to perform the compression. SCCS also supplies sccsdiff, which you use to compare SCCS data files and can use to check on files after a comb operation. (The implication is that you should keep a backup copy of the file until you are sure everything is okay.)
The sact command provides a report on what revisions are checked out for editing and what revision they will become when they are checked back in.
The sccs command provides a simplified interface to all these commands. See the man page that is distributed with it.
Extra SCCS Features
SCCS includes extra software configuration management support hooks that are set when the SCCS file is created. You can use the -f x and -d x options of the admin command to do the following:
See the admin man page entry for more details on these options.
Creating a Revision Branch
Using get -b -e causes SCCS to create a branch from the specified revision. If you want to create a second revision path at 1.2 in the previous example, you can execute the following:
$ get -b -e -r1.2 s.3liner.txt 1.2 new delta 188.8.131.52 4 lines
get reflects that the next delta will be checked in at 184.108.40.206 instead of 1.3. (Note that if someone is editing revision 1.3 while you're working on 220.127.116.11, both users will have to provide the -r flag to delta when you check your revisions back in!)
SCCS does not support branches on branches like RCS does.
Merging revisions is not a feature of SCCS. Instead it is necessary to utilize the merge utility that comes with most UNIX releases.
merge compares two files and outputs the merged file to either a third file or standard output, depending on how it is run. The utility also catches conflicts and notifies the user.
For example, consider a situation where the file we used above progressed to revision 18.104.22.168 in the branch and to 1.3 in the trunk. In preparation for the next major version, 2.0, we wish to merge the latest two revisions.
$ get -e -r1.3 s.3liner.txt $ get -s -p -r22.214.171.124 s.3liner.txt >branch $ get -s -e -p -r1.2 s.3liner.txt >trunk $ merge -p 3liner.txt trunk branch $ delta -r2.0 s.3liner.txt
The first get command checks version 1.3 for editing. The second two provides us with copies of 1.2 and 126.96.36.199 in separate files with unique names. The merge command applies all of the differences between trunk and branch to 3liner.txt, effectively giving us a merge of the files. A common ancestor, 3liner.txt, is necessary for merge to be able to successfully figure out how to apply the changes. After the merge is completed we copy the new file to 3liner.txt and check it in.
This example omitted the changes to the files and focused on the mechanics of merging revisions. The differences between file revisions can be difficult for a program to resolve without user intervention. If revisions occur on the same line merge considers this a collision and outputs information about the problem either into the target file or to standard output. RCS, unlike SCCS, has explicit support for merging revisions and is a better choice for projects that need to perform merges frequently or across complicated files and file sets.
merge is another one of the multipurpose command line tools that accompanies most UNIX releases. See the manual page for details.
Using SCCS: An Example
In this section, I walk you through a simple exercise using SCCS to solve some typical problems involving a multiple file and multiple user project.
To keep things simple, I use only three files that start out with one line of text each. Three files are adequate to introduce you to the operations and concepts behind using a source control system in a real-world situation, and the contents of the files are not important, just as long as the contents change throughout the exercise.
To prepare for this example, you should create a new directory. In the new directory, create three files: file1, file2, and file3.
The contents of file1 should be
This is file1
The contents of file2 should be
This is file2
The contents of file3 should be
This is file3
Starting the Project
I describe three different methods here to create the SCCS files. In the first method, you will initialize an empty source control file and then manually check in the initial version of the file. In the second, you will initialize the source control file to contain the current contents of the source file and manually enter the descriptive information. In the third method, you will initialize the source control file to contain the current contents of the source file, and all descriptive information and comments will be supplied on the command line.
Creating an SCCS File with an Empty Revision
Initialize an empty SCCS file, and check in file1, as follows:
$ admin -n s.file1 $ get -e -p s.file1 Retrieved: 1.1 new delta 1.2 0 lines $ delta s.file1 comments? Initial revision No id keywords (cm7) 1.2 1 inserted 0 deleted 0 unchanged $ get s.file1 Retrieved: 1.2 1 lines No id keywords (cm7) $
With admin -n, an empty initial revision is created, and revision 1.1 will always be an empty file because adding the text creates revision 1.2.
To lock the SCCS file, you execute a get using get -e -p, which prints the file to standard output and locks it. Because you already have the contents of file1, you do not want get to overwrite it with the empty revision 1.1.
The delta command checks in the initial revision of the file as revision 1.2, leaving an empty revision 1.1 as an artifact. The final get command ensures that you have a current, read-only copy of file1.
Creating an SCCS File with a "Full" Revision
To initialize an SCCS file with the current contents of file2 already in it, you can use -i flag of the admin command, as follows:
$ admin -ifile2 s.file2 No id keywords (cm7) $ rm file2 $ get s.file2 Retrieved: 1.1 1 lines No id keywords (cm7)
The -i flag creates s.file2 with the current contents of file2 as revision 1.1. You use the get command to keep available a current copy of the head revision of file2. The rm command is for versions of the SCCS admin command that does not remove the writeable copy of the source file.
The sccs create command performs the same operation as admin -i but requires only the name of the target file.
Creating an SCCS File with Comments
The final method, which follows, supplies descriptive comments on the command line used to create the full source control file:
$ echo "Contents of file3 for source control example" > desc $ admin -tdesc -ifile3 -y"Original source for file3" s.file3 No id keywords (cm7) $ rm file3 $ get s.file3 Retrieved: 1.1 1 lines No id keywords (cm7)
This admin command sets up the SCCS file completely using the source from file3, the description from desc, and the comment supplied with the -y option. This method presents a good opportunity for writing scripts to do large initializations of source control hierarchies.
You can now make changes to file2 and file3 to prepare for an initial release. These simple changes will involve locking the file, editing the file, and checking in the change to source control. You will perform these tasks in two different ways to see how important properly locking files before editing is.
Lock, Modify, Check In
First, make changes after locking the file, and check it back in to source control. For this example, change file2 as follows:
This is file2 Added line 1 Added line 2 Added line 3 Added line 4
This addition creates revision 1.2 with the changes you made. For SCCS, you should run the following:
$ get -e s.file2 Retrieved: 1.1 new delta 1.2 1 lines
Now edit file2 using your favorite editor.
$ delta s.file2 comments? No id keywords (cm7) 1.2 4 inserted 0 deleted 1 unchanged $ get s.file2 Retrieved: 1.2 5 lines No id keywords (cm7)
This method creates revision 1.2 with the changes you made, after prompting you for comments. Notice that the delta command tells you how many lines were inserted, deleted, and unchanged. The final get keeps a read-only copy on hand.
Modify, Lock, Check In, Recover
If you change a file without a lock, you still can lock the source control file and check in the changes. For this example, change file3 as follows:
This is file3 A line called A A line called B A line called C A line called D
Using SCCS, execute these commands:
$ get s.file3 Retrieved: 1.1 1 lines No id keywords (cm7) $ chmod u+w file3
Now edit the file using your favorite editor.
$ get -e -p s.file3 >/dev/null Retrieved: 1.1 new delta 1.2 1 lines $ delta s.file3 comments? No id keywords (cm7) 1.2 4 inserted 0 deleted 1 unchanged $ get s.file3 Retrieved: 1.2 5 lines No id keywords (cm7)
You use the first get command to make sure that you have the correct contents for file3, but it does not set a lock. The chmod should be a red flag that you are doing something dangerous; if you're using chmod on an SCCS managed file, you are probably doing something wrong! The get -e -p command sets a lock on the head revision of file3 (and copies the text of the head revision of file3 to /dev/null). The delta command checks the changes into SCCS. You use the final get command to get a read-only copy of the head.
Using SCCS for a Release
Unlike RCS, SCCS does not offer symbolic names. It does, however, offer several similar options for getting particular revisions, highest delta in a release, or head of a branch or the trunk. See the get man page entry for more details.
SCCS can use a cutoff date for a get; it gets the most recent delta before the cutoff date. For this example, you use the release date and time as the cutoff (the cutoff time you use will be different!). The following shows how to retrieve an SCCS file by date:
$ get -c9703092359 s.* s.file1: Retrieved: 1.2 1 lines No id keywords (cm7) s.file2: Retrieved: 1.2 8 lines No id keywords (cm7) s.file3: Retrieved: 1.2 5 lines No id keywords (cm7)
So by selecting September 3, 1997 as the release date for version 1.0 for the product, you can easily retrieve the appropriate files.
SCCS has wide applicability for system administration tasks because files for adding users, such as passwd and nfs, are frequently edited when users are added to networks, and SCCS provides a convenient audit trail and backup system. (Although SCCS is not a suitable substitute for backups, it is really more of a "back out" system because it provides a method for recovering from errors.)
SCCS is an excellent example of the UNIX model in that it is a set of loosely coupled, simple, and straightforward programs that can be used as the basis for a sophisticated system.
In this chapter I covered how to create SCCS data files, how to check files out for editing, and how to check them back in so that changes can be logged and archived.
You should also understand how SCCS allows a group of users to work on a set of files together without causing conflicts, and how to resolve conflicts when they arise anyway.
I also demonstrated the creation of revision branches and merging project files.