This page is primarily intended for developers of Mercurial.

Contributing Changes

How to help us improve Mercurial's code.

1. Submission checklist

Please double-check your patch meets the following guidelines (explained below) before submitting for review:

  1. first line of commit message is of the form "topic: uncapitalized, no trailing period"

  2. bugs that are resolved are mentioned in summary in the form "(issueNNNN)" (no space)

  3. patch does just one thing (if you need a bullet list, split your patch)

  4. patch contains no other gratuitous changes:
    • whitespace changes
    • code movement
    • typo fixes
    • string changes
  5. patch leaves Mercurial in a working state (doesn't depend on future patches)
  6. test suite has been updated and runs cleanly (use the Heptapod CI to make sure)

  7. code passes check-code and matches coding style

  8. relevant help text is updated (see mercurial/help/)

If emailing:

  1. patches are sent to the mercurial-devel mailing list (not the BTS) and are properly formatted (see below)

  2. appropriate branch is indicated in email subject (eg hg email --flag stable)
  3. version is indicated in email subject if this is an amended patch, (eg hg email --flag v2 if it has been amended once, or v3, v4, etc.)

2. Getting started

Start by cloning a copy of Mercurial's main development repo:

hg clone

You'll also want to read the following pages:

Other pages you may find important:

3. Organizing patches

{X} If your first submission is not 'minimal', you will probably be sent back here. Save yourself time and start small!

If you're making a large change, we're probably going to want it broken into a series of smaller patches (see OneChangePerPatch). This makes for easier review and tests both for us and for you. This can be tricky at first and you might find tools like histedit and the Evolve extension useful in this process.

Each patch in a series should:

<!> Do not mix formatting changes, organizational changes, or multiple functional changes in the same patch!

Things to consider:

3.1. Editing history

You will almost certainly find it necessary to do some form of history editing to generate clean commits, especially after you get your first review feedback. There are multiple tools of varying degrees of power available for this purpose:

4. Coding style and testing

<!> If you send a patch with an underscore in a variable name, we'll know you haven't read this page!

5. Example patch

Here is an example of a Mercurial patch with proper summary, description, coding style, and testing.

changeset:   21111:dda11e799529
branch:      stable
user:        FUJIWARA Katsunori <>
date:        Tue Mar 25 19:34:17 2014 +0900
files:       mercurial/ tests/test-clone.t
hg: use "os.path.join()" to join path components which may be empty (issue4203)

Changset 2d0ab571b822 rewriting "hg.copystore()" with vfs uses
'dstbase + "/lock"' instead of "os.path.join()", because target files
given from "store.copyfiles()" already uses "/" as path separator

But in the repository using revlog format 0, "dstbase" becomes empty
("data" directory is located under ".hg" directly), and 'dstbase +
"/lock"' is treated as "/lock": in almost all cases, write access to
"/lock" causes "permission denied".

This patch uses "os.path.join()" to join path components which may be
empty in "hg.copystore()".

diff -r c57c9cece645 -r dda11e799529 mercurial/
--- a/mercurial/   Mon Mar 24 21:27:40 2014 -0400
+++ b/mercurial/   Tue Mar 25 19:34:17 2014 +0900
@@ -213,8 +213,10 @@
             if srcvfs.exists(f):
                 if f.endswith('data'):
+                    # 'dstbase' may be empty (e.g. revlog format 0)
+                    lockfile = os.path.join(dstbase, "lock")
                     # lock to avoid premature writing to the target
-                    destlock = lock.lock(dstvfs, dstbase + "/lock")
+                    destlock = lock.lock(dstvfs, lockfile)
                 hardlink, n = util.copyfiles(srcvfs.join(f), dstvfs.join(f),
                 num += n
diff -r c57c9cece645 -r dda11e799529 tests/test-clone.t
--- a/tests/test-clone.t        Mon Mar 24 21:27:40 2014 -0400
+++ b/tests/test-clone.t        Tue Mar 25 19:34:17 2014 +0900
@@ -621,3 +621,17 @@

   $ cd ..
+Test clone from the repository in (emulated) revlog format 0 (issue4203):
+  $ mkdir issue4203
+  $ mkdir -p src/.hg
+  $ echo foo > src/foo
+  $ hg -R src add src/foo
+  $ hg -R src commit -m '#0'
+  $ hg -R src log -q
+  0:e1bab28bca43
+  $ hg clone -U -q src dst
+  $ hg -R dst log -q
+  0:e1bab28bca43
+  $ cd ..

6. Changing C code

Changes involving the C code should be done so that the tests will pass across changesets even without recompiling. This allows "bisect" to be run without needing to run "make" each time, for example.

A recommended strategy for changing behavior in the C code is to add a new interface to the C code when changing behavior (do not change old interfaces). Then in the Python code, check for the existence of the new interface.

If you change tests that rely on changes to C extensions, make sure you also run the tests in "pure" Python mode (and vice versa). For example:

$ python --pure

7. Patch descriptions

It's important that you describe your patch. Patch descriptions should be in the following format:

opener: check hardlink count reporting (issue1866)

The Linux CIFS kernel driver (even in 2.6.36) suffers from a hardlink
count blindness bug (lstat() returning 1 in st_nlink when it is expected
to return >1), which causes repository corruption if Mercurial running

Patch descriptions should be aimed at helping the reviewer understand the issue you're addressing.

Try to use the form "When I tried to do X, I got result Y, but the result should be Z". This is better than "X does not work" which assumes a common understanding of what it means for X to work and leaves the reader to intuit what Y and Z might have been.

Try to answer the following, where appropriate:

8. Sending patches

/!\ Don't send your patch to the BugTracker - it can't be reviewed there, so it won't go anywhere!

/!\ Sending a patch implies granting permission to use it in our project under an appropriate license

There are multiple options for sending patches to Mercurial. In order of preference:

  1. Heptapod. See Heptapod for usage instructions.

  2. email (see below)

If you have already multiple series waiting for review, sending any more patches is not advised. Please, please, please read the Flow control section.

Because this is a community project and our developers are very busy, patches will sometimes fall through the cracks. If you've gotten no response to your patch after a few days, feel free to resend it. Find the patch submission on the and reply to it, kindly requesting someone look at it. If it was submitted to Heptapod, you can leave a comment on Heptapod.

8.1. Emailing patches

The (heavily) recommended way of sending changes is through Heptapod. Email is kept as an option as a low-friction tool for small changes for drive-by contributors.

The best way to achieve well-formed patches is to use patchbomb extension which automates the process. Add something like the following to your .hgrc:



to =
from = Ada Lovelace <>
method = smtp

host =
port = 587
tls = starttls
username =

Run hg help config.smtp for more SMTP configuration options and hg help email and hg help -e patchbomb for more info on the email command and the extension that provides it.

Then run the following to do a dryrun test:

$ hg email --test <change1> <change2> ...

Notable options:

9. Flow control

Please try not to swamp the list with patches. We have more contributors than reviewers and we'd like to be sure everyone's patches get looked at.

Other advice:

10. Etiquette and advice

11. See also


ContributingChanges (last edited 2023-04-06 07:59:14 by RaphaelGomes)