2006-08-23

Comparing Mercurial to Bazaar-NG

I want to be able to create local revision repositories easily and have the possibility of having remote backups. I decided to take a look at Mercurial (a.k.a., Hg) and Bazaar-NG (a.k.a., bzr).
I came up with several use-cases to use as a basis of seeing what steps are necessary to pull off what I want; add a file to a new repository, commit it, create a branch, edit and commit in the mainline and update the branch, and create a conflict in committed differences between both branches which is saved to a file that is used to apply the conflict and resolve it.

Here are the steps I took for Hg:

# ... : Section
# ??? : Question
# !!! : Unexpected problem
# -> : command leads to something not showable on command-line

# Create a new repository and see what files need to be added to it.
> mkdir hg_head
> cd hg_head
hg_head> echo "line 1\line 2" | tee file.txt
hg_head> hg init
hg_head> hg status

# Add/commit file.txt .
hg_head> hg add file.txt
hg_head> hg commit -m "Add file.txt ."

# Create a branch.
> cd ..
> hg clone hg_head hg_copy

# Change HEAD and update branch.
hg_head> cd hg_head
hg_head> echo "42\nline 2" | tee file.txt
hg_head> hg commit -m "Change first line to 42."
hg_head> cd ../hg_copy
hg_copy> hg pull ../hg_head
# Compare ``hg parents`` to ``hg tip`` to see if there are any pulled
# changesets that have not been updated/merged.
hg_copy> hg update

# Create a conflict in file.txt in both repositories.
hg_copy> echo "42\n-13" | tee file.txt
hg_copy> hg commit -m "Change second line to -13."
hg_copy> cd ../hg_head
hg_head> echo "42\n64" | tee file.txt
hg_head> hg commit -m "Change second line to 64."

# Generate patch in branch and apply to HEAD while handling conflict.
hg_head> cd ../hg_copy
hg_copy> hg export tip > ../conflict.diff
# !!! Mercurial fails! Cannot resolve patch, so craps out.
hg_copy> hg bundle ../conflict.bundle ../hg_head
hg_copy> cd ../hg_head
hg_head> hg unbundle ../conflict.bundle
hg_head> hg merge
# -> FileMerge launched to resolve conflict.


And now bzr:

# Create a new repository and see what files to be added to it.
> mkdir bzr_head
> cd bzr_head
bzr_head> echo "line 1\nline 2" | tee file.txt
bzr_head> bzr init
# ``bzr unknowns`` will list only files that are not checked in.
bzr_head> bzr status

# Add/commit file.txt .
bzr_head> bzr add file.txt
bzr_head> bzr commit -m "Add file.txt ."

# Create a branch.
bzr_head> cd ..
> bzr branch bzr_head bzr_copy

# Change HEAD and update branch.
> cd bzr_head
bzr_head> echo "42\nline 2" | tee file.txt
bzr_head> bzr commit -m "Change first line to 42."
bzr_head> cd ../bzr_copy
bzr_copy> bzr pull

# Create a conflict in file.txt in both repositories.
bzr_copy> echo "42\n-13" | tee file.txt
bzr_copy> bzr commit -m "Change second line to -13".
bzr_copy> cd ../bzr_head
bzr_head> echo "42\n64" | tee file.txt
bzr_head> bzr commit -m "Change second line to 64."

# Generate a patch in branch and apply to HEAD while handling conflict.
bzr_head> bzr diff -r2..3 > ../conflict.diff
bzr_head> cd ../bzr_copy
bzr_head> patch -p0 < ../conflict.diff
# !!! ``patch`` fails!
bzr_head> cd ../bzr_copy
bzr_copy> bzr bundle > ../conflict.bundle
bzr_copy> cd ../bzr_head
bzr_head> bzr merge ../conflict.bundle
# -> Resolve conflict in file.


There was no glaring difference, at least in the use-cases I had, between the two. bzr does remember what branch you are working with, but Hg promotes the fact that you can pull in disparate branches into a repository if you so choose. bzr doesn't require an explicit update like Hg does, although you can pass a command-line flag ('-U') and have the pull also update. Both are not at version 1.0 yet (which makes me a little worried about trust it with my files that I deem important enough to have under version control). Both also don't have overly extensive docs; took me a while for Hg to figure out how to tell what changesets have not been updated on the repository and bzr took a while to find out about it's bundle support and to use ``bzr merge`` on the file for patches.

Hg had the perk of launching a file merging program to help resolve conflicts. bzr had fewer commands needed to perform the same steps. Hg seemed a little faster, but it was not like bzr was not that much slower nor was this in any way actually measured.

It seems like bzr is putting the effort into making it efficient for server-based repositories. But then again I got the initial impression that getting Hg up on a server and providing a file browsing interface was more straight-forward.

I might make the next step in this evaluation being how hard it is to set up a new repository remotely and committing to it (for the purposes of off-site backup of files and history). Otherwise neither is standing that far out from the other in my eyes. bzr seems to have more friendly output messages, but Hg seems to possibly allow for more possibilities (plus it felt like the docs told you about all the features, unlike bzr). Hg does have a smaller file size and simpler directory layout for its revision history.

But basically it's a toss-up for me. =)