Friday, May 30, 2008

On History Rewriting

This is just a short note on history rewriting.

During my conversion process, I made some significant changes to the bzr-fast-export tool, as it can’t export some repositories by default. As I was hacking away quickly, I made some fast bzr commits, so that I could make nice patches out of them later on.

Today I wanted to do just that, but it appears to be impossible to rewrite your history with Bazaar. I would like to merge some commits, reorder them, change the log message and split one commit up in two parts. Also, I’ll have to adjust the author info, as I didn’t set it up correctly before.

Not too difficult, you’d think. However, I can’t figure out how to do it. The best thing I’ve found is bzr uncommit, which will return you to a previous state. In order to work with this, I’ll have to export a diff for every commit I did, then revert to the parent commit, apply a patch, and commit it again. If I want to split up a commit, I’ll either have to install and use the shelve plugin , or split up the patches myself.

Compare this to Git’s excellent rebase —interactive script. It will allow you to do everything I just mentioned, and then some. This has obvious advantages: you don’t have to worry about your patch series until you’re done with it. Some changes might not be obvious from the start, and being able to edit a log message to make it more clear as valuable tool. With Bazaar, once you’ve committed, you’re pretty much committed to it (pun intended). You’ll have to think ahead of time what you’re going to commit, in what order, and with what message. Obviously I prefer the freedom of Git in this case.

Tuesday, May 27, 2008

Import tools

The last few days I have spent some time using the different import tools that exist. Basically there are two ways to convert a repository: by using some tool-native tool, or by using the fast-{import,export} tools.

A bit of history.

Somewhere in 2006, Git introduced the git fast-import tool. It was created to allow fast importing of tarballs and to allow other revision systems to export their data easily and fast to Git.

Examples of front-ends are cvs2svn and hg-fast-export.py, which allow exporting CVS and Mercurial repositories to Git.

In the mean time, more importers and exporters have been created. For example, Bazaar has both a bzr fastimport plugin and an export script. Git has also implemented a git-fast-export, which should allow you to export your Git repository to any of the importers. Mercurial does not have a fast-import variant yet.

The reality

The reality, however, is that it is very difficult to make these tools work together. Git’s fast-import tool seems the most robust and is willing to take in anything well-formed. There was a bug in the fast-export tool when having a commit with multiple parents, but this has been fixed since.

The hg-fast-export tool also seems to work fairly well. It exports all branches it has, and is not likely to crash. It has succesfully exported all the repositories I gave it.

Bazaar’s tools seem to have the most problem. The fast-import front-end will crash on invalid encodings and other peculiarities that Git’s tool seems to have no problem with. The fast-export tool has several problems which I tried to fix. One of these is handling ghost commits, which is a somewhat bizarre feature of Bazaar where you can say a commit was a merge without supplying one of its parents. When Bazaar has recursive renames (for example, renaming “a/” to “b/” and “a/a” to “b/c”) it will provide output that is invalid for git-import. I also get a different number of revisions after the import is complete. I’m not sure yet what’s going on there. Furthermore, Bazaar’s tool might as well be called slow-import, as it can take a day to import a somewhat large repository.

The same was true when importing the Emacs repository; I couldn’t find any way to convert it into a Git repository. Currently I’m using the Emacs repository on repo.or.cz, but that one differs in history from the Bazaar one.

HG-convert

As Mercurial does not have a fast-import tool, I have to use the “hg convert” command/plugin to import repositories in Mercurial. This tool seems to crash every so often, especially if you provide it with a non-standard Git repository, like git.git or the linux kernel. I’m also not sure if it handles branches correctly; sometimes it seems to import them, and sometimes it seems to just ignore them. As Mercurial has no way to import Bazaar repositories, I had to import the Git versions of them. This means that most conversions have a different number of commits in all three versions.

The branching problem

All three systems have a different way to handle branches. With Git, branches are just references to specific commits that are kept totally out of the repository history. Mercurial has a file within the repository called .hgbranches that names the branches and which allows you to see the history of the branches. Bazaar seems to have the most bizarre way of keeping branches. They use the old and confusing concept of SVN’s “branches are directories”. Especially when importing this can be a bit difficult. The bzr fast-import tool allows you to import multiple branches, and they will be created as different directories. I’m not sure yet how to handle this. Is there a way to get the total number of revisions of all branches? What happens if I delete a branch, can I get it back easily? Will space be freed in the repository after deleting the branch? Can I switch between branches easily, or do I need to keep these working trees checked out?

All this vagueness and general incompatibility make me think about dropping branch support in my conversions and only work on a head branch. I’ll still do benchmarks on branching and merging speed, but just don’t import all the branches.

Meet the candidates

As a first real post, I’d like to introduce you to the candidate repositories that will be used in the performance tests. This list is not final yet, as the importers can have problems with anything remotely weird. I tried to pick a range of projects from each system.

Bazaar repositories

