I should say first of all that I’m not an expert of Mercurial, or hg for short. It’s the preferred version control system at Mozilla, and it takes some getting used to—especially if you, like me, have git built in to your muscle memory.
The first thing you need to do is to reset your perception about how and what a version control system should do for you. Mercurial follows a philosophy of minimalism where very little is given by default, where extensions provide most of the functionality. Things you take for granted in git aren’t included by default, and you will need extensions. Lots of them.
This document recounts the hurdles I’ve had using hg and serves mostly as a personal reference. But it might still be useful for others who are just getting into contributing to Mozilla.
By far the most frustrating experience with hg is that you cannot expect the default installation to come with sensible defaults. The argument is that keeping “advanced” functionality out of core prevents new users from accidentally using it.
An unindended consequence is that it’s sometimes difficult for other people to help when you’re stuck because more often than not their environment won’t match yours. This is something you just have to get used to; that hg users are very fond of their own quirky workflow and that it more often than not is subtly different from yours.
Because different extensions imply different styles of workflows,
their user interface and interoperability is not always compatible.
To use a certain workflow you often need to change the default behaviour of commands
to be aware of your chosen work style.
For example if you want
hg log to be aware of commits on the current bookmark,
you need to change the default aguments.
The setup process is difficult for beginners because the rudimentary stock features are sparse, My impression is that the plethora of extensions and different workflows have left Mercurial in somewhat of a schizophrenic state, where no specific workflow is being recommended (because anything is possible!) and they are leading to mental conflict because the different styles are subtly
One frequently lauded aspect of hg is that the user interface is easier to understand. hilst I appreciate difference in taste, my experience is the opposite. If you follow the HEAD-based, bookmark-style workflow I describe below, I find many cognitive dissonances in how the bookmark feature interacts with other commands.
Since only a few organisations use Mercurial (far more use git), documentation and examples are often a problem. I’ll go through a basic setup for working on the Mozilla code base, what extensions you need and which are useful, as well as describe my workflow.
The most important built-in Mercurial extensions to have are rebase, purge, histedit, and shelve. Furthermore you need mq, if you want the qbackout extension to back out patches you mistakingly push to inbound, and extdiff if you want to use an external diff viewer. Note that ome of these extensions only ship with fairly modern versions of Mercurial.
hg cleanto removing any untracked files.
git rebase -i(interactive rebase) which allows you to squash, reorder, fixup, and rename commits.
git stashthat lets you put away uncommitted changes temporarily without committing them. Useful when you need to switch to another bookmark or do some other work.
There are additionally a number of custom extensions you’ll need to work efficiently on the Mozilla codebase that are specific to Mozilla’s integration environment. Most of them are available and documented in Mozilla's Version Control Tools.
The firefoxtree extension lets you consolidate the different remote staging repositories in a single hg repository locally. This saves space and provides an all-around better experience as you move commits from one repo to another.
I have version-control-tools and trychooser checked out in ~/.mozbuild.
Pulling most recent changes from central, if you have central checked out.
Similarily, pulling changes from inbound, without updating.
To create a new feature branch, or bookmark, in hg lingua.
Then to commit the code, which brings up EDITOR.
To see last commit made.
Or to see all commits made on your bookmark, where N indicates the number of commits to show.
To push a bookmark to review.
And to see what is staged for pushing and compare that against a remote.
To push to try.
If you want to rebase just one commit on the current bookmark, where DEST can be “inbound”.
Or when you have multiple commits on the same bookmark and you want to rebase them all (ancestors up to the branch point).
Finally to push your bookmark to a remote, e.g. inbound.
When your patch gets backed out from inbound or central and you need to re-land it, I create a new bookmark off inbound/central and graft (analogous to cherry-picking in git) them onto the new bookmark.
When I need to fix up (amend) the previous commit, I do.
And whenever I need to squash and rewrite the history of a bookmark, where REV it the revision number or commit SHA.
This is a gathering of useful Mercurial commands. I'd like to call out Andrew Halberstad's New Mercurial Workflow article as a particularly good starting point for learning modern hg with bookmarks.
hg log -f to follow rename or copy history of files.
Showing the history of your current bookmark can be achieved with
hg log -r 'bookmark()'.
hg outgoing -r BOOKMARK inbound
to see the diff between your bookmark and inbound.
hg log -r . to see the last commit on tip.
hg log -lN,
where N is the number of commits to show the log message of.
hg histedit is roughly equivalent to squashing using
git rebase -i, only that it happens without rebasing.
hg pull -u is equivalent to
it fetches and updates.
hg trychooser -m ARGS,
where ARGS are the try
arguments to use.
To push all commits on given BOOKMARK
one can use
hg push -r BOOKMARK.
And to rebase do
hg rebase -b BOOKMARK -d inbound --collapse.
--collapse argument lets you fold/squash commits.
There's a shelve extension
that works like git's stash functionality.
You invoke it for any modified code with
hg unshelve to get the changes back.