Chapter 11
Customising the output of Mercurial

Mercurial provides a powerful mechanism to let you control how it displays information. The mechanism is based on templates. You can use templates to generate specific output for a single command, or to customise the entire appearance of the built-in web interface.

11.1 Using precanned output styles

Packaged with Mercurial are some output styles that you can use immediately. A style is simply a precanned template that someone wrote and installed somewhere that Mercurial can find.

Before we take a look at Mercurial’s bundled styles, let’s review its normal output.

1  $ hg log -r1
2  changeset:   1:b56ce7b07c52
3  tag:         mytag
4  user:        Bryan O'Sullivan <bos@serpentine.com>
5  date:        Thu Aug 21 18:22:25 2008 +0000
6  summary:     added line to end of <<hello>> file.
7  

This is somewhat informative, but it takes up a lot of space—five lines of output per changeset. The compact style reduces this to three lines, presented in a sparse manner.

1  $ hg log --style compact
2  3[tip]   3ea944887979   2008-08-21 18:22 +0000   bos
3    Added tag v0.1 for changeset 56bfb1da2094
4  
5  2[v0.1]   56bfb1da2094   2008-08-21 18:22 +0000   bos
6    Added tag mytag for changeset b56ce7b07c52
7  
8  1[mytag]   b56ce7b07c52   2008-08-21 18:22 +0000   bos
9    added line to end of <<hello>> file.
10  
11  0   bd2d1e24f0e0   2008-08-21 18:22 +0000   bos
12    added hello
13  

The changelog style hints at the expressive power of Mercurial’s templating engine. This style attempts to follow the GNU Project’s changelog guidelines[RS].

1  $ hg log --style changelog
2  2008-08-21  Bryan O'Sullivan  <bos@serpentine.com>
3  
4   ⋆ .hgtags:
5   Added tag v0.1 for changeset 56bfb1da2094
6   [3ea944887979] [tip]
7  
8   ⋆ .hgtags:
9   Added tag mytag for changeset b56ce7b07c52
10   [56bfb1da2094] [v0.1]
11  
12   ⋆ goodbye, hello:
13   added line to end of <<hello>> file.
14  
15   in addition, added a file with the helpful name (at least i hope
16   that some might consider it so) of goodbye.
17   [b56ce7b07c52] [mytag]
18  
19   ⋆ hello:
20   added hello
21   [bd2d1e24f0e0]
22  

You will not be shocked to learn that Mercurial’s default output style is named default.

11.1.1 Setting a default style

You can modify the output style that Mercurial will use for every command by editing your hgrc file, naming the style you would prefer to use.

1  [ui]
2  style = compact

If you write a style of your own, you can use it by either providing the path to your style file, or copying your style file into a location where Mercurial can find it (typically the templates subdirectory of your Mercurial install directory).

11.2 Commands that support styles and templates

All of Mercurial’s “log-like” commands let you use styles and templates: hg incoming”, hg log”, hg outgoing”, and hg tip”.

As I write this manual, these are so far the only commands that support styles and templates. Since these are the most important commands that need customisable output, there has been little pressure from the Mercurial user community to add style and template support to other commands.

11.3 The basics of templating

At its simplest, a Mercurial template is a piece of text. Some of the text never changes, while other parts are expanded, or replaced with new text, when necessary.

Before we continue, let’s look again at a simple example of Mercurial’s normal output.

1  $ hg log -r1
2  changeset:   1:b56ce7b07c52
3  tag:         mytag
4  user:        Bryan O'Sullivan <bos@serpentine.com>
5  date:        Thu Aug 21 18:22:25 2008 +0000
6  summary:     added line to end of <<hello>> file.
7  

Now, let’s run the same command, but using a template to change its output.

1  $ hg log -r1 --template 'i saw a changesetn'
2  i saw a changeset

The example above illustrates the simplest possible template; it’s just a piece of static text, printed once for each changeset. The --template option to the hg log” command tells Mercurial to use the given text as the template when printing each changeset.

Notice that the template string above ends with the text “\n”. This is an escape sequence, telling Mercurial to print a newline at the end of each template item. If you omit this newline, Mercurial will run each piece of output together. See section 11.5 for more details of escape sequences.

A template that prints a fixed string of text all the time isn’t very useful; let’s try something a bit more complex.

1  $ hg log --template 'i saw a changeset: {desc}∖n'
2  i saw a changeset: Added tag v0.1 for changeset 56bfb1da2094
3  i saw a changeset: Added tag mytag for changeset b56ce7b07c52
4  i saw a changeset: added line to end of <<hello>> file.
5  
6  in addition, added a file with the helpful name (at least i hope that some might consider it so) of goodbye.
7  i saw a changeset: added hello

As you can see, the string “{desc}” in the template has been replaced in the output with the description of each changeset. Every time Mercurial finds text enclosed in curly braces (“{” and “}”), it will try to replace the braces and text with the expansion of whatever is inside. To print a literal curly brace, you must escape it, as described in section 11.5.

