[ << ] [ >> ]           [Top] [Contents] [Index] [ ? ]

Basic Revision Control

This chapter introduces the fundamental operations for storing revisions in archives, retrieving them, doing clever things with patches, and managing project trees for archived projects.


The First Revision

When beginning a new project, the first step is to check in the very first revision of the tree. From the top level directory of the project tree, you can do this with create-version. For example

 
        % arx create-version CATEGORY--BRANCH--VERSION

This will set up all of the things behind the stage needed to commit the tree. It will not actually modify the archive. It will also pop up an editor (set with my-editor) to edit a log file template. It will look like

 
        Summary:
        Keywords:

The details of what should go in a log message are project specific. To make a multi-line Summary: or Keywords: line, just indent it. Also, you have to skip a space after the Keywords: line before. So a complete log entry might look like

 
        Summary: Added foo, removed bar.  Rearranged and split up 
          the baz directories.
        Keywords: foo, bar
        
        Added foo, which required reworking lart.c to handle
        a more general case.
        Removed bar, because it is now subsumed by foo.

It could also be as simple as

 
        Summary: Added foo, removed bar.

In general, the format of a log message uses RFC822 style headers followed by a free-form body. The only required header is the Summary:. A body is not required. When ArX stores a log message, it will add some headers of its own.

Add files By default, you have to explicitly add files to the list of files that are considered to be source (and thus should be archived). So if you have files foo.c, bar.py, and baz.pl in the project tree, but you only want to archive foo.c and bar.py, then issue the command

 
        % arx add foo.c bar.py

You can check which files have been marked as source with

 
        % arx inventory

See ArX Project Inventories for more information about how ArX decides what to archive.

Archive the Tree Again, in the root of the project tree, use the commit command to archive the tree:

 
        % arx commit

commit will make all of the necessary categories, branches, and versions, store the tree in the archive (as a compressed tar file), and update the patch log of the working directory to reflect the commit.

After commiting a revision to, say, hello--devo--1.0, you can use the command revisions to see a list of archived revisions:

 
        % arx revisions hello--devo--1.0
        base-0

base-0 is the "patch level name" for the first revision. Patch levels are described in greater detail below.


Successive Revisions

Suppose that you have continued to edit your working directory after checking in the initial revision. Successive revisions can be checked in with the command commit, issued at the root of the working directory. As before, you must first have a log file. You can use the make-log function to prepare a log message for each commit:

 
        % arx make-log

This will pop up an editor to modify the log file template. To commit the changes, you once again use commit.

 
        % arx commit

After several commits, you will have a number of patch levels:

 
        % arx revisions hello--devo--1.0
        base-0
        patch-1
        patch-2
        patch-3
        ...

As a point of interest, the base revision is stored as a compressed tar file of the entire tree. Each patch-N is stored as a compressed tar file of just a patch set that describes how to derive that revision from the previous revision.


Patch Levels

Within a version, there is a sequence of revisions, each of which is a different patch level. Every patch level has a patch level name, derived from the version name by adding a suffix:

 
        hello--devo--1.0--base-0
        hello--devo--1.0--patch-1
        hello--devo--1.0--patch-2
        hello--devo--1.0--patch-3
        ...

Just as with version names, there is also such a thing as a fully qualified patch level name:

 
        joe.hacker@gnu.org--test-archive/hello--devo--1.0--patch-3

It is perhaps worth mentioning that patch level names can be sorted easily using:

 
       sort -t - -k 1,1 -k 2,2n

or in reverse:

 
       sort -t - -k 1,1r -k 2,2rn


Tagging

You can also give alternative names for revisions. For example, you can use the tag release-candidate to name whatever revision people should download for testing purposes, regardless of what branch, version, or patch level the release candidate happens to be on.

In ArX, tags are revisions on ordinary branches. For example, suppose we are developing ArX--devo--0.5 and want to create a tag release-candidate to mark revisions which "early adopters" should test. This is as simple as

 
      % arx tag ArX--devo--0.5--patch-37 \
                 ArX--release-candidate--0.5

Note that source-revision and tag-revision may be abbreviated. For example, to tag the most recent revision of ArX--devo:

 
      % arx tag ArX--devo--0.5 ArX--release-candidate--0.5

or

 
      % arx tag ArX--devo ArX--release-candidate

After such a command, you can retrieve the tagged revision in the ordinary way:

 
      % arx get ArX--release-candidate--0.5

Note that when you get a tag that way, the default version of the resulting project tree is the tag's version, not the tagged version (see Labelling Project Trees).

You can always update a tag, making it point to a later revision, again using the tag command:

 
      % arx tag ArX--devo--0.5--patch-53 \
                 ArX--release-candidate--0.5

