Git and Bazaar

Subversion interoperability

Because of its popularity, I consider Subversion interoperability the most important feature of all other source control software. Distributed source control has certain advantages, you can watch a Linus Torvalds tech talk. He has given a worthwhile lecture about version control software. Even if you believe he’s biased towards Git, it’s still worth considering his arguments for distributed source control.

Given the popularity of Subversion, the most common scenario would be to use distributed source control software, pull source from a Subversion repository, work with it having several branches, and finally commit your changes back to Subversion.

There are many distributed source control projects, but having a limited amount of time, I only tested Bazaar and Git.

This tutorial was inspired by the excellent Git-SVN Crash Course.

Differences between Git and Bazaar

Branch vs branch container

In Bazaar, a directory tree is the branch. In Git, it’s a branch container. This leads to different ways of using those programs. For instance, if you want to create a new Bazaar branch, you need to create a new directory tree. In Git, you do it in your current one.

Bazaar model is simple: since you can have only one branch in one tree, it’s enough to give a directory name and you can push, pull and merge. In Git, it can get complicated, because you either need to specify a branch, or the branch is assumed, for instance “the active branch”.  

Moving your changes through network

I see two major points in favor of Bazaar. First is that you need to install Git on the server you want to upload your changes to. If you happen to use server such as Dreamhost, you need to set up your own Git installation; compile it, install in $HOME/bin, set the $PATH and so on. And should you decide to upload your code to another server, you need to do that again. Bazaar can read and write via ssh (sftp) and it doesn’t require remote Bazaar installation.

The second point is the ease of remote repository creation. With Bazaar, you can just specify new URL, add --create-prefix option and it’s done. With Git, you need to log on to the server and you need to create a repository from the command line.  

Subversion metadata

When cloning Git repositories, Subversion metadata is omitted; you can’t clone your branch and push to Subversion from there. In other words, you can only send your changes back to Subversion from where you pulled it with git-svn.

Unlike Git, Bazaar is able to push changes back to Subversion from any branch. You can pull from Subversion, make another branch, make your changes and push back to Subversion from there.  

Prerequisites

This tutorial was written using Git 1.5.2.1 and Bazaar 0.17.0.

Getting everything working is not that easy at the moment of writing. Subversion interoperability for Bazaar requires new version of Subversion. I couldn’t install it on my Gentoo box using common Portage repositories. Ubuntu Feisty Fawn has Subversion patched, but it has Git 1.4, which is sufficiently different from 1.5 for this tutorial not to work. In “other words”:

  Gentoo 2007.0 Ubuntu 7.04
Subversion 1.3 (too old) 1.3 patched
Git 1.5 1.4

To solve that, I compiled Git from sources on Ubuntu 7.04.

To walk through that tutorial, you need a Subversion repository that you have write access to. If you don’t have any write access to any Subversion repository, you won’t be able to commit back to Subversion, which one hand is the whole point of this tutorial, but on the other hand, this tutorial is just as useful for people who want to take source code from some project available on, say, Sourceforge, and play with it. This was the longest sentence in this tutorial. If you managed to read it, you’ve already got past the worst part.

The tutorial

Getting the sources from Subversion

Let’s assume you have a standard, recommended Subversion repository layout with trunk, branches and tags.

.
|-- branches
|-- tags
`-- trunk

You can import all branches and tags into Git, but you can only import trunk to Bazaar, hence url/trunk.

git-svn clone -T trunk -b branches -t tags url
bzr branch url/trunk

Making local changes

You can edit some files. When you’re done you need to commit them. Here’s the difference between centralized and distributed source control: you’re not committing to any server. You’re committing your changes to your local branch.

git commit -a bzr commit

Sending changes back to Subversion

git-svn dcommit bzr push url/trunk

It might happen that somebody updated the Subversion repository. You can’t just commit your changes now, because… you’ve already commited them! You’ve committed them to your local branch. And since somebody has committed something to the Subversion repository, the branches have diverged. You need to merge them.

Now, merging in Bazaar or Git is something very different from what you have in Subversion. You don’t have to remember any revision numbers. You don’t have to worry about all that crap, and you don’t need to spend half a day on it. You can just merge.

It’s a little different in Git than in Bazaar. In Bazaar, you merge Subversion changes into your branch. In Git you need two steps. First, you update a remote branch called trunk, and then you merge this trunk with your branch. Another difference is, that in Bazaar, you need to commit after a merge. In Git, if there are no conflicts, you don’t need to do that.

git-svn fetch bzr merge url/trunk
git merge remotes/trunk  

At this point, since you’re merging, you can get conflicts. It’s your job to resolve them. Git has something called git-mergetool. It uses Emacs by default. If you want, you can ask it to use vim.

git-mergetool -t vimdiff bzr resolve file
git commit -a bzr commit

Now, you’ve got the remote changes merged, code conflicts resolved and committed. In other words, you have merged branches that have previously diverged. You can push your changes to the server.

git-svn dcommit bzr push url/trunk

Creating a new branch

This means different things for Git and for Bazaar. In the former, you work in the same directory tree, in Bazaar you create a new one.

git checkout -b branch
bzr branch file:///path new-path

Merging one branch to another

In both Git and Bazaar, merging is done in a pulling manner.

git merge branch
bzr merge url
bzr commit

Pushing your changes to a USB pendrive

If you want to move your stuff between few computers, you can use a USB pendrive. The *.git directory naming is a Git convention for bare repositories.

git clone --bare path /media/Pendrive/my-project.git
bzr push file:///new-path --create-prefix

Here, path denotes a path to a directory tree with your sources. There’s another difference between Git and Bazaar; Git doesn’t have --create-prefix option. In order to create a new directory tree on your pendrive, you need to clone, which means pulling rather than pushing.

You can now clone your pendrive repository to your local disk on a different computer.

git clone /media/Pendrive/my-project.git my-project
bzr branch file:///media/Pendrive/my-project

Sending changes over the network

A USB pendrive is not enough for me; I often want to send changes over the network. A fairly easy solution would be to use a server where you have an account accessible via ssh. If you have it installed, you can mount a remote directory and use it as if it was local.

sshfs -C user@example.com:/home/user ~/foo \
-o idmap=user -o workaround=rename \
-o uid=$UID -o gid=$(id -g)

Don’t ask me about those strange options. They are here to fix something, I’ve worked them out quite a while ago and any information about them was washed away by a torrent of articles from reddit.com about Haskell.

If you user Bazaar, sending over the network is easier. You can just:

bzr push sftp://user@example.com/home/user/my-project \
--create-prefix

The --create-prefix option is needed only the first time. Afterwards, you can:

bzr push sftp://user@example.com/home/user/my-project

Afterword

This tutorial is only a basic walktrough and it’s not meant to be very thorough and/or complete. Suggestions are appreciated, you can drop me an e-mail.

python -c "print 'bWFjaWVqLmJsaXppbnNraUBnbWFpbC5jb20='.decode('base64')" 

Last modified on Sat Jul 14 11:05:53 +0100 2007.