Ramblings of General Geekery

Mercurial Advent Blogging

Here’s another advent blog series! This time it’s from Kamal Marhubi
and it’s on the subject of Mercurial. It’s pretty interesting, especially
for giving a fresh perspective on Mercurial’s user experience.

The introduction post lays down some of what makes Mercurial interesting
(phases, changeset evolution, extensibility) while the third post catches
up to another cool thing (revsets, one of my favourite Mercurial features) that
was missing from that initial list.

Extensions and papercuts

There’s a good article in the series about how Mercurial’s reliance on
extensions (and more specifically the need to explicitely enable them) is one of
the several “papercuts” you get when you start using it. This reminded me of
Josef Sipek’s “Modern Mercurial” blog series which starts with an
article precisely about that problem
:

Then it suddenly hit me —- before these tweaks, I had been using Mercurial
like it’s still 2005!

I think this is a very important observation. Mercurial didn’t seem to be
improving because none of the user-visible changes were forced onto the users.

The problem is that the Mercurial devs have an extremely strict approach to how
the CLI should behave, and how no breaking changes should ever be introduced.
This means that:

  1. No “dangerous” commands should be accessible by default ("don’t give the
    user opportunities to shoot their own foot
    "), which explains why history
    rewriting commands like rebase are disabled out-of-the-box.
  2. Things that were later added (like colours, pager support, etc.) were often
    done in an optional extension to not break previous behaviour.

Arguably, these strict rules are partially the reason why the Mercurial CLI is
so nice to use compared to other CLIs like Git’s, but they’re also obviously
causing a lot of pain elsewhere.

I naively think this might be somewhat fixable by:

  • Making the first hg run setup some sane default if it doesn’t find any user
    .hgrc (i.e. better bootstrapping).
  • Relaxing some of the strict CLI rules by realizing that most use-cases that
    rely on specific historical behaviours (like automated scripts) are already
    most probably setting environment variables like HGPLAIN, in which case
    Mercurial can disable some of the more “human facing” features.

But of course, it’s lot more complicated than this… and to some degree, this
was addressed with the tweakdefaults setting (formerly known as “friendly
hg
”), but, ironically enough, you still need to know about enabling
it, since it default to false, of course.

Staging areas

The fourth post talks about how Mercurial doesn’t have a staging area
(a.k.a. index) like in Git.

It’s kind of funny to me that we have people who started with Git as their first
(and sometimes only) VCS, and it will soon dawn on them that, frankly, there’s
nothing out there quite like Git’s index (well, at least not in any of the
half-dozen VCSes I’ve used so far). Git’s pretty unique on that front.

Although I don’t recommend trying to emulate a tool’s idiosyncratic workflow
when using another tool, people coming from Git invariably ask about this so
there’s always been some partial answer for Mercurial. A few years ago, the MQ
extension was that answer (it kinda gives you something that looks like
multiple staging areas!), but it seems that most of the Mercurial community
has moved away from it (I have too). MQ is still available for those who want
it, but these days it seems that using secret phases and history rewriting is
more common (and it also kinda gives you multiple staging areas too!).

I don’t really do that, but I imagine it would work along the lines of:

[alias]
newstage = commit -s -m "STAGING AREA"
upstage = commit --amend

So when you start working on something new, you push your work-in-progress with
hg newstage into a secret commit called “STAGING AREA”. Since it’s secret,
it won’t get pushed and will stay local. Then, as you keep working, you run hg upstage every now and then to “grow” that commit. When it’s ready, you change
that commit’s phase to draft. It’s a bit clunky (there are 2 aliases when
ideally there would be only one) but you get the idea, and with a bit of
scripting I’m sure that it’s possible to get it down to a similar UX as Git’s.

Twelve days to go

Anyway, we’re still half-way to Christmas so check out Kamal’s blog
for the rest of the series (assuming he keeps it going 🙂 ).