An interesting question has just been sent by Greg Ward on the Mercurial devel mailing-list (as a funny coincidence, it happened that I had to solve this problem a few days ago).

Let me quote his message:

here's my problem: imagine a customer is running software built from
changeset A, and we want to upgrade them to a new version, built from
changeset B.  So I need to know what bugs are fixed in B that were not
fixed in A.  I have already implemented a changeset/bug mapping, so I
can trivially lookup the bugs fixed by any changeset.  (It even handles
"ongoing" and "reverted" bugs in addition to "fixed".)

And he gives an example of situation where a tricky case may be found:

                +--- 75 -- 78 -- 79 ------------+
               /                                 \
              /     +-- 77 -- 80 ---------- 84 -- 85
             /     /                        /
0 -- ... -- 74 -- 76                       /
                   \                      /
                    +-- 81 -- 82 -- 83 --+

So what is the problem?

Imagine the lastest distributed stable release is built on rev 81. Now, I need to publish a new bugfix release based on this latest stable version, including every changeset that is a bugfix, but that have not yet been applied at revision 81.

So the first problem we need to solve is answering: what are the revisions ancestors of revision 85 that are not ancestor of revision 81?

Command line solution

Using hg commands, the solution is proposed by Steve Losh:

hg log --template '{rev}\n' --rev 85:0 --follow --prune 81

or better, as suggested by Matt:

hg log -q --template '{rev}\n' --rev 85:0 --follow --prune 81

The second is better since it does only read the index, and thus is much faster. But on big repositories, this command remains quite slow (with Greg's situation, a repo of more than 100000 revisions, the command takes more than 2 minutes).

Python solution

Using Python, one may think about using revlog.nodesbetween(), but it won't work as wanted here, not listing revisions 75, 78 and 79.

On the mailing list, Matt gave the most simple and efficient solution:

cl = repo.changelog
a = set(cl.ancestors(81))
b = set(cl.ancestors(85))
revs = b - a

Idea for a new extension

Using this simple python code, it should be easy to write a nice Mercurial extension (which could be named missingrevisions) to do this job.

Then, it should be interesting to also implement some filtering feature. For example, if there are simple conventions used in commit messages, eg. using something like "[fix #1245]" or "[close #1245]" in the commit message when the changeset is a fix for a bug listed in the bugtracker, then we may type commands like:

hg missingrevs REV -f bugfix


hg missingrevs REV -h HEADREV -f bugfix

to find bugfix revisions ancestors of HEADREV that are not ancestors of REV.

With filters (bugfix here) may be configurables in hgrc using regexps.

blog entry of