You can see the history of a tag in the usual way, too:

 
      % arx revisions --summary ArX--release-candidate--0.5
      base-0
          tag of joe.hacker@gnu.org--ArX/ArX--devo--0.5--patch-37
      patch-1
          tag of joe.hacker@gnu.org--ArX/ArX--devo--0.5--patch-53


Development Phases

Note: Phased development may be removed in the future. Its' status is uncertain.

Development within a version may be optionally divided into four phases: base revision, pre-patches, version revision, and post-patches. Conceptually, "pre-patches" are revisions made before the version is "done". "Post-patches" are revisions made after the version is done (e.g. "bug fix patches").

At the beginning of a development path is the base revision (called base-0). Between the pre-patch and post-patch phases is the version revision (called version-0). Post-patches have names like versionfix-1, versionfix-2, etc.

So the total sequence of revisions within a development path has the form:

 
        The Initial Revision:
 
                base-0
 
        Pre-Patches:
 
                patch-1
                patch-2
                patch-3
                ...
                patch-N
 
        The Version Revision:
 
                version-0
 
        Post-Patches:
 
                versionfix-1
                versionfix-2
                versionfix-3
                ...

Typically, the version-0 revision is what would be released under the version number and the post-patch revisions are fixes made after the release.

The ordinary commit command creates pre-patches (patch-N revisions).

To create the version revision, use commit --seal:

 
        % arx commit --seal

After the version revision exists, ordinary commit will no longer work. To create a post-patch revision, use commit --fix:

 
        % arx commit --fix

If you are familiar with other revision control systems, a four-phased development process may at first seem somewhat arbitrary and needlessly complicated. Two points are worth mentioning:

First, phased development is entirely optional. Nothing requires you to ever --seal a version, and if you never seal a version, you never need to use --fix. Instead, every revision (after base-0) will be a patch-N revision.

Second, phased development is a handy way to prevent accidents when organizing more complex projects. Sealing a version is a way to set a flag that says, in effect, "ordinary development in this version has stopped -- you might not really want to make a new revision here." You can make a new revision if you insist (by specifying --fix), but the requirement that you insist helps alert you to the fact that your new revision might need to be merged with later versions of the same project; or that that version you are revising has already been released. Phased development is a bookkeeping convenience: for the most part, ArX treats all revisions equally, regardless of their phase.


Getting a Revision

To retrieve a revision from an archive, use arx get:

 
        % arx get REVISION DIR

as in:

 
        % arx get hello--devo--1.0--patch-4 hello

to retrieve the revision patch-4 and store it in the new directory hello.

An abbreviation can be used to obtain the most recent revision of a version:

 
        % arx get hello--devo--1.0 hello

or to obtain the most recent revsion of the highest-numbered version:

 
        % arx get hello--devo hello

A fully-qualified name can be used to obtain a revision from someplace other than the default archive:

 
        % arx get joe.hacker@gnu.org--test-archive/hello--devo


Optimizing Archives for get

The way that get ordinarily works is that it searches backwards from the desired revision to find the nearest full-source base revision. It gets the compressed tar file for that base revision and creates a source tree. Then, for each intermediate patch level, it gets a compressed tar file of the patch set, uncompresses and un-tars the patch-set, and applies the patch-set to the source tree.

If there are many intermediate patch-sets, that process can be slow. In such cases, you can ask ArX to cache a full-source copy of an arbitrary revision, with the command:

 
        % arx archive-cache-revision [ARCHIVE/]REVISION

That command first builds the requested revision, then it builds a compressed tar file of the revision, then it stores the tar file back in the archive. Subsequent attempts to get the same revision (or any later revision) will use the cached tree.

To remove a previously cached tree, use:

 
        % arx archive-uncache-revision [ARCHIVE/]REVISION

For each user, ArX also maintains a "client side" cache of revisions that can speed up get (and other operations). See Revision Tree Libraries for more details.


Finding Out What Changed

Before performing a commit, you might want to check to see what has actually changed -- that is, find out exactly what patch set your commit will create.

You can do that with the command what-changed:

 
        % arx what-changed
        [...patch set report...]

what-changed computes a patch set between your modified project tree and the latest patch level for which your project tree is up-to-date. In other words, it tells you what changes have been made to your tree compared to the tree in the archive.

what-changed leaves behind a directory containing the patch set and patch report, which you can usefully browse by hand.

 
    % ls
    ,,what-changed.ArX--devo--0.5--patch-14--lord@regexps.com--ArX-1
    [...]

The default output of what-changed is formatted for use with the outline mode of GNU Emacs. The emacs mode bundled in the distribution makes it easy to browse the differences.

You can ask what-changed to also generate an HTML-formatted report with:

 
        % arx what-changed --url
        URL of patch report

The HTML report has links to each context diff, added, and removed file. The output of the command is a file: method URL, which can be used by browsers

 
        % mozilla -remote "openURL(`arx what-changed --url`)"

