Next: Development Branches -- The star-merge Style of Cooperation, Previous: Shared and Public Archives, Up: Collaborating With Other People
In this chapter, we'll begin to explore the concept of branching, which you may be familiar with from other revision control systems.
If you are already familiar with the concept, you should be aware that
branching in arch
almost certainly goes far beyond what you are
accustomed to.
Regardless of whether or not you are familiar with the concept, fear not – we'll be starting slow:
Let's suppose for the moment that the hello-world
project is making
its sources available as a public, read-only mirror (see
Shared and Public Archives).
Early on, you (someone not involved in the hello-world
project)
decides that you'll want to use their program, but that you'll need to
make some local changes.
As a sort of toy example, let's suppose that you've decided that in your environment, saying hello world is unacceptable – you really require the more correctly punctuated hello, world.
Now, here's the problem: sure, you can download their sources and make that change. But meanwhile, the project is going to keep working. They're going to keep making changes. So, you'll be faced with a perpetual task of repeatedly downloading their latest sources and copying your changes to their latest version.
arch
can help automate that task, and this chapter explains how.
In the examples that follow, you'll be changing roles. Instead of
"playing" Alice or Bob, the programmers on the hello-world
project, you'll be playing Candice: a third party.
Let's start by giving Candice her own archive to use, and making that the default archive:
% tla make-archive candice@candice.net--2003-candice \ ~/archives/2003-candice % tla my-default-archive candice@candice.net--2003-candice default archive set (candice@candice.net--2003-candice)
(You can review what those commands do by reading Creating a New Archive.)
Candice needs to create a hello-world
project in her own archive.
She can use:
% tla archive-setup hello-world--candice--0.1
She doesn't have to use the same project name that Alice and Bob are using and, in fact, in this case she chose a different branch name. (To review those commands, see Starting a New Project.)
When Alice and Bob created their archive, they used import
to create
the first revision. Since we're creating a branch, we'll use a
different command.
For the sake of example, let's suppose Candice is going to start from
the patch-1
revision of Alice and Bob's archive:
% tla tag \ lord@emf.net--2003-example/hello-world--mainline--0.1--patch-1 \ hello-world--candice--0.1 [....]
There are a few things worth noting about that command.
First, note that we used a fully qualified revision name to refer to
Alice and Bob's patch-1
revision. That's because that revision is
in some archive other than the current default archive. (See
Working with Several Archives at Once in Shared and Public Archives.)
Next, note that we specified the patch-1
revision explicitly. If we
had left of the --patch-1
suffix, then the tag
command would
assume we meant the latest revision in Alice and Bob's archive
(which happens to be patch-3
).
After using tag
, Candice now has a new revision in her archive:
% tla revisions --summary hello-world--candice--0.1 base-0 tag of lord@emf.net--2003-example/hello-world--mainline--0.1--patch-1
She can retrieve that revision in the usual way:
% tla get hello-world--candice--0.1 hw-candice [...] % ls hw-candice hw.c main.c {arch}
Nifty arch Feature: If you've followed along closely, you should have noticed that Candice created a branch in her archive from an arch revision stored in another archive entirely. In our examples, both of these archives happen to be on the local file system but that isn't necessary: Candice could have formed her branch even if she was accessing Alice and Bob's archive over the network.
Usage Caution: Candice's job isn't quite done yet. The next section explains another step she'll probably want to take.
Candice used tag
to create a branch from Alice and Bob's archive.
When she uses get
to check-out that revision, what happens? Roughly
speaking, arch
notices that the revision is a branch, then consults
Alice and Bob's archive to really get the source.
The question then arises: what if Alice and Bob's archive "goes
away"? As things stand, if that happens, Candice will no longer be
able to get
from her branch.
She can fix that though by caching in her archive all of the information needed to build the revision:
% tla cacherev hello-world--candice--0.1--base-0 [...]
and confirm that that worked with:
% tla cachedrevs hello-world--candice--0.1 hello-world--candice--0.1--base-0
Thereafter, arch
will no longer rely on Alice and Bob's archive to
retrieve Candice's base-0
revision.
Earlier, Candice created her branch and used get
to check it out.
Let's examine that tree:
% cd ~/wd/hw-candice % tla log-versions candice@candice.net--2003-candice/hello-world--candice--0.1 lord@emf.net--2003-example/hello-world--mainline--0.1
Note that Candice's tree has patch logs both for Alice and Bob's versions, and for her own branch:
% tla logs --summary \ lord@emf.net--2003-example/hello-world--mainline--0.1 base-0 initial import patch-1 Fix bugs in the "hello world" string % tla logs --summary hello-world--candice--0.1 base-0 tag of \ lord@emf.net--2003-example/hello-world--mainline--0.1--patch-1
There are not any later changes on Candice's branch:
% tla missing hello-world--candice--0.1 [no output]
but recall that Alice and Bob are already up to patch-3
:
% tla missing -A lord@emf.net--2003-example \ hello-world--mainline--0.1 patch-2 patch-3
After the initial tag
, Candice can commit changes to her branch in
the usual way.
Let's suppose that she has edited hw.c
so that it now reads (in
part):
% cat hw.c [...] void hello_world (void) { (void)printf ("hello, world\n"); } [...]
and that's she's prepared a log message:
% cat ++log.hello-world--candice--0.1--lord@emf.net--2003-candice Summary: Punctuated the output correctly Keywords: This program should say "hello, world" not "hello world".
Now she can simply commit in the usual way, creating her own patch-1
revision:
% tla commit [....] % tla revisions --summary hello-world--candice--0.1 base-0 tag of \ lord@emf.net--2003-example/hello-world--mainline--0.1--patch-1 patch-1 Punctuated the output correctly
Meanwhile, Alice and Bob have gone on to create their revisions
patch-2
and patch-3
. How can Candice add those changes to her
branch?
Well, really, arch
provides lots of techniques. Using commands
we've already introduced, she could use either update
or replay
.
In this example, we'll demonstrate using replay
.
% cd ~/wd/hw-candice % tla replay -A lord@emf.net--2003-example \ hello-world--mainline--0.1 [...]
Note that we used a -A
argument to say which archive we are
replaying changes from, and a version name to say which changes we
want. In this case, replay
applied the changesets for patch-2
and
patch-3
to Candice's tree.
This use of replay
is a form of merging: Candice's local changes
have been merged with Alice and Bob's mainline
changes.
Learning Note: If you're following along with the examples, you
should examine hw.c
and notice that Candice's change to the printf
string and Alice's addition of a "copywrong" notice are both
included.
Learning Note: You should also check out a second copy of Candice's
patch-1
revision and experiment with doing the same merge using
update
instead of replay
. You might have to look at tla update
-help
to figure out exactly what options and arguments to provide.
Note also that, so far, we've only made these changes to Candice's project tree – they haven't been checked into Candice's archive. To actually record the merge in her archive, she'll have to make a log message and commit in the usual way (see Checking-in Changes).
There is, however, one more convenience to point out. When Candice
writes her log message, she'll presumably want to note that the merge
took place and what it involves. arch
includes a command whose
output is ideal for inclusion in such a log message:
% cd ~/wd/hw-candice % tla log-for-merge Patches applied: * lord@emf.net--2003-example/hello-world--mainline--0.1--patch-3 added copywrong statements * lord@emf.net--2003-example/hello-world--mainline--0.1--patch-2 commented return from main
What did tag
do? Let's look at Candice's archive:
% cd ~/archives % cd 2003-candice % cd hello-world % cd hello-world--candice % cd hello-world--candice--0.1 % ls +version-lock base-0 patch-1 patch-2
Of particular interest is the base-0
revision – the one created by
tag
:
% cd base-0 % ls CONTINUATION hello-world--candice--0.1--base-0.patches.tar.gz hello-world--candice--0.1--base-0.tar.gz log % cat CONTINUATION lord@emf.net--2003-example/hello-world--mainline--0.1--patch-1
The file CONTINUATION
identifies this revision as a tag
revision.
Its contents tell us what revision we branched from.
The changeset for this revision (....patches.tar.gz
) was also created
by tag
. If you explore that changeset (recall get-changeset
and
show-changeset
) you'll see that all it does is add a log entry to the
tree's patch log.
The source file (...base-0.tar.gz
) was created by
archive-cache-revision
. It contains a complete copy of Candice's
base-0
revision. Since that file is there, get
is not obligated
to look at Alice and Bob's archive to construct this revision.