Continuing my exploration of distributed version control systems, I decided to take a quick look at the Git:
Managing Branches
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:
cd path/to/myproject
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 .
That’s it! 🙂
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!
I’m using this plugin myself with a slightly different repository setup: I have one repository per project in ~/bzr, which is a symlink to a network filesystem (a server on my LAN). My actual work is done in lightweight checkouts in ~/src. That means that if I switch branches it looked like “bzr switch ~/bzr/projectname/branchname”. This plugin turns that into “bzr switch repo:branchname”, which is less typing.
The plugin is a little odd because (and this differs from most other vcs) what bzr calls a “repository” is purely an optimization: you can do the same thing without a (shared) repository and bzr will simply use a separate repository for each branch, using more disk space. This plugin breaks the rule that you do not need to care about repositories a little, but it’s convenient enough that I will probably keep using it.
Excellent post! Especially enjoying the Repoalias plugin. Nice work.
You copied the wrong segment from the Bazaar user guide — specifically, the “svn” layout. Bazaar doesn’t have a preferred layout, because directories can be placed anywhere and still work.
For example, this is my layout:
+ project/
–+ trunk/
–+ add-feature-foo/
–+ bug-12345_bar-crashes/
Thanks John, my point was simply to illustrate a common Bazaar layout, not to suggest that there is a preferred one. Note how the one I copied is actually rather similar to yours.
Perhaps I was unclear. The layout you copied is *not* a Bazaar layout at all. Tags are not managed as separate branches in Bazaar, but are per-branch objects managed using the “bzr tag” command. The example you used is how a repository would be arranged in Subversion.
The Bazaar version is a bit further down the page; it is the second code listing in section 10.3.1.1
Ah, I follow you now, I see that I did not state that in the post, thanks for pointing that out. The layouts recommended by the guide are similar enough in principle to the SVN layout though (and different enough from the Git style), that I hope the point still gets across in the post. Meaning, why and how one would want to use the Git-style.
I like the idea of being able to branch and switch between local branches easily, but something that’s not mentioned is how to push those branches back to the remote repository. With git I can use git push –all (I usually do want all my branches to be backed up on the server, no matter how trivial), but it’s not obvious how to do that with this setup. Any thoughts?
I’m by no means a bzr expert yet, I would try asking on the #bzr irc channel, there are lots of helpful folks there, or try the mailing list.
Pingback: Ali Sabil (asabil) 's status on Wednesday, 23-Sep-09 12:17:38 UTC - Identi.ca
The argument to ‘init-repo’ should be ‘–no-trees’, not ‘–no-tree’. ‘–no-tree’ is used for creating a single branch without a working tree.
bzr init-repo –no-trees .bzr-repo
Thanks for catching that David! I’ve updated the post to that effect.