A simpler solution is to set your browser using the my-browser command. Then you can invoke what-changed with the --new-browser or --new-tab options. For example,

 
        % arx what-changed --new-tab

will open the report in a new tab of your browser.


The whats-missing Command

Suppose that more than one programmer is checking revisions into a version, Alice and Bob for example.

Alice and Bob both start with working directories and both make some changes. Alice commits several changes. Now Bob's working directory has fallen behind archived development path.

The command whats-missing can be used to tell Bob which patches he is missing:

 
        % arx whats-missing --summary
        patch-N
                summary of patch N
        patch-N+1
                summary of patch N+1 
        ...

For each patch that Bob is missing, whats-missing --summary prints the name of the patch and the contents of the Summary: header from its log message.

The whats-missing command is explained in greater detail in a later chapter (see Patch Logs and ChangeLogs).


Update

So Bob is behind by a few patches, but also has his own modifications.

Diagramatically, we have something like:

 
        Patch Levels    Bob's Working
        in the          Directory
        Archive:
        ------------------------------
 
        base-0
 
        patch-1
        patch-2
        patch-3
        patch-4 --------> bob-0 (Bob's initial working directory)
        patch-5             |
        patch-6             |
        patch-7             V
        patch-8           bob-1 (Bob's working dir with changes)

Bob is missing patches five through eight.

The command update can be used to fix the situation:

 
        % arx update OLD-DIR NEW-DIR

as in:

 
        % arx update bob-1 bob-2

update works in several steps. First, it gets a copy of the latest revision (patch-8 in this case). It also gets a copy of the revision from which OLD-DIR is dervied (patch-4 in this case). Then it uses mkpatch to compute the differences between OLD-DIR and its source revision, and applies those differences (using dopatch) to the latest revision.

In the example, update will create the directory bob-2, with the source:

 
        delta(patch-4, bob-1)[patch-8]

(For information about this notation, see The Theory of Patches and Revisions.)

Applying that patch might cause conflicts. In that case, update will print a message telling Bob to look for .rej files.

As a convenience, update also copies all non-source, non-junk files from OLD-DIR to NEW-DIR (see ArX Project Inventories).

Of course, if Bob only wanted to "partly update", he could do that with an extra parameter to update, as in the example:

 
        # update, but only up to patch level 6:
        # 
 
        % arx update bob-1 bob-2 hello--devo--1.1--patch-6

Finally, update can replace OLD-DIR with the updated directory if given the --in-place flag:

 
        % arx update --in-place OLD-DIR


Replay

update isn't the only way to catch-up with a development path. Another option is replay:

 
        % arx replay old-dir new-dir

Using the same example:

 
        Patch Levels    Bob's Working
        in the          Directory
        Archive:
        ------------------------------
 
        base-0
 
        patch-1
        patch-2
        patch-3
        patch-4 --------> bob-0 (Bob's initial working directory)
        patch-5             |
        patch-6             |
        patch-7             V
        patch-8           bob-1 (Bob's working dir with changes)

and the command:

 
        % arx replay bob-1 bob-2

replay will first copy bob-1 to create bob-2. Then it will apply each missing patch in succession until bob-2 is up-to-date, or until a merge conflict occurs.

Thus, if no conflict occurs, replay computes:

 
        patch-8 [ patch-7 [ patch-6 [ patch-5 [ bob-1 ]]]]

If a conflict occured in, say, patch-6, then replay would compute:

 
        patch-6 [ patch-5 [ bob-1 ]]

and after fixing the conflict, Bob could use a second replay command to apply patches seven and eight.

As with update, replay also copies all non-source, non-junk files from OLD-DIR to NEW-DIR (see ArX Project Inventories).

Of course, if Bob only wanted to "partly replay", he could do that with an extra parameter to replay, as in the example:

 
        # replay, but only up to patch level 6:
        # 
 
        % arx replay bob-1 bob-2 hello--devo--1.1--patch-6

You can use replay to modify an existing directory rather than creating a new directory:

 
        % arx replay --in-place DIR [REVISION]

but be careful: if DIR contains precious local changes, and conflicts occur, or if you simply decide the replay wasn't a good idea, you'll have to do some work to revert the replay.


The Next Version

In simple situations, a version like hello--devo--1.0 will be followed by the next version: hello--devo--1.1 or hello--devo--2.0, for example.

Such a version is called a continuation of the previous version and it is created with create-version.

 
        % arx create-version NEXT-VERSION
        [...edit log message...]
        % arx commit

as in:

 
        % arx create-version hello--devo--1.1
        [...edit log message...]
        % arx commit

Those commands create the base-0 revision of the new version but instead of storing complete source for the base revision, they store a pointer to the older revision which the base revision is equal to.


[ << ] [ >> ]           [Top] [Contents] [Index] [ ? ]

This document was generated by Walter Landry on April, 30 2003 using texi2html