Customizing 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 customize the entire appearance of the built-in web interface.

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.

$ hg log -r1
changeset:   1:c8ec776f4fca
tag:         mytag
user:        test
date:        Thu Jan 01 00:00:00 1970 +0000
summary:     added line to end of <<hello>> file.

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.

$ hg log --template compact
3[tip]   91900a8c91ee   1970-01-01 00:00 +0000   test
  Added tag v0.1 for changeset e8277000e239

2[v0.1]   e8277000e239   1970-01-01 00:00 +0000   test
  Added tag mytag for changeset c8ec776f4fca

1[mytag]   c8ec776f4fca   1970-01-01 00:00 +0000   test
  added line to end of <<hello>> file.

0   0312f545d1d7   1970-01-01 00:00 +0000   test
  added hello

The changelog style hints at the expressive power of Mercurial's templating engine. This style attempts to follow the GNU Project's changelog guidelinesweb:changelog.

$ hg log --template changelog
1970-01-01  test  <test>

      * .hgtags:
      Added tag v0.1 for changeset e8277000e239
      [91900a8c91ee] [tip]

      * .hgtags:
      Added tag mytag for changeset c8ec776f4fca
      [e8277000e239] [v0.1]

      * goodbye, hello:
      added line to end of <<hello>> file.

      in addition, added a file with the helpful name (at least i hope
      that some might consider it so) of goodbye.
      [c8ec776f4fca] [mytag]

      * hello:
      added hello
      [0312f545d1d7]

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

It's possible to get a full overview of template styles:

$ hg log --template list
available styles: bisect, changelog, compact, default, phases, show, status, xml
abort: specify a template

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 so on.

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.

$ hg log -r1
changeset:   1:c8ec776f4fca
tag:         mytag
user:        test
date:        Thu Jan 01 00:00:00 1970 +0000
summary:     added line to end of <<hello>> file.

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

$ hg log -r1 --template 'i saw a changeset\n'
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. You can also use the shorthand -T option.

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 sec:template:escape 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.

$ hg log --template 'i saw a changeset: {desc}\n'
i saw a changeset: Added tag v0.1 for changeset e8277000e239
i saw a changeset: Added tag mytag for changeset c8ec776f4fca
i saw a changeset: added line to end of <<hello>> file.

in addition, added a file with the helpful name (at least i hope that some might consider it so) of goodbye.
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 sec:template:escape.

Common template keywords

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

  • author: String. The unmodified author of the changeset.
  • branch: String. The name of the branch on which the changeset was committed. Will be empty if the branch name was default.
  • date: Date information. The date when the changeset was committed. This is not human-readable; you must pass it through a filter that will render it appropriately. See sec:template:filter for more information on filters. The date is expressed as a pair of numbers. The first number is a Unix UTC timestamp (seconds since January 1, 1970); the second is the offset of the committer's timezone from UTC, in seconds.
  • desc: String. The text of the changeset description.
  • files: List of strings. All files modified, added, or removed by this changeset.
  • file_adds: List of strings. Files added by this changeset.
  • file_dels: List of strings. Files removed by this changeset.
  • node: String. The changeset identification hash, as a 40-character hexadecimal string.
  • parents: List of strings. The parents of the changeset.
  • rev: Integer. The repository-local changeset revision number.
  • tags: List of strings. Any tags associated with the changeset.

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

$ hg log -r1 --template 'author: {author}\n'
author: test
$ hg log -r1 --template 'desc:\n{desc}\n'
desc:
added line to end of <<hello>> file.

in addition, added a file with the helpful name (at least i hope that some might consider it so) of goodbye.
$ hg log -r1 --template 'files: {files}\n'
files: goodbye hello
$ hg log -r1 --template 'file_adds: {file_adds}\n'
file_adds: goodbye
$ hg log -r1 --template 'file_dels: {file_dels}\n'
file_dels:
$ hg log -r1 --template 'node: {node}\n'
node: c8ec776f4fca16a08e85d5a13dcd372fb7c66f0e
$ hg log -r1 --template 'parents: {parents}\n'
parents:
$ hg log -r1 --template 'rev: {rev}\n'
rev: 1
$ hg log -r1 --template 'tags: {tags}\n'
tags: mytag