11.4 Common template keywords

You can start writing simple templates immediately using the keywords below.

A few simple experiments will show us what to expect when we use these keywords; you can see the results in figure 11.1.


1  $ hg log -r1 --template 'author: {author}∖n'
2  author: Bryan O'Sullivan <bos@serpentine.com>
3  $ hg log -r1 --template 'desc:n{desc}∖n'
4  desc:
5  added line to end of <<hello>> file.
6  
7  in addition, added a file with the helpful name (at least i hope that some might consider it so) of goodbye.
8  $ hg log -r1 --template 'files: {files}∖n'
9  files: goodbye hello
10  $ hg log -r1 --template 'file_adds: {file_adds}∖n'
11  file_adds: goodbye
12  $ hg log -r1 --template 'file_dels: {file_dels}∖n'
13  file_dels:
14  $ hg log -r1 --template 'node: {node}∖n'
15  node: b56ce7b07c52de7d5fd79fb89701ea538af65746
16  $ hg log -r1 --template 'parents: {parents}∖n'
17  parents:
18  $ hg log -r1 --template 'rev: {rev}∖n'
19  rev: 1
20  $ hg log -r1 --template 'tags: {tags}∖n'
21  tags: mytag

Figure 11.1: Template keywords in use

As we noted above, the date keyword does not produce human-readable output, so we must treat it specially. This involves using a filter, about which more in section 11.6.

1  $ hg log -r1 --template 'date: {date}∖n'
2  date: 1219342945.00
3  $ hg log -r1 --template 'date: {date|isodate}∖n'
4  date: 2008-08-21 18:22 +0000

11.5 Escape sequences

Mercurial’s templating engine recognises the most commonly used escape sequences in strings. When it sees a backslash (“\”) character, it looks at the following character and substitutes the two characters with a single replacement, as described below.

