Adding functionality with extensions#

While the core of Mercurial is quite complete from a functionality standpoint, it’s deliberately shorn of fancy features. This approach of preserving simplicity keeps the software easy to deal with for both maintainers and users.

However, Mercurial doesn’t box you in with an inflexible command set: you can add features to it as extensions (sometimes known as plugins). We’ve already discussed a few of these extensions in earlier chapters.

  • Simplifying the pull-merge-commit sequence covers the fetch extension; this combines pulling new changes and merging them with local changes into a single command, fetch.

  • In Handling repository events with hooks, we covered several extensions that are useful for hook-related functionality: acl adds access control lists; bugzilla adds integration with the Bugzilla bug tracking system; and notify sends notification emails on new changes.

In this chapter, we’ll cover some of the other extensions that are available for Mercurial, and briefly touch on some of the machinery you’ll need to know about if you want to write an extension of your own.

Flexible diff support with the extdiff extension#

Mercurial’s built-in hg diff command outputs plaintext unified diffs.

Hide code cell content
export HGRCPATH=$PWD/../hgrc4book
mkdir -p /tmp/tmp_mercurial_book
cd /tmp/tmp_mercurial_book
rm -rf /tmp/tmp_mercurial_book/*
hg init a
cd a
echo 'The first line.' > myfile
hg ci -Ama
echo 'The second line.' >> myfile
adding myfile
hg diff
diff --git a/myfile b/myfile
--- a/myfile
+++ b/myfile
@@ -1,1 +1,2 @@
 The first line.
+The second line.

If you would like to use an external tool to display modifications, you’ll want to use the extdiff extension. This will let you use, for example, a graphical diff tool.

The extdiff extension is bundled with Mercurial, so it’s easy to set up. In the extensions section of your ~/.hgrc, simply add a one-line entry to enable the extension.

[extensions]
extdiff =

This introduces a command named extdiff, which by default uses your system’s diff command to generate a unified diff in the same form as the built-in hg diff command.

hg extdiff
--- /tmp/extdiff.fv9pl0bd/a.e5f03160e083/myfile	2023-09-13 16:14:19.000000000 +0000
+++ /tmp/tmp_mercurial_book/a/myfile	2023-09-13 16:14:19.622110730 +0000
@@ -1 +1,2 @@
 The first line.
+The second line.

The result won’t be exactly the same as with the built-in hg diff variations, because the output of diff varies from one system to another, even when passed the same options.

As the “making snapshot” lines of output above imply, the extdiff command works by creating two snapshots of your source tree. The first snapshot is of the source revision; the second, of the target revision or working directory. The extdiff command generates these snapshots in a temporary directory, passes the name of each directory to an external diff viewer, then deletes the temporary directory. For efficiency, it only snapshots the directories and files that have changed between the two revisions.

Snapshot directory names have the same base name as your repository. If your repository path is /quux/bar/foo, then foo will be the name of each snapshot directory. Each snapshot directory name has its changeset ID appended, if appropriate. If a snapshot is of revision a631aca1083f, the directory will be named foo.a631aca1083f. A snapshot of the working directory won’t have a changeset ID appended, so it would just be foo in this example. To see what this looks like in practice, look again at the extdiff example above. Notice that the diff has the snapshot directory names embedded in its header.

The extdiff command accepts two important options. The hg -p option lets you choose a program to view differences with, instead of diff. With the hg -o option, you can change the options that extdiff passes to the program (by default, these options are “-Npru”, which only make sense if you’re running diff). In other respects, the extdiff command acts similarly to the built-in hg diff command: you use the same option names, syntax, and arguments to specify the revisions you want, the files you want, and so on.

As an example, here’s how to run the normal system diff command, getting it to generate context diffs (using the -c option) instead of unified diffs, and five lines of context instead of the default three (passing 5 as the argument to the -C option).

hg extdiff -o -NprcC5
*** /tmp/extdiff.k_riuzs7/a.e5f03160e083/myfile	2023-09-13 16:14:19.000000000 +0000
--- /tmp/tmp_mercurial_book/a/myfile	2023-09-13 16:14:19.622110730 +0000
***************
*** 1 ****
--- 1,2 ----
  The first line.
+ The second line.