New template keywords are added to Mercurial every so often, you can see a full overview by executing hg help templates.

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 sec:template:filter.

$ hg log -r1 --template 'date: {date}\n'
date: 0.00
$ hg log -r1 --template 'date: {date|isodate}\n'
date: 1970-01-01 00:00 +0000

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.

  • \: Backslash, “\”, ASCII 134.
  • \n: Newline, ASCII 12.
  • \r: Carriage return, ASCII 15.
  • \t: Tab, ASCII 11.
  • \v: Vertical tab, ASCII 13.
  • \{: Open curly brace, “{”, ASCII 173.
  • \}: Close curly brace, “}”, ASCII 175.

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

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.

  • addbreaks: Any text. Add an XHTML “<br/>” tag before the end of every line except the last. For example, “foo\nbar” becomes “foo<br/>\nbar”.
  • age: date keyword. Render the age of the date, relative to the current time. Yields a string like “10 minutes”.
  • basename: Any text, but most useful for the files keyword and its relatives. Treat the text as a path, and return the basename. For example, “foo/bar/baz” becomes “baz”.
  • date: date keyword. Render a date in a similar format to the Unix date command, but with timezone included. Yields a string like “Mon Sep 04 15:13:13 2006 -0700”.
  • domain: Any text, but most useful for the author keyword. Finds the first string that looks like an email address, and extract just the domain component. For example, “Bryan O'Sullivan <bos@serpentine.com>” becomes “serpentine.com”.
  • email: Any text, but most useful for the author keyword. Extract the first string that looks like an email address. For example, “Bryan O'Sullivan <bos@serpentine.com>” becomes “bos@serpentine.com”.
  • escape: Any text. Replace the special XML/XHTML characters “&”, “<” and “>” with XML entities.
  • fill68: Any text. Wrap the text to fit in 68 columns. This is useful before you pass text through the tabindent filter, and still want it to fit in an 80-column fixed-font window.
  • fill76: Any text. Wrap the text to fit in 76 columns.
  • firstline: Any text. Yield the first line of text, without any trailing newlines.
  • hgdate: date keyword. Render the date as a pair of readable numbers. Yields a string like “1157407993 25200”.
  • isodate: date keyword. Render the date as a text string in ISO 8601 format. Yields a string like “2006-09-04 15:13:13 -0700”.
  • obfuscate: Any text, but most useful for the author keyword. Yield the input text rendered as a sequence of XML entities. This helps to defeat some particularly stupid screen-scraping email harvesting spambots.
  • person: Any text, but most useful for the author keyword. Yield the text before an email address. For example, “Bryan O'Sullivan <bos@serpentine.com>” becomes “Bryan O'Sullivan”.
  • rfc822date: date keyword. Render a date using the same format used in email headers. Yields a string like “Mon, 04 Sep 2006 15:13:13 -0700”.
  • short: Changeset hash. Yield the short form of a changeset hash, i.e. a 12-character hexadecimal string.
  • shortdate: date keyword. Render the year, month, and day of the date. Yields a string like “2006-09-04”.
  • strip: Any text. Strip all leading and trailing whitespace from the string.
  • tabindent: Any text. Yield the text, with every line except the first starting with a tab character.
  • urlescape: Any text. Escape all characters that are considered “special” by URL parsers. For example, foo bar becomes foo%20bar.
  • user: Any text, but most useful for the author keyword. Return the “user” portion of an email address. For example, “Bryan O'Sullivan <bos@serpentine.com>” becomes “bos”.
$ hg log -r1 --template '{author}\n'
test
$ hg log -r1 --template '{author|domain}\n'

