[ << ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
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.
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.
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.
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 |
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 |
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.
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 |
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.
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.
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).
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 |
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
.
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] | [ ? ] |