mpen
mpen

Reputation: 282955

Display "path to default"?

I can see when a named branch got merged into default via this command:

hg log -r "children(ancestor(default, b21341)) and merge()" --template "{node|short} ({branch}) was merged on {date|date} -- {desc}\n"

But this displays something like:

836230f2cbc3 (b21341) was merged on Tue Mar 28 09:51:28 2017 -0700 -- terrible terrible merge
65a95167a306 (default) was merged on Tue Mar 28 09:30:06 2017 -0700 -- Merged b30695 into default

If you read those wonderful commit messages you'll notice that the second one actually says "Merged b30695 into default" even though I'm trying to figure out how b21341 got into default.

So then if I try to figure out how b21341 got merged into b30695 I'm given two more changesets:

hg log -r "children(ancestor(b30695, b21341)) and merge()" --template "{node|short} ({branch}) was merged on {date|date} -- {desc}\n"  
2e082d1b45e9 (b27369) was merged on Mon Mar 27 09:49:22 2017 -0700 -- merged in stable
73752628d887 (b29454) was merged on Mon Mar 27 11:28:41 2017 -0700 -- merge stable

And so forth.

What I'd like is a graph of how b21341 got merged into default. i.e., it should show a path of all that different named branches that it got merged into until it makes its way into default.

Is there a query that will do that?


I'm thinking something like this

hg log -G -r "b21341:default and merge()" -T "{node|short} ({branch}) | {date|date} | {desc}"

But it doesn't look quite right. I want to see the names of the branches that b21341 got merged into, but only if that branch eventually got merged into default. The graph should also terminate as soon as the merge into default happens (the query above is going up to present)


torek's suggestion yields:

$ hg log -G -r "descendants(ancestor(default, b21341)) and merge()" -T "{revset('p2(%d)', rev) % '{node|short} ({branch})'} => {node|short} ({branch}) | {date|date} | {desc|strip|firstline|strip}\n"
o    c461c6d7e725 (default) => f30e9413ff25 (default) | Tue Apr 04 12:17:20 2017 -0700 | merge
|\
| o    87e6f6864404 (default) => 682511875e7d (default) | Tue Apr 04 09:07:52 2017 -0700 | Automated merge
| |\
| | o  45ad99aabab6 (default) => a58e849eb198 (default) | Tue Apr 04 08:55:12 2017 -0700 | rpt-14
| |/
| o  36414f2bcbc2 (default) => a2c949bf13fc (default) | Mon Apr 03 20:49:27 2017 -0700 | merge
| |
| o  119a1960a61d (default) => 47fb25095be8 (default) | Mon Apr 03 20:34:25 2017 -0700 | merge
| |
| o    9c0a22b21d09 (default) => 84208df5a215 (default) | Mon Apr 03 20:17:39 2017 -0700 | merge
| |\
| o |  a9a51ef9230d (default) => 857ba78f4fdf (default) | Mon Apr 03 19:59:38 2017 -0700 | Automated merge
| |/
| o    c62e4f3565f6 (default) => f91b349e50b8 (default) | Mon Apr 03 19:39:37 2017 -0700 | Automated merge
| |\
| o |  ab9848c00bbc (default) => c62e4f3565f6 (default) | Mon Apr 03 19:07:48 2017 -0700 | fetch fixees. merged in
| |/
| o    714b6a6f826a (default) => 4a3e91baa604 (default) | Mon Apr 03 16:59:49 2017 -0700 | merge
| |\
| o |  c201b33f3ef5 (default) => 714b6a6f826a (default) | Mon Apr 03 16:27:37 2017 -0700 | ->Fetch updates
| |/
| o  4d0584f3722b (default) => 48e3df894646 (default) | Mon Apr 03 14:14:40 2017 -0700 | Automated merge
| |
| o  cc26a1fe435a (default) => 75eab9550876 (default) | Fri Mar 31 16:29:14 2017 -0700 | merge
| |
| o  2010d6c42271 (default) => 360677ad2709 (default) | Fri Mar 31 13:47:14 2017 -0700 | Mergey merge
| |
| o    c3013d9c21b0 (default) => d5f420767672 (default) | Fri Mar 31 12:42:27 2017 -0700 | Automated merge
| |\
| o |  d5fb7882ded8 (default) => c3013d9c21b0 (default) | Fri Mar 31 12:35:50 2017 -0700 | merge
| |/
| o  f6333f8b1927 (default) => 0ff996beb803 (default) | Fri Mar 31 11:07:56 2017 -0700 | Automated merge
| |
| o    12d521d98f45 (b28197) => 0aab8dd2b4c2 (default) | Thu Mar 30 14:36:29 2017 -0700 | Merged b28197 into default
| |\
| o \    8cc3cfdf55d1 (b30630) => 35f0a6f2c4f6 (default) | Thu Mar 30 14:36:26 2017 -0700 | Merged b30630 into default
| |\ \
| o \ \    c2b23ec72ff3 (b27477) => 5b6367131b36 (default) | Thu Mar 30 14:36:23 2017 -0700 | Merged b27477 into default
| |\ \ \
| | o \ \    95c0db6914cd (b28675) => bb46978c48c4 (default) | Thu Mar 30 14:32:09 2017 -0700 | Merged b28675 into default
| | |\ \ \
| | o \ \ \    866073c5de8e (b28336) => 80b486aaf058 (default) | Thu Mar 30 14:32:06 2017 -0700 | Merged b28336 into default
| | |\ \ \ \
| | o \ \ \ \    fcc5c3791172 (b30353) => 605a51c52f65 (default) | Thu Mar 30 14:30:28 2017 -0700 | Merged b30353 into default
| | |\ \ \ \ \
+---o | | | | |  1446674834b8 (b30774) => e2aed3cc1b97 (default) | Thu Mar 30 14:30:25 2017 -0700 | Merged b30774 into default
| | | | | | | |
+---o | | | | |  32a22fb906b1 (b28867) => 6b4824d7c988 (default) | Thu Mar 30 14:30:22 2017 -0700 | Merged b28867 into default
| | | | | | | |
o | | | | | | |    d3fbf05d250f (b30590) => 8b52881b125f (default) | Tue Mar 28 16:28:06 2017 -0700 | Merged b30590 into default
|\ \ \ \ \ \ \ \
o \ \ \ \ \ \ \ \    bade429fce2f (b30287) => f5a0585d38ac (default) | Tue Mar 28 15:25:47 2017 -0700 | Merged b30287 into default
|\ \ \ \ \ \ \ \ \
o \ \ \ \ \ \ \ \ \    65a95167a306 (default) => 784f90350d9f (default) | Tue Mar 28 10:39:38 2017 -0700 | Merged namespace fix
|\ \ \ \ \ \ \ \ \ \
+-------o | | | | | |  65a95167a306 (default) => c2b23ec72ff3 (b27477) | Tue Mar 28 10:36:48 2017 -0700 | Merged in default
| | | | | | | | | | |
o | | | | | | | | | |    2fa39946baa0 (b30695) => 65a95167a306 (default) | Tue Mar 28 09:30:06 2017 -0700 | Merged b30695 into default
|\ \ \ \ \ \ \ \ \ \ \
+-----------------------o  766f032973cf (default) => 836230f2cbc3 (b21341) | Tue Mar 28 09:51:28 2017 -0700 | terrible terrible merge
| | | | | | | | | | | | |
o | | | | | | | | | | | |    c1bbe7368498 (default) => 766f032973cf (default) | Tue Mar 28 09:22:44 2017 -0700 | moving stable merginess
|\ \ \ \ \ \ \ \ \ \ \ \ \

But this isn't quite right.

  1. It traces default up to present -- I want it to stop as soon as the branch makes its way into default
  2. It doesn't give a clear picture of how b21341 got into default. Near the bottom I see default being merged into b21341 but I still can't see where b21341 got merged into something else.

