mercurialmercurial-revsets

Mercurial: determine latest tag on each merged branch


To determine which tags have been merged into a given revision, I use a command like this:

$ hg log --style=xml -r "ancestors(471694254d60) and tag()" | grep "<tag>"
<tag>3.27.0.0</tag>
<tag>3.27.0.1</tag>
<tag>3.27.0.2</tag>
<tag>3.27.0.3</tag>
<tag>3.27.0.4</tag>
<tag>3.27.0.5</tag>
<tag>3.28.0.0</tag>
<tag>3.27.0.6</tag>
<tag>3.28.0.1</tag>
<tag>3.28.0.2</tag>
<tag>3.28.0.3</tag>
<tag>3.29.0.0</tag>
<tag>3.28.0.4</tag>
<tag>3.29.0.1</tag>
<tag>3.29.0.2</tag>
<tag>3.29.0.3</tag>
<tag>3.29.0.4</tag>
<tag>3.29.0.5</tag>
<tag>3.29.0.6</tag>

This is ok, but I'd like to improve it by instead reporting only the latest tag from each branch:

$ hg log --style=xml -r "ancestors(471694254d60) and tag() and <MYSTERY CLAUSE>" | grep "<tag>"
<tag>3.27.0.6</tag>
<tag>3.28.0.4</tag>
<tag>3.29.0.6</tag>

Hopefully the implied branch structure is obvious enough.

Does this seem possible (without using multiple hg commands or filtering the results after-the-fact)?


Solution

  • Well, 2 (dirty) solutions

    Post-processing style

    Slightly changed original command as starting point (another repository was used)

    >hg log -r "::. & tag()" --template "{branch} {tags}\n"

    (short syntax and templating, static leaf-node for testing). Result isn't OK for post-processing

    default 1.0
    default 1.0.1
    default 1.1
    default 1.1.1
    default 1.1.2
    default 1.2
    default 1.2.1
    default 1.3
    default 1.4
    default 1.5
    stable 1.5.1
    default 1.6
    stable 1.6.1
    

    because branch's specific tags are fragmented. Sorting by branch will save internal order of tags inside of every branch

    >hg log -r "sort(::. & tag(), branch)" --template "{branch} {tags}\n"
    default 1.0
    default 1.0.1
    default 1.1
    default 1.1.1
    default 1.1.2
    default 1.2
    default 1.2.1
    default 1.3
    default 1.4
    default 1.5
    default 1.6
    stable 1.5.1
    stable 1.6.1
    

    Output only last record for every branch (+ last string in list) is easy task in any language.

    In order to convert hg log | <command> ingot into usable solution, next modifications are applied

    ltb = hg log -r "sort(::$1 & tag(), branch)" --template "{branch} {tags}\n"

    (and hg ltb 471694254d60 | <command> in shell will produce result)

    ltb = !$HG log -r "sort(::$1 & tag(), branch)" --template "{branch} {tags}\n" | <command>

    (used now as just hg ltb 471694254d60)

    Pre-processing style

    "Last tagged changeset in branch" in revset's lingo will be (for you case) last(::REV & tag() & branch(BRANCH)), repeated for every branch or

    (last(::REV & tag() & branch(BRANCH1))) | (last(::REV & tag() & branch(BRANCH2)) | ... | (last(::REV & tag() & branch(BRANCHN))

    in single giant command. Main problem is to list all needed branches for command(s), because you haven't predefined list.

    You can

    Easiest way is hg branches

    >hg branches
    default                     1196:878372849175
    stable                      1179:e4b737479302 (inactive)
    

    and insert all branch-names (first field) into log by hand (hg log -r "last(::471694254d60 & tag() & branch(default))" > log.txt + hg log -r "last(::471694254d60 & tag() & branch(stable))" >> log.txt for my repo and your changeset)

    hg branches | gawk {print $1} | \ xargs -I BRANCH hg log -r "last(::471694254d60 & tag() & branch(BRANCH))" --template "{branch} {tags}\n"

    (after debugging also can be converted into shell-alias)