As indicated above, if you want the expansion of a template to contain a literal “\”, “{”, or “{” character, you must escape it.

11.6 Filtering keywords to change their results

Some of the results of template expansion are not immediately easy to use. Mercurial lets you specify an optional chain of filters to modify the result of expanding a keyword. You have already seen a common filter, isodate, in action above, to make a date readable.

Below is a list of the most commonly used filters that Mercurial supports. While some filters can be applied to any text, others can only be used in specific circumstances. The name of each filter is followed first by an indication of where it can be used, then a description of its effect.


1  $ hg log -r1 --template '{author}∖n'
2  Bryan O'Sullivan <bos@serpentine.com>
3  $ hg log -r1 --template '{author|domain}∖n'
4  serpentine.com
5  $ hg log -r1 --template '{author|email}∖n'
6  bos@serpentine.com
7  $ hg log -r1 --template '{author|obfuscate}∖n' | cut -c-76
8  Bryan O'Sulli
9  $ hg log -r1 --template '{author|person}∖n'
10  Bryan O'Sullivan
11  $ hg log -r1 --template '{author|user}∖n'
12  bos
13  $ hg log -r1 --template 'looks almost right, but actually garbage: {date}∖n'
14  looks almost right, but actually garbage: 1219342945.00
15  $ hg log -r1 --template '{date|age}∖n'
16  1 second
17  $ hg log -r1 --template '{date|date}∖n'
18  Thu Aug 21 18:22:25 2008 +0000
19  $ hg log -r1 --template '{date|hgdate}∖n'
20  1219342945 0
21  $ hg log -r1 --template '{date|isodate}∖n'
22  2008-08-21 18:22 +0000
23  $ hg log -r1 --template '{date|rfc822date}∖n'
24  Thu, 21 Aug 2008 18:22:25 +0000
25  $ hg log -r1 --template '{date|shortdate}∖n'
26  2008-08-21
27  $ hg log -r1 --template '{desc}∖n' | cut -c-76
28  added line to end of <<hello>> file.
29  
30  in addition, added a file with the helpful name (at least i hope that some m
31  $ hg log -r1 --template '{desc|addbreaks}∖n' | cut -c-76
32  added line to end of <<hello>> file.<br/>
33  <br/>
34  in addition, added a file with the helpful name (at least i hope that some m
35  $ hg log -r1 --template '{desc|escape}∖n' | cut -c-76
36  added line to end of <<hello>> file.
37  
38  in addition, added a file with the helpful name (at least i hope that some m
39  $ hg log -r1 --template '{desc|fill68}∖n'
40  added line to end of <<hello>> file.
41  
42  in addition, added a file with the helpful name (at least i hope
43  that some might consider it so) of goodbye.
44  $ hg log -r1 --template '{desc|fill76}∖n'
45  added line to end of <<hello>> file.
46  
47  in addition, added a file with the helpful name (at least i hope that some
48  might consider it so) of goodbye.
49  $ hg log -r1 --template '{desc|firstline}∖n'
50  added line to end of <<hello>> file.
51  $ hg log -r1 --template '{desc|strip}∖n' | cut -c-76
52  added line to end of <<hello>> file.
53  
54  in addition, added a file with the helpful name (at least i hope that some m
55  $ hg log -r1 --template '{desc|tabindent}∖n' | expand | cut -c-76
56  added line to end of <<hello>> file.
57  
58          in addition, added a file with the helpful name (at least i hope tha
59  $ hg log -r1 --template '{node}∖n'
60  b56ce7b07c52de7d5fd79fb89701ea538af65746
61  $ hg log -r1 --template '{node|short}∖n'
62  b56ce7b07c52

Figure 11.2: Template filters in action

Note: If you try to apply a filter to a piece of data that it cannot process, Mercurial will fail and print a Python exception. For example, trying to run the output of the desc keyword into the isodate filter is not a good idea.

11.6.1 Combining filters

It is easy to combine filters to yield output in the form you would like. The following chain of filters tidies up a description, then makes sure that it fits cleanly into 68 columns, then indents it by a further 8 characters (at least on Unix-like systems, where a tab is conventionally 8 characters wide).

1  $ hg log -r1 --template 'description:nt{desc|strip|fill68|tabindent}∖n'
2  description:
3   added line to end of <<hello>> file.
4  
5   in addition, added a file with the helpful name (at least i hope
6   that some might consider it so) of goodbye.

Note the use of “\t” (a tab character) in the template to force the first line to be indented; this is necessary since tabindent indents all lines except the first.

Keep in mind that the order of filters in a chain is significant. The first filter is applied to the result of the keyword; the second to the result of the first filter; and so on. For example, using fill68|tabindent gives very different results from tabindent|fill68.

11.7 From templates to styles

A command line template provides a quick and simple way to format some output. Templates can become verbose, though, and it’s useful to be able to give a template a name. A style file is a template with a name, stored in a file.

More than that, using a style file unlocks the power of Mercurial’s templating engine in ways that are not possible using the command line --template option.

11.7.1 The simplest of style files

Our simple style file contains just one line:

1  $ echo 'changeset = "rev: {rev}∖n"' > rev
2  $ hg log -l1 --style ./rev
3  rev: 3

This tells Mercurial, “if you’re printing a changeset, use the text on the right as the template”.

11.7.2 Style file syntax

The syntax rules for a style file are simple.

11.8 Style files by example

To illustrate how to write a style file, we will construct a few by example. Rather than provide a complete style file and walk through it, we’ll mirror the usual process of developing a style file by starting with something very simple, and walking through a series of successively more complete examples.

11.8.1 Identifying mistakes in style files

If Mercurial encounters a problem in a style file you are working on, it prints a terse error message that, once you figure out what it means, is actually quite useful.

1  $ cat broken.style
2  changeset =

Notice that broken.style attempts to define a changeset keyword, but forgets to give any content for it. When instructed to use this style file, Mercurial promptly complains.

1  $ hg log -r1 --style broken.style
2  abort: broken.style:1: parse error

This error message looks intimidating, but it is not too hard to follow.

11.8.2 Uniquely identifying a repository

If you would like to be able to identify a Mercurial repository “fairly uniquely” using a short string as an identifier, you can use the first revision in the repository.

1  $ hg log -r0 --template '{node}'
2  bd2d1e24f0e0c1c1b33369d884ddac10ca35bd11

This is not guaranteed to be unique, but it is nevertheless useful in many cases.

Here are some uses to which you could put this identifier:

11.8.3 Mimicking Subversion’s output

Let’s try to emulate the default output format used by another revision control tool, Subversion.

1  $ svn log -r9653
2  ------------------------------------------------------------------------
3  r9653 | sean.hefty | 2006-09-27 14:39:55 -0700 (Wed, 27 Sep 2006) | 5 lines
4  
5  On reporting a route error, also include the status for the error,
6  rather than indicating a status of 0 when an error has occurred.
7  
8  Signed-off-by: Sean Hefty <sean.hefty@intel.com>
9  
10  ------------------------------------------------------------------------

Since Subversion’s output style is fairly simple, it is easy to copy-and-paste a hunk of its output into a file, and replace the text produced above by Subversion with the template values we’d like to see expanded.

1  $ cat svn.template
2  r{rev} | {author|user} | {date|isodate} ({date|rfc822date})
3  
4  {desc|strip|fill76}
5  
6  ------------------------------------------------------------------------

There are a few small ways in which this template deviates from the output produced by Subversion.

It took me no more than a minute or two of work to replace literal text from an example of Subversion’s output with some keywords and filters to give the template above. The style file simply refers to the template.

1  $ cat svn.style
2  header = '------------------------------------------------------------------------nn'
3  changeset = svn.template

We could have included the text of the template file directly in the style file by enclosing it in quotes and replacing the newlines with “
n” sequences, but it would have made the style file too difficult to read. Readability is a good guide when you’re trying to decide whether some text belongs in a style file, or in a template file that the style file points to. If the style file will look too big or cluttered if you insert a literal piece of text, drop it into a template instead.