Continuing my exploration of distributed version control systems, I decided to take a quick look at the Git:
A single git repository can maintain multiple branches of development. To create a new branch named “experimental”, use:
$ git branch experimental
If you now run
$ git branch
you’ll get a list of all existing branches:
experimental * master
That’s strange, I thought. Bazaar does it a bit differently. In Bazaar, the branches are often stored in a shared repository, which is just a special folder that contains the branches in it as subdirectories, but unlike Git, the repository is typically a “normal” folder that contains branches which are stored as subdirectories in plain sight to the developer.
Here’s an example from the Bazaar User Guide:
repository/ # Overall repository +- trunk/ # The mainline of development +- branches/ # A container directory | +- foo/ # Branch for developing feature foo | ... +- tags/ # Container directory +- release-X # A branch specific to mark a given release version ...
Hmm… I actually like how Git does it. Git “already works” with the way I have my existing projects setup. I don’t want to move my projects to match the directory structure shown above. Is there any way to use Bazaar in a Git-like manner? Well, I suppose you already know the answer to that, as I wouldn’t have much of a blog post to write if there wasn’t!
Setting up a Git-like workflow with Bazaar
Being completely new to Bazaar, and to DVCS’ in general, I decided to ask the folks over at #bzr. They were very helpful, and fairly quickly ‘mzz’ had an answer:
First, we cd into our project, which is already setup as a bazaar branch:
Next, we run the following command:
bzr init-repo --no-trees .bzr-repo
That creates a hidden shared repository inside the project folder called .bzr-repo. We add the --no-trees option to tell Bazaar not to create unnecessary copies of the working tree.
Note that this is quite different from how repositories in Bazaar are normally used, usually they’re the parent directory.
bzr ignore .bzr-repo
We add the repository itself to the ignore list so that it’s not tracked.
Next, we commit the changes and create the main branch, called “trunk”:
bzr commit -m "added .bzr-repo to ignore list" bzr branch . .bzr-repo/trunk
At this point we have two branches, the one in .bzr-repo/trunk and the branch we started with. This is no good, we want to be deal with only one branch at a time—the one we’re currently working with, and we want that branch to be one of the ones in .bzr-repo.
Thus enters the concept of a lightweight checkout. A checkout is very similar in concept to its SVN counterpart, you have a folder were you can make changes to files, and when you commit them they are sent off to some central location. One of the main differences between checkouts in Bazaar and checkouts in SVN is that in Bazaar the revision history is stored locally within the checkout itself. But in our setup, we don’t want that since each branch is stored locally anyway. Having two copies of it wouldn’t offer any advantage and would just take up space. A lightweight checkout lets us have a checkout without a revision history.
We can tell Bazaar to change the current branch into a checkout that points to .bzr-repo/trunk by using the reconfigure command:
bzr reconfigure --lightweight-checkout --bind-to .bzr-repo/trunk .
Now we can continue our work as usual. Let’s test this out by adding a new file to the project:
$ echo "Version 1.0" > CHANGES
$ bzr add CHANGES adding CHANGES $ bzr commit -m "added CHANGES" Committing to: /Users/gslepak/myproject/.bzr-repo/trunk/ added CHANGES Committed revision 2.
Everything seems in order. We can now use Bazaar like Git:
$ bzr branch . .bzr-repo/experimental Branched 2 revision(s). $ bzr switch .bzr-repo/experimental Tree is up to date at revision 2. Switched to branch: /Users/gslepak/myproject/.bzr-repo/experimental/
Since Bazaar doesn’t have an equivalent to the args-less git branch to list the available branches, we just use plain-old ‘ls’:
$ ls .bzr-repo/ experimental/ trunk/
At this point you might be wondering if there’s a way to get around having to type out the path to the repository each time you use bzr branch and bzr switch…
Introducing the ‘repoalias’ Plugin
I asked that question on #bzr and mzz snapped into action, within a few minutes he had a working plugin ready that did just that. Needless to say my head was reeling from his Python kung-fu.
Repoalias allows you to reference the branch’s repository like so:
bzr branch . repo:experimental bzr switch repo:experimental ... do work ... bzr switch repo:trunk bzr merge repo:experimental ... etc ...
Getting the plugin is simple:
mkdir -p ~/.bazaar/plugins # create the plugins folder if it doesn't exist cd ~/.bazaar/plugins bzr branch lp:~marienz/+junk/repoalias
That’s it! Many thanks to mzz and the folks at #bzr for helping me understand this stuff!