Search code examples
mercurialmercurial-revsets

Mercurial - files modified in current branch


Can you help me to create a proper revset for mercurial hg status ? I would like to list all the files that were changed in the current branch since it was created. I tried

hg status --rev "branch(foo)"

where foo is the name of my branch, but this also lists files that were changed in the branch from which my branch was created (?). I don't get how to create a proper revset for this.

I created my branch and made several changes in multiple files. Now I want to reload these files in my application, but only them.


Solution

  • This seems pretty straightforward (see hg help revsets and hg help revisions for where this comes from).

    We might start with the set of all commits in a branch, e.g., for branch foo:

    -r 'branch(foo)'
    

    Obviously this can produce a dozen, or even a million, revisions; but you want to see what happened between "branch creation"—which needs to examine the parent of the first such revision—and "current status of branch", which needs to examine the last such revision.

    The first1 revision of a large set is obtained by first() and the last by last(). However, when various commands are given a revision specifier, they look it up as a single revision, and here a branch name suffices to name the last commit on the branch anyway.

    To get the (first) parent of a revision, we use the p1() function (the suffix ^ is only allowed on a literal revision, not a function that returns a revision). Hence the parent of the first revision on branch foo is:

    -r 'p1(first(branch(foo)))'
    

    To get a full diff of this against the last commit in the branch:

    hg diff -r 'p1(first(branch(foo)))' -r 'foo'
    

    But you don't want a full diff, you want the file names. The command that produces this is hg status, and it has a slightly different syntax:

    hg status --rev 'p1(first(branch(foo)))' --rev 'foo'
    

    The status includes the letters at the front, as well as the names: A for newly added files, M for modified files, and so on. Note the use of --rev rather than just -r (in fact, you can use --rev with hg diff as well).

    Note that there's a much shorter syntax, ::foo, that gets all the ancestors of the given branch up to and including the last revision in the named branch. However, this gets too many ancestors. You can, however, use p1(first(branch(foo)))::foo as the (entire) argument to --rev, and this also works. so:

    hg status --rev 'p1(first(branch(foo)))::foo`
    

    is a slightly shorter way to express this.

    Last, note that comparing the first commit in the branch to the last (as would happen with hg status --rev 'first(branch(foo))' --rev foo, for instance) can miss changes made in that first commit on the branch. That's why we use p1 here.


    1The first function selects the first in the set, which may not be the same as the numerically-first revision. For instance, suppose the set is made from x | y and a revision in y is numerically lower than a revision in x, or you use reverse(branch(foo)) to put the commits in high-to-low order. In this case, min instead of first would be the function to use.