The Hackerlab at `regexps.com`

## Elementary Branches -- Maintaining Private Changes

up: arch Meets hello-world next: Some Usage Advice -- Making Private Mirrors prev: Selected Files Commit

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:

### A Branching Scenario -- The Need for Private Changes

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.

### Making a Branch from a Remote Project in a Local Archive

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:

            % larch make-archive lord@emf.net--2003-candice \
                                 ~/{archives}/2003-candice

            % larch my-default-archive lord@emf.net--2003-candice
            default archive set (lord@emf.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:

            % larch make-category hello-world
            % larch make-branch hello-world--candice
            % larch make-version 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:

        % larch 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.)

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` ).

### What tag Just Did

After using `tag` , Candice now has a new revision in her archive:

       % larch 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:

       % larch 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.

### Caching a tag Revision

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:

       % larch archive-cache-revision hello-world--candice--0.1--base-0
       [...]

and confirm that that worked with:

       % larch archive-cached-revisions 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.

### Exploring the New Branch

Earlier, Candice created her branch and used `get` to check it out. Let's examine that tree:

            % cd ~/wd/hw-candice

            % larch logs
            lord@emf.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 version, and for her own branch:

        % larch log-ls --summary \
                lord@emf.net--2003-example/hello-world--mainline--0.1
        base-0
            initial import
        patch-1
            Fix bugs in the "hello world" string

        % larch log-ls 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:

            % larch whats-missing hello-world--candice--0.1
            [no output]

but recall that Alice and Bob are already up to `patch-3` :

            % larch whats-missing -A lord@emf.net--2003-example \
                    hello-world--mainline--0.1
            patch-2
            patch-3

### Making a Local Change

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:

       % larch commit
       [....]

       % larch 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

### Updating from a Branched-from Version

Meanwhile, Alice and Bob have gone on to create their revisions `patch-2` and `patch-3` . How can Alice 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

            % larch replay --in-place \
                    -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 `larch 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

      % larch 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

### How It Works -- tag and Elementary Branches

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   =README         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. It's 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-patch` and `patch-report` ) 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.

arch Meets hello-world: A Tutorial Introduction to The arch Revision Control System
The Hackerlab at `regexps.com`