Upvotes: 0

Views: 48

Answers (1)

torek
torek

Reputation: 488619

Based on your text update, it sounds like you want "merges in the DAG range that starts at the merge base of default and b21341 and continues through to, but does not exceed, some possibly-difficult-to-specify node." (Though you may want a different starting point entirely, one which Mercurial can give you, but Git cannot.)

Any commit-graph-based operation has a problem here. We know where to start looking at the graph: it's either "all commits belonging to branch b21341" or "the merge base of default and b21341". Because Mercurial remembers in which branch any given commit is made, we can distinguish these two cases, which we can illustrate for very simple cases as:

...--A--o--...--D--o--...--F--...--H  (default)
      \        /          /
       B--o---C--o--...--E--...--G    (b21341)

Here, the "interesting" commits are A, which is the point at which branch b21341 forks off from default; B, which is the first commit on b21341 itself; C, which is a common ancestor of both b21341 and default; D, which is a merge commit on default that brings in b21341; E, which is the last common ancestor; F, which is another merge; G, which is the head in b21341; and H, which is the head in default. (This assumes a single head in each named branch, which is not necessarily the case, but if we have multiple unnamed heads it becomes difficult to talk about them!)

In Mercurial, we can always find all these interesting commits. (We cannot in Git, which does not remember the branch on which a commit was made: everything to the immediate left of E is on both branches. Git has a trick to help out, namely following --first-parent only, but to use it you must practice good merge discipline, which not everyone does.) The expressions to find them may get long and convoluted, but it's always possible.

If you want to start from commit E, it's the expression you have been using: ancestor(default, b21341). To start from B is easy, it's first(b21341). Finding C seems a bit hard (it's the first of a set of commits that merge "upward" toward or into default, so first(something), but specifying that set is hard, or at least hard-ish) and I'm not going to attempt it here.


In this case, of course, b21341 does not merge directly into default but rather through some intermediary or intermediaries. Hence we have a different "interesting" set of commits, though I will keep F and H from before, while adding new single letters to denote new interesting commits:

...-----------------F--...-G-...-H  (default)
 .                 /      /
  .               E----...          (some branch)
   .             /
    .           D--...              (yet another branch)
     \         /
      B--...--C--...                (b21341)

I think your "interesting" commits begin with C, which is again just ancestor(default, b21341). For compression-of-display purposes I only drew the upward merges leading back up to default, but there may be any number of non-merge commits on each of the intermediate branches, i.e., before D and before E, which we wish to skip. There may also be additional merges, such as G, that we also wish to skip as they are not on the direct path up from C: i.e., what we want to do is stop when we hit a merge that is on default and is a descendant of C:

first(descendants(ancestor(default, b21341)) and merge() and branch(default))

so I think the revset expression here is the somewhat horrifying :-) :

(ancestor(default, b21341)::first(descendants(ancestor(default, b21341)) and merge() and branch(default))) and merge()

Having picked out our commit node or nodes, we can then display it/them however we like with the templating. I'm not sure if there is a more efficient way to do this:

'{node|short} ({revset(p2node) % "{node|short} {branch}"} => {branch}) {desc}'

but it's what we want if we pick commit F and wish to see E's node ID and which branch commit E is on by E's branch name (F is of course on default in this case).

If there are additional merges "between" C and F, e.g., if the two intermediate branches merge with each other several times, you will pick all of those up. That's difficult to avoid without writing actual Python code. The template here should identify them pretty well, though.

Putting these all together and breaking up long lines:

hg log -G -r '(ancestor(default, b21341) :: \
    first(descendants(ancestor(default, b21341)) and \
       merge() and branch(default))) and merge()' -T \
    '{node|short} ({revset(p2node) % "{node|short} {branch}"} => {branch}) {desc}'

which of course I have not tested as I do not have your repository.

Upvotes: 1

Related Questions