$ hg log -r1 --template '{author|email}\n'
test
$ hg log -r1 --template '{author|obfuscate}\n' | cut -c-76
&#116;&#101;&#115;&#116;
$ hg log -r1 --template '{author|person}\n'
test
$ hg log -r1 --template '{author|user}\n'
test

$ hg log -r1 --template 'looks almost right, but actually garbage: {date}\n'
looks almost right, but actually garbage: 0.00
$ hg log -r1 --template '{date|age}\n'
1970-01-01
$ hg log -r1 --template '{date|date}\n'
Thu Jan 01 00:00:00 1970 +0000
$ hg log -r1 --template '{date|hgdate}\n'
0 0
$ hg log -r1 --template '{date|isodate}\n'
1970-01-01 00:00 +0000
$ hg log -r1 --template '{date|rfc822date}\n'
Thu, 01 Jan 1970 00:00:00 +0000
$ hg log -r1 --template '{date|shortdate}\n'
1970-01-01

$ hg log -r1 --template '{desc}\n' | cut -c-76
added line to end of <<hello>> file.

in addition, added a file with the helpful name (at least i hope that some m
$ hg log -r1 --template '{desc|addbreaks}\n' | cut -c-76
added line to end of <<hello>> file.<br/>
<br/>
in addition, added a file with the helpful name (at least i hope that some m
$ hg log -r1 --template '{desc|escape}\n' | cut -c-76
added line to end of &lt;&lt;hello&gt;&gt; file.

in addition, added a file with the helpful name (at least i hope that some m
$ hg log -r1 --template '{desc|fill68}\n'
added line to end of <<hello>> file.

in addition, added a file with the helpful name (at least i hope
that some might consider it so) of goodbye.
$ hg log -r1 --template '{desc|fill76}\n'
added line to end of <<hello>> file.

in addition, added a file with the helpful name (at least i hope that some
might consider it so) of goodbye.
$ hg log -r1 --template '{desc|firstline}\n'
added line to end of <<hello>> file.
$ hg log -r1 --template '{desc|strip}\n' | cut -c-76
added line to end of <<hello>> file.

in addition, added a file with the helpful name (at least i hope that some m
$ hg log -r1 --template '{desc|tabindent}\n' | expand | cut -c-76
added line to end of <<hello>> file.

        in addition, added a file with the helpful name (at least i hope tha

$ hg log -r1 --template '{node}\n'
c8ec776f4fca16a08e85d5a13dcd372fb7c66f0e
$ hg log -r1 --template '{node|short}\n'
c8ec776f4fca

Note

If you try to apply a filter to a piece of data that it cannot process, Mercurial will print an error clarifying the incompatibility. For example, trying to apply the 'isodate' filter to the 'desc' keyword is not possible.

$ hg log -r1 --template '{desc|isodate}\n'
abort: template filter 'isodate' is not compatible with keyword 'desc'

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).

$ hg log -r1 --template 'description:\n\t{desc|strip|fill68|tabindent}\n'
description:
      added line to end of <<hello>> file.

      in addition, added a file with the helpful name (at least i hope
      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.

Adding logic

It's possible to make more advanced templates by using the built-in functions Mercurial provides. All of these can be found using hg help templates. An overview of commonly used functions is listed below:

  • date(date[, fmt]): display (and format) a date. By default, this will show a date formatted like Mon Sep 04 15:13:13 2006 0700.

    You can specify your own date formatting as specified in the Python string formatting: https://docs.python.org/2/library/time.html#time.strftime . For example if you specify %Y-%m-%d, a formatted date like 2006-09-04 will be shown.

  • fill(text[, width[, initialindent[, hangindent]]]): fill the given text to a specified length.

    If the string initialindent is specified as well, additional indentation will be used for the first line. If the string hangindent is specified as well, additional indentation will be used for all lines except the first one. The fill function limits the total length of each line, including the additional indentation.

  • get(dict, key): extract an attribute from a complex object.

    Some of the keywords that you can use in a template, are complex objects. One example is the {extras} keyword, which is a dictionary. The extras field in a changeset stores information like the branch name, but can also contain additional information. The get function allows you to extract a specific field, both from the extras and other complex objects.

  • if(expr, then[, else]): conditionally execute template parts based on the result of the given expression.

  • ifcontains(search, thing, then[, else]): conditionally execute based on whether

    the item "search" is in "thing".

  • indent(text, indentchars[, firstline]): indent text using the contents of "indentchars",

    optionally using a different indentation for the first line.

  • join(list, sep): join all the items in the list using the given separator.

  • label(label, expr): apply a specific label to the given expression.

    This is used specifically by the color extension to colour different parts of command output. A number of existing labels can be found by viewing hg help color, or you can define your own labels.

It's not always obvious how to use these functions, so here's an overview of examples for each of the above:

$ hg log -r1 --template '{date(date)}\n'
Thu Jan 01 00:00:00 1970 +0000
$ hg log -r1 --template '{date(date, "%Y-%m-%d")}\n'
1970-01-01
$ hg log -r1 --template '{fill(desc, 40, "   ", "      ")}'
   added line to end of <<hello>> file.

   in addition, added a file with the
      helpful name (at least i hope that
      some might consider it so) of
      goodbye. (no-eol)
$ hg log -r1 --template '{fill(desc, 20, "*** ", "====== ")}'
*** added line to
====== end of
====== <<hello>>
====== file.

*** in addition,
====== added a file
====== with the
====== helpful name
====== (at least i
====== hope that
====== some might
====== consider it
====== so) of
====== goodbye. (no-eol)

$ hg update -r 2
1 files updated, 0 files merged, 0 files removed, 0 files unresolved
$ touch foobar
$ hg add foobar
$ hg commit -m "Add additional file"
created new head
$ hg --config extensions.rebase= rebase
rebasing 4:43f5284fffa0 "Add additional file" (tip)
saved backup bundle to $TESTTMP/myrepo/.hg/strip-backup/43f5284fffa0-0ff4595e-backup.hg (glob)

$ hg log -r4 --template '{extras}\n'
branch=defaultrebase_source=43f5284fffa0c882f04e7ddf9048685a4d932f9e
$ hg log -r4 --template "{get(extras, 'rebase_source')}\n"
43f5284fffa0c882f04e7ddf9048685a4d932f9e

$ hg log --template "{if(tags, '--> {tags}','')} - {desc|firstline}\n"
--> tip - Add additional file
 - Added tag v0.1 for changeset e8277000e239
--> v0.1 - Added tag mytag for changeset c8ec776f4fca
--> mytag - added line to end of <<hello>> file.
 - added hello

$ hg log --template "{ifcontains('hello', desc, '>> SAYING HELLO << ', '')} - {desc|firstline}\n"
 - Add additional file
 - Added tag v0.1 for changeset e8277000e239
 - Added tag mytag for changeset c8ec776f4fca
>> SAYING HELLO <<  - added line to end of <<hello>> file.
>> SAYING HELLO <<  - added hello

$ hg log -r1 --template "{indent(desc, '    ', '  ')}\n"
  added line to end of <<hello>> file.

    in addition, added a file with the helpful name (at least i hope that some might consider it so) of goodbye.

$ hg log --template "{rev}: {join(files, ' -- ')}\n"
4: foobar
3: .hgtags
2: .hgtags
1: goodbye -- hello
0: hello

$ echo '[extensions]' >> $HGRCPATH
$ echo 'color =' >> $HGRCPATH
$ hg log --template "{label('log.branch', branch)} - {desc|firstline}\n"
default - Add additional file
default - Added tag v0.1 for changeset e8277000e239
default - Added tag mytag for changeset c8ec776f4fca
default - added line to end of <<hello>> file.
default - added hello

Note

The example for the use of labels to add colours doesn't actually show any colours above. Executing the commands in your terminal should give you pretty colours (as long as your terminal supports them). You can view the available colors and what they look like on your system using the hg debugcolor command.

Additionally, it's possible to apply a template to a list of items in an expression. For example:

$ hg log -r1 --template "{files % ' - {file}\n'}"
 - goodbye
 - hello

Setting a default template

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

[ui]
logtemplate = {node}: {desc}\n

From templates to commands

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 provide a name. This is possible using the Mercurial configuration sections '[templates]' and '[templatealias]'.

The section '[templatealias]' allows us to define new functions and keywords, which we can use in our templates.

The section '[templates]' makes it possible to create new template strings, which work in the same way as the styles that come bundled with Mercurial. You can specify the template string you want in your .hgrc, after which you can use it with --template or -T.

Alternatively, you can also use a template file. You can create a text file containing a single template string and refer to this template string by specifying --template /path/to/template/file.

The simplest of template aliases

A simple template alias consists of just one line:

$ cat >> $HGRCPATH << EOF
> [templatealias]
> changeset = "rev: {rev}"
> EOF
$ hg log -r3 --template "{changeset}"
rev: 3 (no-eol)

This tells Mercurial, “if you're printing the 'changeset' template, use the text on the right as the template”. We can use this template alias in a custom template:

$ cat >> $HGRCPATH << EOF
> [templates]
> simplechangeset = "{desc}\n{changeset}"
> EOF
$ hg log -r3 -Tsimplechangeset
Added tag v0.1 for changeset e8277000e239
rev: 3 (no-eol)

Templates by example

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

Identifying mistakes in templates

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

$ cat $HGRCPATH
cs = "startswith(bar, baz, bos, bzz)"

Notice that the broken template alias attempts to define a cs keyword, but uses an incorrect number of arguments for this keyword. Mercurial promptly complains:

$ hg log -r1 --template "{startswith(foo, bar, wup, huy)}"
hg: parse error: startswith expects two arguments

The description of the problem is not always clear (though it is in this case), but even when it is cryptic, it is almost always trivial to visually inspect the offending part of the template and see what is wrong.

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.

$ hg log -r0 --template '{node}'
0312f545d1d7e5637a821db2b82dc5057595569b (no-eol)

This is likely to be unique, and so it is useful in many cases. There are a few caveats.

  • It will not work in a completely empty repository, because such a repository does not have a revision zero.
  • Neither will it work in the (extremely rare) case where a repository is a merge of two or more formerly independent repositories, and you still have those repositories around.

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

  • As a key into a table for a database that manages repositories on a server.
  • As half of a {repository ID, revision ID} tuple. Save this information away when you run an automated build or other activity, so that you can “replay” the build later if necessary.

Listing files on multiple lines

Suppose we want to list the files changed by a changeset, one per line, with a little indentation before each file name.

$ cat > $HGRCPATH << EOF
> [templates]
> changeset = "Changed in {node|short}:\n{files % '  {file}\n'}"
> EOF
$ hg log --template changeset
Changed in 45669bc1c813:
  test.c

Mimicking Subversion's output

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

$ ./svn log -r9653
------------------------------------------------------------------------
r9653 | sean.hefty | 2006-09-27 14:39:55 -0700 (Wed, 27 Sep 2006) | 5 lines

On reporting a route error, also include the status for the error,
rather than indicating a status of 0 when an error has occurred.

Signed-off-by: Sean Hefty <sean.hefty@intel.com>

------------------------------------------------------------------------

Since Subversion's output style is fairly simple, we can easily create a few aliases and combine them into a new '{svn}' keyword.

$ cat > svn.templatealias << EOF
> [templatealias]
> header = '------------------------------------------------------------------------'
> svndate(d) = '{date(d, "%a, %d %b %Y")}'
> headerline = 'r{rev} | {author|user} | {date|isodate} ({svndate(date)})'
> description = '{desc|strip|fill76}'
> [templates]
> svn = '{header}\n\n{headerline}\n\n{description}\n\n{header}\n'
> EOF

The date is a bit more complicated. Mercurial doesn't have a keyword to replicate the Subversion 'readable' date. Instead, we create our own 'svndate' function, which in turn uses the 'date' function.

Our template doesn't perfectly match the output produced by Subversion. Subversion's output includes a count in the header of the number of lines in the commit message. We cannot replicate this in Mercurial; the templating engine does not currently provide a filter that counts the number of lines the template generates.

Using a number of template aliases keeps everything readable and makes it easy to generate output similar to subversion:

$ cat svn.templatealias >> $HGRCPATH
$ hg log -r1 -Tsvn
------------------------------------------------------------------------

r1 | test | 1970-01-01 00:00 +0000 (Thu, 01 Jan 1970)

added line to end of <<hello>> file.

in addition, added a file with the helpful name (at least i hope that some
might consider it so) of goodbye.

------------------------------------------------------------------------

We can also use a more readable multiline template to get the same result:

$ cat > svn.multiline << EOF
> [templates]
> svnmulti = {header}\n
>  {headerline}\n
>  {description}\n
>  {header}\n
> EOF

Finally, we can also use a separate template file for our multiline template:

$ cat > multiline << EOF
> {header}\n
> {headerline}\n
> {description}\n
> {header}
> EOF

The end result is still the same, we just need to pass the template file path:

$ hg log -r1 -T./multiline
------------------------------------------------------------------------

r1 | test | 1970-01-01 00:00 +0000 (Thu, 01 Jan 1970)

added line to end of <<hello>> file.

in addition, added a file with the helpful name (at least i hope that some
might consider it so) of goodbye.

------------------------------------------------------------------------

Parsing Mercurial output

Mercurial developers put a lot of effort in keeping Mercurial backwards compatible. That's not just the case for repository formats or communication between different version. Even the output format of Mercurial commands is kept as stable as possible. This is even mentioned explicitly in the Compatibility Rules. You could parse the output of hg log over a huge range of Mercurial versions and not experience any problem at all.

Of course, just because you can parse the output of the commands, that doesn't mean you should. First of all, you can use the --template option with the necessary keywords and functions to specify exactly the information you want to extract from a specific command.

Secondly, you can use the styles Mercurial provides with the explicit goal of making output easy to parse. Mercurial allows you to use the xml and json style:

$ hg log -r . -Txml
<?xml version="1.0"?>
<log>
<logentry revision="4" node="938bdbcaf6eedf1faddd64c849568c6e9750beb5">
<tag>tip</tag>
<author email="test">test</author>
<date>1970-01-01T00:00:00+00:00</date>
<msg xml:space="preserve">Add additional file</msg>
</logentry>
</log>
$ hg log -r . --template json
[
 {
  "rev": 4,
  "node": "938bdbcaf6eedf1faddd64c849568c6e9750beb5",
  "branch": "default",
  "phase": "draft",
  "user": "test",
  "date": [0, 0],
  "desc": "Add additional file",
  "bookmarks": [],
  "tags": ["tip"],
  "parents": ["91900a8c91eeb65a4da9ae79f9d86db6fadccbc8"]
 }
]
$ hg status --change . -Tjson
[
 {
  "path": "foobar",
  "status": "A"
 }
]

You can use the built-in XML or JSON libraries from whichever programming language you prefer to parse the output.

The json style is available for almost all output commands, because it's generated using a generic template system. This also means other popular data formats can easily be added in the future.

Overview of the template system

Mercurial provides an advanced template system, which provides a number of ways to customize output of its commands. To summarize, here's an overview of what we mentioned in this chapter:

  • It's possible to specify the contents of a template on the command line: --template "{node}\n". Such a template can contain built-in functions and keywords, as well as those specified in the [templatealias] section.
  • We can pass a file to be used as template: --template path/to/template/file.
  • Another option is to use a template we've specified in the [templates] section: --template templatename.
  • We can pass template styles defined by Mercurial, for example: --template compact. A list can be seen with --template list.
  • Finally, the generic template system allows generating output in formats like json: --template json.