'''Copied from https://launchpad.canonical.com/AbentleyUsingLooms -- I suspect this is now out of date, and that abentley uses [[https://launchpad.net/bzr-pipeline|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: 1. merge into sql-updates 1. maybe resolve conflicts 1. commit 1. up-thread to orm-updates 1. maybe resolve conflicts 1. commit 1. up-thread to web-ui-updates 1. maybe resolve conflicts 1. 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. ## Todo: what doesn't work, desired improvements == 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. {i} 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) = {i} 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. ---- CategoryTipsAndTricks