Copied from https://launchpad.canonical.com/AbentleyUsingLooms -- I suspect this is now out of date, and that abentley uses bzr-pipeline -- jml, 2009-07-21
The loom plugin for Bazaar is a tool designed to fill the same niche as Quilt or Mercurial's Queues. It's best used to help you develop a series of related changes.
Looms are special Bazaar branches containing "threads". Threads are similar to normal Bazaar branches-- you can commit to them, and they each maintain a "line of development". But threads differ because they are ordered-- they form a stack that you can move up and down. They also don't have their own configuration data. They use the loom branch's configuration.
Initial development
When I start out a task, I use a separate thread for each reviewable piece of the work, in the order I expect them to be merged. As an example, my stack for a change that adds a new attribute to a database item might look like this:
- web-ui-updates
- orm-updates
- sql-updates
Note that items are added above older ones, so sql-updates is actually the oldest thread, being at the bottom. It is the one that I expect to be merged first.
I periodically merge from launchpad trunk. When I do, I start with the lowest active thread. So, for example:
- merge into sql-updates
- maybe resolve conflicts
- commit
- up-thread to orm-updates
- maybe resolve conflicts
- commit
- up-thread to web-ui-updates
- maybe resolve conflicts
- commit
(Yes, this is somewhat repetitive, and there's talk of automating it in the looms plugin)
To see the changes introduced in a thread, I use
$ bzr diff -r thread:
Well, actually, I use cdiff from bzrtools, and I have it aliased as tdiff.
I can work on any given thread at a time, and with a bit of fancy footwork, I can even test one thread while developing another.
Reviews
When it comes time to submit a thread for review, I export the threads as normal branches.
$ bzr export-loom ~/launchpad/new-attribute
My ~/launchpad directory is a shared repository with treeless branches, so this completes very quickly. It creates:
- ~/launchpad/new-attribute/sql-updates
- ~/launchpad/new-attribute/orm-updates
- ~/launchpad/new-attribute/web-ui-updates
I actually have a default export location configured, so that I can just run bzr export-loom with no arguments.
I use an alias to do this, and I store the exported branches in a directory under the main branch. In my bazaar.conf I have:
[ALIASES] # To be run in the branch's root directory xl = export-loom ./spool
This makes it easy to move the entire project from lp-branches into lp-branches/attic when I'm done with it. -- MarisFogels
Then I
$ cd ~/launchpad/new-attribute/sql-updates $ bzr push $ bzr review-submit -R tim.penhey@canonical.com
etc, etc.
When my work is reviewed, I create a new thread, e.g. sql-updates2 to make any changes in. This means that I can use diff -r thread: to produce a diff of the changes I've made since the review. I can still do merges and get a clean diff, as long as I merge into sql-updates first, and apply the changes to sql-updates2 using up-thread.
When I've completed these changes, I resubmit using bzr send:
$ bzr send -r thread:..
This gives my reviewer an incremental diff of the changes I've made, and they can even apply it to their local branch.
Managing branch size
Looms can be useful for keeping a feature's linecount down by splitting the feature work into small threads. But you may find yourself in the situation where a thread is too small to submit for review by itself, and it should really be combined with another thread around it. Some fancy threading footwork can clean things up.
The process relies on the knowledge that a thread includes all the revisions from the threads below it.
Lets say this is our loom, with three threads:
$ bzr show-loom medium-changes <= only-10-lines big-changes RocketFuel
We want to clip the only-10-lines thread and pull it into the medium-changes thread, but we don't want to hit the reviewer with a diff from big-changes. We can take a diff of both medium-changes and only-10-lines using the thread: revisionspec. The multi-thread diff can be submitted along with the exported medium-changes branch.
$ # while sitting on the 'medium-changes' thread. $ bzr diff -r thread: | wc -l 400 $ bzr diff -r thread:only-10-line | wc -l 400 $ bzr diff -r thread:big-changes | wc -l 410 $ bzr diff -r thread:RocketFuel | wc -l 987
You can use this technique to slice-and-dice your diffs (and linecounts!) any way you want. For a review, you would submit the slice along with the exported thread from the top of the slice.
Recovering a deleted thread (combine-thread is dangerous)
How can you check if a thread is completely safe to delete? If bzr diff -r thread: shows nothing.
The combine-thread command is dangerous. It should be called delete-thread, because that is what it does, it completely deletes a thread. Nothing is merged with the thread above or below. Your revisions are still there, but they may or may not be referenced by anything.
If you combine-thread on a thread that has been fully merged into the thread above, then your changes are still in that upper thread. If your changes aren't merged into the thread above, then they are in limbo: they are still in the branch repository, but un-referenced.
The same goes for the top-most thread. If you run combine-thread on this, then *poof*, your changes in the top-most thread are in limbo.
To recover those changes, you need to pull them back from limbo by making the branch or thread reference them again. Here is an (untested) process:
First, use bzr head to find your lost revisions in the branch history. Note the revision ID of the latest commit.
Next:
$ bzr create-thread givemebackmycode $ bzr pull --overwrite -r latestcommitrevid
If you forgot to create-thread
Occasionally, you may forget to create a new thread before starting a new piece of work.
Say we have a loom with threads "part-1", and "part-2". You mean to start work on "part-3", but you actually continue "part-2" by mistake.
$ bzr switch part-2 # This creates a new thread that identical to part-2, i.e. it has the part-3 work. $ bzr create-thread part-3 $ bzr switch part-2 # This removes the work that wasn't supposed to go in part-2 $ bzr uncommit
If the work was accidentally committed to part-1, you would have to merge the changes from part-1 into part3.