Wednesday, September 1, 2010

Hg vs. Git in the workplace

This post is based on the following mail I sent to the ALT.NET Israel list. I'm discussing a Windows development environment.

I'm much better at git than hg, and I use git a lot for real work, and it's great (no ifs or buts).
I also helped originate the move to git at work, because the transition plan was much better. I evaluated hg first and loved it, but the transition plan wouldn't have been half has smooth (a better hg-svn bridge may have been written since then).

Still, here are - in order - the reasons I thing hg would fit better at my workplace (and had we found a good transition plan we'd probably be using hg instead of git):

  1. Friendlier commands and interface. With git I feel like I need to research how to do straightforward things. Git is extremely powerful and I can do anything with it, and I'm strange so I like the arcane, but git requires more of an investment from people to use it effectively when they have other things to do. Some things are arguably easier to understand in git (rebasing, for example, vs. hg's patch queues - although that's debatable) but the whole package leans heavily to hg IMO. This is the least-loved aspect of git among the teams.
  2. In hg, commits remember the named branch they were committed to (see here). I would LOVE to have this in git, but no cigar - we're still playing with different schemes of approximating this.
    With many people working at times on several branches, and with merging done between branches, then given commit XYZ it's nontrivial in git to figure out which branch it belongs to.
    This is especially true in some scenarios we encountered - e.g. human error caused an older release branch to be fast-forwarded to the head of the latest devel branch - few traces are left in the repository itself of the previous state, and we had fun a few times fixing this (can take hours). Now we have a hook to prevent this.
    If we'd have cherry-picked between different branches instead of merged then this would be easy (and this is equivalent to svn's merging, only better), but we like git's merge and we want to use that.
  3. hg has less quirky Windows support. Points to consider:
    • msysgit gets sporadic releases and is usually months behind the stable git version, the latest hg versions just work.
      • This hit us a few times (bug has been fixed but not available in msysgit).
      • Current example: Git 1.7.2 has improved crlf handling but msysgit isn't there.
    • Being able to "hg serve" your repository is incredibly cool, but "git daemon" doesn't work with msysgit
      • Think continuous integration that watches your local repository and runs builds with your current code, giving up-to-date feedback
      • collaborating with someone without pushing a publicly-visible branch (I've actually wanted to do that a few times)
      • developing and testing on more than 1 machine simultaneously. There are workarounds, but "git daemon" would have been perfect.
    • automating hg, including hooks, run in a Windows environment (vs. git where it runs in mingw's MSYS environment)
What doesn't bother me much for the long run is tooling. Right now hg seems to have better tools for our scenarios (even including much better Trac support), but I think git's extreme popularity will cause better and better tools to be written. Some people were very sad to let go of their VisualSvn / Ankh plugins, but they manage with Git Extensions (mostly) and occasionally TortoiseGit. I was surprised at how few people use git from the command-line, I can't live without it.


  1. I do not understand point (2.).
    Who should remember - the changeset, or the commit command (working tree actually)? (aren't working trees connected to a specific branch?)

    Did the lack of this feature cause the problem you describe, or do you mean it would have helped solving it?

    What do you mean by "few traces were left", isn't the full snapshot of the previous state available through basic git commands?

  2. Amit - it's easy to check whether branch A contains commit X at this moment. But branches are ephemeral labels - if they moved, you don't necessarily know what branches contained commit X at a previous time.

    There is no full snapshot of the previous state - the branches state (which label pointed to which commit) isn't versioned. I believe this is true in bzr and hg as well but I'm not sure.

    Since writing this I've found out that hg's named branches don't give me what I want - the "named branch" associated with a commit is just a string and has no intrinsic meaning - it's usually the name of the developer's topic branch which isn't helpful.

    I guess what I'd like is either (a) versioning of the branch labels themselves, or (b) metadata on each commit specifying the branch it was pushed to on the central server. This implies a central server. It can be done with git hooks - the info can be saved with git's "notes" (mutable metadata per commit).