I had the most trouble finding suitable projects for Bazaar. While there are a lot of small projects, there’s almost no large project that has chosen Bazaar for their version control. The WhoUsesBzr wiki page lists some large projects, for example Drupal. However, their official development still takes place in SVN or CVS, which means these clones miss any branching / merging.

  • Emacs Finally, I settled on emacs. Emacs recently switched to bazaar. Their choice was mostly motivated by political reasons, and there have been some complaints, but most projects seem to have complainers when switching from repository. This is a big repository: it has almost 90000 commits and its repository is 300MB. It has a working tree of 104MB, which perhaps makes it one of the biggest repositories in the test.

  • Pkg-config. This is the smallest repository in the test. The repository is 1.8MB in size, with a working tree of less than a megabyte. It has just 187 commits.

  • Mailman. This is reasonably large repository. It has 6700 commits, a repository of 73MB and a working tree of 20MB.

Mercurial repositories

I found a couple of nice mercurial repositories that were used in the tests:

  • Mozilla-central. This is one of the repositories found on mozilla’s site. It has a repository of 205MB, it has more than 15000 commits and a working tree of 284MB, which makes it the largest repo in the test.

  • dovecot. Dovecot’s repo has 7500 commits, is 14MB with a working tree of 6MB.

  • Octave. Octave is an open-source clone of mathlab, without all the cool packages. It has just 8000 commits, but a repo of 60MB and a working tree of 29MB.

Git repositories

This was somewhat challenging too: while there are a lot of projects using Git, almost all the importers have trouble importing them. I will discuss the importers in another post, so I’ll just list the projects here.

  • Cairo. This is the smallest Git repository I’ve used. Cairo has a mostly linear history, with some merges happening. The repository has only about 5000 commits, but is still 16MB in size. This is probably because the project is quite large: the working directory is 10MB.

  • coreutils. Coreutil’s repository is about 30MB. It has around 25000 commits and a working dir of 9MB. It has some merges, but is mostly linear, like Cairo’s.

And the final candidate…

I had a lot of trouble finding the last repository. At first I wanted to use Git’s repository itself. However, it uses some octopus merges (merges with more than 2 parents) which cannot be imported correctly by “hg convert”, which ignores them. Furthermore, there was a bug in git-fast-export which made “bzr fast-import” crash on them.

Similarly I had troubles importing both the Linux-2.6 and Wine, on which the “hg convert” tool crashes because of an invalid byte encoding issue. Mercurial also had troubles importing the VLC repository, while bzr-fast-import couldn’t handle the Rubinius repository. Therefore, I’m still looking for a third repository to use with Git.

Bazaar, Git, Mercurial comparison: Introduction

This blog will describe my adventures in comparing different version control systems. In particular, I will look at three distributed systems: Bazaar, Mercurial, Git.

Why?

There are already some existing benchmarks between these system. However, most of them are bogus in some way. For example, the Git Benchmarks are mostly outdated. Bazaar has some benchmarks too, but these measure the uninteresting tasks. There are some other benchmarks, but these are small scale, don’t specify how the measurements were done and generally aren’t a good measure.

Performance, of course, isn’t everything. If two system are “fast enough”, then you shouldn’t care about which one to pick only on performance. However, if a system is so fast that you can do things you couldn’t do before (like merging within a second, or displaying differences two branches instantly), then performance becomes a factor. If you’re working on a large repository, and your log command takes several seconds to run, then performance is a factor too.

What’s wrong with Bazaar’s benchmarks?

Bazaar on first sight seems to have made some nice benchmarks. However, if you look more closely, you will see that it lacks in several ways:

  • They measure project size wrongly. For example, Git uses hard links when cloning a repository, so repository size is not doubled. These benchmarks do not take that into account
  • They don’t use full repository history. Their benchmarks are based on importing a single tarball from a project. This does not tell us anything about how a project scales in time. As we will see in future posts, Bazaar for example scales badly on a repository with a large amount of commits.
  • They do not measure useful things. Things that they do measure, for example, are time for the first import. However, in my opinion, this is not a measurement to make a final decision on, as importing a project will only be done once.

Bazaar’s benchmarks are just an example of what is wrong with existing benchmarks; however it should illustrate the problem.

Comparison

So then, what will I measure? This blog will test the performance of all three systems on existing repositories. These repositories will differ in size, though there is an emphasis on bigger repositories (with tens of thousands of commits). To compare the systems, all repositories will be converted to all systems. Three native repositories will be picked from each system, so conversion shouldn’t play a factor in performance.

I will not look at the time it takes to convert the repositories, as these one-time tasks should play no role in the final developer workflow. I will look at things that you’ll actually do when working in a repository: merging branches, branching off, repository size and size increase, the time it takes to diff, commit or ask the status of your repository. These quantitative measurements should be acceptable for everybody and offer little room for discussion.

However, as said before, performance isn’t everything. Part of this series will also look at the qualitative aspect of the systems: how easy is it to do different tasks? What workflows do the systems allow? How reliable is the system: if I kill a process halfway in committing, will it hurt my repository? What if I corrupt some data? These posts will be somewhat subjective and offer room for discussion.

Finally, I’m not without an opinion of myself. Some of my posts will be more like columns on what difficulties I encounter during my tests. I have more experience with some systems than with others, so I can be wrong sometimes. These posts will allow others to correct me and offer another point of view.

Finally

The first posts will be on the conversion of the different systems. I’m currently mostly done, however it’s a hard task find repositories that can be converted to all systems. I hope readers will find this information useful, or at least entertaining :)