Bazaar

Bazaar

 




Wiki Tools

  • Find Page
  • Recent Changes
  • Page History
  • Attachments

One obvious application of the loom plugin is as a replacement for the quilt patch management utility.

What Quilt Got Right

The quilt workflow is based on the observation that the immediate product of development work is a series of patches, where each patch implements a particular feature or fixes a specific bug. This is often the case with large open-source projects, but the resulting workflow is a convenient model for all sorts of developers to follow.

The user interface model presented by quilt can be summarized thusly:

The developer manages a stack of patches. Any changes made to the tree are explicitly associated with a patch on the stack. Lower patches on the stack apply to the tree before higher patches, so higher patches can be dependent on lower patches. As the developer works, he moves freely up and down the stack, grouping changes into feature- or fix-specific patches. When a patch is completed, it is sent upstream and removed from the stack.

Why Not Just Use Quilt, Then?

The problem with quilt is that it's not very sophisticated, and it isn't version control-aware, so it knows nothing of renames, adds, removals, etc. Loom can do the same job as quilt, but can be VC-aware and can handle merges and conflicts in a much more sophisticated way.

Current State Of Loom As A Better Quilt

bzr loom does not yet make a perfect quilt. While all of the necessary underlying infrastructure is in place and works well, the user interface lacks some niceties that would really make bzr shine here. None-the-less, persistent users can make loom work for this purpose.

Using Loom To Quilt

Currently, the best approach that I've found is as follows:

I maintain two separate branches. One is my primary "trunk" branch, and the other is my loom branch. The lowest thread on the loom branch is usually identical to the current tip of the trunk branch.

$ bzr branch trunk loom
$ cd loom
$ bzr nick loom
$ bzr loomify

Creating Threads

Create one thread for each feature or bugfix. Dependent changes should be higher threads. For instance, suppose I have two features to add ("foo" and "baz") and one bugfix to make ("bar"), and suppose that, in order to implement bugfix bar, I have to first implement feature foo. I would probably create threads as follows:

$ bzr create-thread feature-foo
$ bzr create-thread bugfix-bar
$ bzr create-thread feature-baz
$ bzr switch feature-foo
$ bzr show-loom
  feature-baz
  bugfix-bar
=>feature-foo
  loom

Committing Changes And Propagating Them To Higher Threads

When I have changes to make in thread feature-foo, I switch to that thread (using either bzr switch, bzr down-thread, or bzr up-thread, as appropriate), make my changes, and commit them. This is a critical moment in the process, however, due to the way that loom propagates changes between threads. Once a new commit has been made, switching up to the next thread implies a merge, and the merge must be committed on higher threads. Normally, this process goes like this:

$ bzr commit -m feature-foo
$ bzr up-thread
All changes applied successfully.
Moved to thread 'bugfix-bar'.
$ bzr commit -m up-thread
Committing to: ...
...
Committed revision ...
$ bzr up-thread
All changes applied successfully.
Moved to thread 'feature-baz'.
$ bzr commit -m up-thread
Committing to: ...
...
Committed revision ...

However, it is disastrous to perform a partial commit in feature-foo and then going up-thread, as the remaining changes are suddenly combined with any pending merges resulting from moving up-thread. Thus, if a partial commit is performed, I first shelve any remaining changes before going up-thread:

$ bzr commit -m feature-foo file1
$ bzr shelve --all -m tmp
Shelving to default/00: "tmp"
$ bzr up-thread
All changes applied successfully.
Moved to thread 'bugfix-bar'.
$ bzr commit -m up-thread
Committing to: ...
...
Committed revision ...
$ bzr up-thread
All changes applied successfully.
Moved to thread 'feature-baz'.
$ bzr commit -m up-thread
Committing to: ...
...
Committed revision ...
$ bzr switch bugfix-bar
All changes applied successfully.
Moved to thread 'bugfix-bar'.
$ bzr unshelve --all 00
Unshelving from default/00: "tmp"

And then I continue working, and commit the remaining changes to the appropriate thread.

If I forget to shelve changes before moving up-thread with pending merges, the remaining uncommitted changes become intertwined with the pending merge, and can potentially be difficult to extricate. This can be a frustrating situation and is one of the primary warts of using loom as a quilt replacement.

Pulling Changes Back To The Trunk Branch

Once I'm satisfied with the state of the lowest thread, I merge it into the trunk branch and then clean up the loom:

$ cd ../trunk
$ bzr merge -r thread:loom..thread:feature-foo ../loom
All changes applied successfully.
$ bzr revert --forget-merges
$ bzr commit -m 'Implemented foo.'
Committing too ...
...
Committed revision ...
$ cd ../loom
$ bzr switch feature-foo
All changes applied successfully.
Moved to thread 'feature-foo'.
$ bzr combine-thread
Combining thread 'feature-foo' into 'loom'
All changes applied successfully.
Moved to thread 'loom'.
$ bzr pull ../trunk
...
All changes applied successfully.
Now on revision ...
$ bzr up-thread
All changes applied successfully.
Moved to thread 'bugfix-bar'.
$ bzr commit -m up-thread
Committing to: ...
...
Committed revision ...
$ bzr up-thread
All changes applied successfully.
Moved to thread 'feature-baz'.
$ bzr commit -m up-thread
Committing to: ...
...
Committed revision ...

There are a few things to note here:

  • After merging into the trunk branch, I do bzr revert --forget-merges. This makes the merge appear to be a single commit in the trunk history, which is what I want.

  • Pulling the new trunk tip into the loom base thread must be followed by another round of propagation up the loom. Don't forget to shelve any partial changes, if you have them, before doing this!