Ch 26 -- Introduction to SCCS
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.
SCCS isn't just for programmers though. You can use SCCS for any text file, and
it is especially handy when you need to maintain more than one version of a file
or have to modify a file frequently and need a reliable way to recover or view previous
versions. This sort of capability can be a lifesaver to system administrators for
DNS or passwd files, Web developers for HTML and JavaScript code and even
desktop publishers for PostScript, ghostscript and LaTeX files.
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.
Basic Operation
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.
Initial Revisions
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
:D:--Creation date
:T:--Time created
: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.
Module 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:
%D%--Current date
%E%--Date of newest delta
%R%--Release number
%C%--Current line number
%U%--Time newest delta was applied
%Z%--String recognized by what command
%M%--Module name
%I%--Revision number
%W%--Abbreviation for %Z%%M%(tab)%I%
See the get man page entry for a full list of keywords.
TIP: As you are shown in the preceding
list, you can embed SCCS keywords that identify your program executable by using
the following:
char sccsid[] = "%W%";
This way, you can use the what command to identify what revision(s) of
what file(s) went into creating the executable.
Make sure that all your files are checked out for reading, not editing and not with
the -k option.
Other Commands
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:
x |
Action |
v[pgm] |
Require modification request numbers for delta. |
cceil |
Limit the releases that can be retrieved using get. |
ffloor |
Limit the releases that can be retrieved using get. |
llist |
Limit the releases that can be submitted using delta. |
j |
Enable/disable concurrent locks. |
b |
Enable/disable branching. |
dSID |
Set default revision for get. |
n |
Create null deltas for skipped releases. You can use this option to create a base
revision for branches in releases that had no source modifications. |
[qtm] |
Control expansion of some keywords. |
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 1.2.1.1
4 lines
get reflects that the next delta will be checked in at 1.2.1.1
instead of 1.3. (Note that if someone is editing revision 1.3 while
you're working on 1.2.1.1, 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
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
1.2.1.2 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 -r1.2.1.2 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 1.2.1.2 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.
NOTE: To see what is happening with the
source control files, you might want to run prs periodically to observe
the changes in the source control files. If you're truly adventurous, you might even
want to view the source control files themselves. Most systems have an sccsfile
man page that describes the file format in detail.
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)
NOTE: Some versions of SCCS may neglect
to delete the initial file, leaving a writeable copy behind. The get command will
fail if a writeable copy of the target file is already present in the working directory.
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.
Modifying Files
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
CAUTION: In a workgroup project, making
modifications to a file without checking it out can be a very risky proposition.
Be very careful about this practice in real life. This procedure is presented as
a recovery procedure, not an everyday practice.
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.
Practical Use
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.)
Also, beyond SCCS's inevitable association with C programming, it can be used
for other text-file-based development such as HTML, Java, and JavaScript.
Summary
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.
©Copyright,
Macmillan Computer Publishing. All rights reserved.
|