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.
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”.
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.
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.
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.
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 |
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 |
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 |
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 |
In both Git and Bazaar, merging is done in a pulling manner.
git merge branch |
bzr merge url |
bzr commit |
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 |
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 |
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.