The Mercurial project continues its fast pace of innovation in version control. Both major releases this year (3.7 and 3.8) have very important new features that promise to improve user experience to a large degree.
Mercurial 3.7 had a major focus on performance. This is — to a large degree — due to large users like Facebook and Mozilla working on both performance and scalability.
The first major feature is one that has been in development for several years and changes the internals of how Mercurial stores its history. Originally, Mercurial stored history by comparing each changeset to the ‘previous’ changeset. In repositories with a very linear history (where you only have one branch, or where you rebase a lot instead of merging), this worked efficiently. Multiple active branches in parallel did pose a problem: rather than storing small deltas, deltas between entire branches would be stored.
Mercurial 3.7 solves this issue by automatically using ‘generaldelta‘ (which allows deltas to parent revisions, rather than ‘previous’ revisions) for new changesets.
It’s possible to convert an old repository by making a clone:
hg clone -U --config format.generaldelta=1 --pull originalrepo generaldeltarepo
A second important feature is a new serverside extension called ‘clonebundles’. By default, making a clone results in the server creating a zipped ‘bundle’, which is then transferred to the client. For small repositories, this works perfectly fine. For large repositories, creating such a bundle on the fly for every clone has quite some performance impact. The clonebundles extension allows a server operator to generate a daily/weekly bundle, place it on an HTTP server and point the client to that bundle. This results in less CPU usage on the server and faster clones for the client. Details can be found in the help page:
hg help clonebundles
Mercurial 3.7 has quite a few additional improvements. A list can be found on the website. Some highlights:
- Interactive commit (
hg commit -i) and amend (
hg commit --amend) can now be used together.
- ‘hg histedit’ now has a default range of commits it works on. This means you no longer have to specify any arguments for this command. By default, the first changeset used for histedit is “the first ancestor of the current changeset that is draft and does not have any descendants that are merges”.
- The ‘hg revert’ command generates ‘*.orig’ files. It’s now possible to store these in a custom location.
hg clone --uncompressedis now 3-4 times faster on Windows. Details about why cloning was slower on Windows in the first place, can be found in a blog post from Gregory Szorc, who implemented the improvements.
Mercurial 3.8 again had a number of improvements focused on performance, along with focuses on user experience.
A first major feature is the fsmonitor extension (previously known as ‘hgwatchman’). This extension was created by Facebook developers to improve performance and has now been integrated as a base Mercurial extension.
Operations like ‘hg status’, ‘hg diff’, ‘hg commit’ require seeing what files in the repository have been changed. In a normal situation, this requires going over every file in the repository to check for changes. Fsmonitor uses the ‘watchman’ service to be notified when files have changed. Watchman in turn uses platform-specific API’s like ‘inotify’ or ‘FSevents’ to be notified by the operating system every time a repository file has changed.
Using fsmonitor, ‘hg status’, ‘hg diff’ and others only have to check files that have actually changed, rather than going over the entire repository. The result: all of the disk-intensive operations become a lot faster.
Another important improvement is the introduction of the experimental ‘automv’ extension. Normally, people move files around in their repositories using ‘hg mv’ or ‘hg cp’ (or aliases ‘hg move’/’hg rename’ and ‘hg copy’). However, it’s quite easy to forget about these command and use a regular move, especially when using an IDE. The ‘automv’ extension tries to detect similar files upon commit and marks these as moves/copies.
The newly integrated ‘chg’ client offers an alternative way to run Mercurial commands.
One of the issues Mercurial has with regard to speed of commands is that it’s implemented in Python. This is usually not a limiting factor, but starting the Python interpreter does add some overhead.
Chg resolves this using a client implemented in C and a server implemented in Python (the Mercurial command server). Rather than starting a Python process for every Mercurial command, calling ‘chg’ starts a simple C application which communicates with the command server for every command.
Finally, there are a lot of additional improvements regarding user experience. Again, a list is available on the website. Some important highlights are:
- ‘hg update’ no longer updates to the tip-most changeset on any topological head, but to the tip-most changeset on the same topological head. This behaviour is a lot more intuitive.
- Mercurial now gives more hints on continuing interrupted commands.
- Rebase chooses the default destination the same way merge does.
- Graphical logging now displays an improved style.
- The ‘[templatealias]’ section allows users to specify keywords and functions.
As usual, the latest Mercurial website can be found on the official website.