Patchwork revset: allow negative integers to list child revs

login
register
mail settings
Submitter Sean Farley
Date Oct. 4, 2014, 4:57 p.m.
Message ID <c3bd6d6457bf42d2fbca.1412441879@1.0.0.127.in-addr.arpa>
Download mbox | patch
Permalink /patch/6115/
State Changes Requested
Headers show

Comments

Sean Farley - Oct. 4, 2014, 4:57 p.m.
# HG changeset patch
# User Sean Farley <sean.michael.farley@gmail.com>
# Date 1412441841 25200
#      Sat Oct 04 09:57:21 2014 -0700
# Node ID c3bd6d6457bf42d2fbcaba89cf0418a0d0604239
# Parent  78c916f24dd99a56e4c29153a5df3bd7d1c40edd
revset: allow negative integers to list child revs

With the heavy use of changeset evolution, it often becomes convenient (read:
necessary) to refer to a child revset easily. This patch introduces ^-1 as a
way to do that.

RFC: This syntax was the most appropriate that I could find: ^{0,1,2} refers to
a changeset's zeroth (meaning itself), first, or second parent. Therefore,
^{-1,-2,-3,...} refers to the nth child of a changeset.

TODO:
 - If accepted we'd have to change the error message away from just saying "0,
   1, or 2"

 - Allow or disallow .~-N

 - Add documentation / examples
Sean Farley - Oct. 4, 2014, 6:02 p.m.
Sean Farley writes:

> # HG changeset patch
> # User Sean Farley <sean.michael.farley@gmail.com>
> # Date 1412441841 25200
> #      Sat Oct 04 09:57:21 2014 -0700
> # Node ID c3bd6d6457bf42d2fbcaba89cf0418a0d0604239
> # Parent  78c916f24dd99a56e4c29153a5df3bd7d1c40edd
> revset: allow negative integers to list child revs

Sorry, I forgot to flag this as RFC.
Mads Kiilerich - Oct. 6, 2014, 3:45 p.m.
On 10/04/2014 06:57 PM, Sean Farley wrote:
> # HG changeset patch
> # User Sean Farley <sean.michael.farley@gmail.com>
> # Date 1412441841 25200
> #      Sat Oct 04 09:57:21 2014 -0700
> # Node ID c3bd6d6457bf42d2fbcaba89cf0418a0d0604239
> # Parent  78c916f24dd99a56e4c29153a5df3bd7d1c40edd
> revset: allow negative integers to list child revs
>
> With the heavy use of changeset evolution, it often becomes convenient (read:
> necessary) to refer to a child revset easily.

"child revset"? "refer to children in revsets"?

Is that "children" in the normal sense, where all the changesets that 
have X as parent are children of X?

Can you say more about the use case for this? When do you know that it 
is the 4th and not the 3rd child you want?

Is it finding the n'th child found among immediate children in some 
ordering, or is it iteratively taking the "best" child? (That (and the 
ordering) should be clarified in patch description and documentation.)

(Assuming it is following a chain of "first child", it would be more 
consistent if it was like X~-2. The common case in a DAG is to have only 
one ancestor, and a chain of "first ancestors" is thus usually quite 
obvious and well defined (and usually converging if it is ambiguous). I 
think it is less obvious what "chain of first child" would be ... and it 
would be more fragile.)

/Mads

> This patch introduces ^-1 as a
> way to do that.
>
> RFC: This syntax was the most appropriate that I could find: ^{0,1,2} refers to
> a changeset's zeroth (meaning itself), first, or second parent. Therefore,
> ^{-1,-2,-3,...} refers to the nth child of a changeset.
>
> TODO:
>   - If accepted we'd have to change the error message away from just saying "0,
>     1, or 2"
>
>   - Allow or disallow .~-N
>
>   - Add documentation / examples
>
> diff --git a/mercurial/revset.py b/mercurial/revset.py
> --- a/mercurial/revset.py
> +++ b/mercurial/revset.py
> @@ -1250,11 +1250,11 @@ def parentspec(repo, subset, x, n):
>       ``set^1`` (or ``set^``), ``set^2``
>       First or second parent, respectively, of all changesets in set.
>       """
>       try:
>           n = int(n[1])
> -        if n not in (0, 1, 2):
> +        if n > 2:
>               raise ValueError
>       except (TypeError, ValueError):
>           raise error.ParseError(_("^ expects a number 0, 1, or 2"))
>       ps = set()
>       cl = repo.changelog
> @@ -1265,10 +1265,16 @@ def parentspec(repo, subset, x, n):
>               ps.add(cl.parentrevs(r)[0])
>           elif n == 2:
>               parents = cl.parentrevs(r)
>               if len(parents) > 1:
>                   ps.add(parents[1])
> +        else: # negative number means the nth-child
> +            children = cl.children(repo[r].node())
> +            idx = -n-1
> +            if children and idx < len(children):
> +                ps.add(repo[children[idx]].rev())
> +
>       return subset & ps
>   
>   def present(repo, subset, x):
>       """``present(set)``
>       An empty set, if any revision in set isn't found; otherwise,
> diff --git a/tests/test-revset.t b/tests/test-revset.t
> --- a/tests/test-revset.t
> +++ b/tests/test-revset.t
> @@ -778,10 +778,18 @@ multiple revspecs
>     4
>     5
>     6
>     7
>   
> +test getting child revs
> +
> +  $ log 'merge()~3^-1'
> +  2
> +  $ log 'merge()~3^-2'
> +  3
> +
> +
>   test usage in revpair (with "+")
>   
>   (real pair)
>   
>     $ hg diff -r 'tip^^' -r 'tip'
> _______________________________________________
> Mercurial-devel mailing list
> Mercurial-devel@selenic.com
> http://selenic.com/mailman/listinfo/mercurial-devel
Sean Farley - Oct. 6, 2014, 5:24 p.m.
Mads Kiilerich writes:

> On 10/04/2014 06:57 PM, Sean Farley wrote:
>> # HG changeset patch
>> # User Sean Farley <sean.michael.farley@gmail.com>
>> # Date 1412441841 25200
>> #      Sat Oct 04 09:57:21 2014 -0700
>> # Node ID c3bd6d6457bf42d2fbcaba89cf0418a0d0604239
>> # Parent  78c916f24dd99a56e4c29153a5df3bd7d1c40edd
>> revset: allow negative integers to list child revs
>>
>> With the heavy use of changeset evolution, it often becomes convenient (read:
>> necessary) to refer to a child revset easily.
>
> "child revset"? "refer to children in revsets"?

Whoops, yes, I meant children of a changeset.

> Is that "children" in the normal sense, where all the changesets that 
> have X as parent are children of X?

Yes.

> Can you say more about the use case for this? When do you know that it 
> is the 4th and not the 3rd child you want?

This comes up very frequently in evolve where you easily have a parent
of a commit and no easy way (revset way) to refer to the child.

> Is it finding the n'th child found among immediate children in some 
> ordering, or is it iteratively taking the "best" child? (That (and the 
> ordering) should be clarified in patch description and documentation.)

Good question. The ordering is given by changelog.children. It would
seem to be the revision number order. Thoughts on putting a (documented)
order on this?

> (Assuming it is following a chain of "first child", it would be more 
> consistent if it was like X~-2. The common case in a DAG is to have only 
> one ancestor, and a chain of "first ancestors" is thus usually quite 
> obvious and well defined (and usually converging if it is ambiguous). I 
> think it is less obvious what "chain of first child" would be ... and it 
> would be more fragile.)

I haven't thought of a good way to do this. With this patch, X^-2 refers
to the second child (for now, we won't worry about order). X^-50 would
be the 50th child. X~-50 would be ... the 50th first child? I don't know.
Siddharth Agarwal - Oct. 6, 2014, 5:33 p.m.
On 10/04/2014 09:57 AM, Sean Farley wrote:
> # HG changeset patch
> # User Sean Farley <sean.michael.farley@gmail.com>
> # Date 1412441841 25200
> #      Sat Oct 04 09:57:21 2014 -0700
> # Node ID c3bd6d6457bf42d2fbcaba89cf0418a0d0604239
> # Parent  78c916f24dd99a56e4c29153a5df3bd7d1c40edd
> revset: allow negative integers to list child revs

I like the idea of having a shorthand for children, but I'm not in 
favour of the shorthand being to select particular children. I think the 
shorthand we need is for 'all children' instead.

I might be OK with '^-1' to mean 'all children'.
Sean Farley - Oct. 6, 2014, 5:58 p.m.
Siddharth Agarwal writes:

> On 10/04/2014 09:57 AM, Sean Farley wrote:
>> # HG changeset patch
>> # User Sean Farley <sean.michael.farley@gmail.com>
>> # Date 1412441841 25200
>> #      Sat Oct 04 09:57:21 2014 -0700
>> # Node ID c3bd6d6457bf42d2fbcaba89cf0418a0d0604239
>> # Parent  78c916f24dd99a56e4c29153a5df3bd7d1c40edd
>> revset: allow negative integers to list child revs
>
> I like the idea of having a shorthand for children, but I'm not in 
> favour of the shorthand being to select particular children. I think the 
> shorthand we need is for 'all children' instead.

That's fair. Would you want to support index notation? e.g. X[N] for the
Nth child? It might get funky with ordering as Mads pointed out.

> I might be OK with '^-1' to mean 'all children'.

Yeah, that might be ok, too.
Mads Kiilerich - Oct. 6, 2014, 6:41 p.m.
On 10/06/2014 07:33 PM, Siddharth Agarwal wrote:
> On 10/04/2014 09:57 AM, Sean Farley wrote:
>> # HG changeset patch
>> # User Sean Farley <sean.michael.farley@gmail.com>
>> # Date 1412441841 25200
>> #      Sat Oct 04 09:57:21 2014 -0700
>> # Node ID c3bd6d6457bf42d2fbcaba89cf0418a0d0604239
>> # Parent  78c916f24dd99a56e4c29153a5df3bd7d1c40edd
>> revset: allow negative integers to list child revs
>
> I like the idea of having a shorthand for children, 

Yeah, it seems like this really is a shorthand for children(X)?

> but I'm not in favour of the shorthand being to select particular 
> children. I think the shorthand we need is for 'all children' instead.

Yes, it seems about right that the singlerev interpretation of that 
would be the tipmost child.

>
> I might be OK with '^-1' to mean 'all children'.

It could however be confusing that x^n gives a single revision for n = 
0, 1, 2 but a set for n = -1.

The n in x^n designates which options to use. The n in x~n designates 
distance from x. It would thus be more consistent to use x~-1 ... and it 
would also be more that x~-2 should mean children(children(X)).

Any use of negative numbers would also make x^-1 more ambiguous (unless 
precedence is considered). Some other symbol would be nice. The best 
(but not so good) candidates could be something with ! or the ~^ 
combination.

/Mads
Sean Farley - Oct. 6, 2014, 6:47 p.m.
Mads Kiilerich writes:

> On 10/06/2014 07:33 PM, Siddharth Agarwal wrote:
>> On 10/04/2014 09:57 AM, Sean Farley wrote:
>>> # HG changeset patch
>>> # User Sean Farley <sean.michael.farley@gmail.com>
>>> # Date 1412441841 25200
>>> #      Sat Oct 04 09:57:21 2014 -0700
>>> # Node ID c3bd6d6457bf42d2fbcaba89cf0418a0d0604239
>>> # Parent  78c916f24dd99a56e4c29153a5df3bd7d1c40edd
>>> revset: allow negative integers to list child revs
>>
>> I like the idea of having a shorthand for children, 
>
> Yeah, it seems like this really is a shorthand for children(X)?
>
>> but I'm not in favour of the shorthand being to select particular 
>> children. I think the shorthand we need is for 'all children' instead.
>
> Yes, it seems about right that the singlerev interpretation of that 
> would be the tipmost child.
>
>>
>> I might be OK with '^-1' to mean 'all children'.
>
> It could however be confusing that x^n gives a single revision for n = 
> 0, 1, 2 but a set for n = -1.
>
> The n in x^n designates which options to use. The n in x~n designates 
> distance from x. It would thus be more consistent to use x~-1 ... and it 
> would also be more that x~-2 should mean children(children(X)).

Sure, this works for me. By that, I mean, X~-2 is children(children(X)).
Pierre-Yves David - Oct. 7, 2014, 6:11 a.m.
On 10/04/2014 09:57 AM, Sean Farley wrote:
> # HG changeset patch
> # User Sean Farley <sean.michael.farley@gmail.com>
> # Date 1412441841 25200
> #      Sat Oct 04 09:57:21 2014 -0700
> # Node ID c3bd6d6457bf42d2fbcaba89cf0418a0d0604239
> # Parent  78c916f24dd99a56e4c29153a5df3bd7d1c40edd
> revset: allow negative integers to list child revs

Quick reply on various subject.

As X^1 and X^2 return a single revision (per X) (short version for p1(X) 
and P2(X)) It would be a bad idea to have X^-1 return multiple revision.

first(children(X)) have less good defined semantic as first(parents(X)) 
as it no deterministic and will change over time. the first parent of a 
changeset is carved in stone. The amount of Children change over time 
and with history rewriting, their order change over time. So you cannot 
really predict the order. You need to (a) have one parent or (b) look 
the number up (c) use a more precise revsets:
   children(X) and ::bookmarkname
   children(X) and desc(yyy)

With evolution, the children revset become less useful when you have 
unstable changeset. Because you may have obsolete or non obsolete 
children. (hg next was an alias for `hg log --rev `children(.) - 
obsolete()` for some time). Handling this requires to use more complex 
revsets.


Given all the issue above, I'm not convinced about the benefit of a 
children append notation. We'll have to mix it with other revset to get 
something useful in a lot of case. I agree that children(X) is a bit 
cumbersome. So I support the mpm proposal for c(x))ion so much.

However, I'm curious about your use case. Can you details them? So that 
we have a better idea of the issue you are trying to solve here ?
Sean Farley - Oct. 7, 2014, 6:40 p.m.
Pierre-Yves David writes:

> On 10/04/2014 09:57 AM, Sean Farley wrote:
>> # HG changeset patch
>> # User Sean Farley <sean.michael.farley@gmail.com>
>> # Date 1412441841 25200
>> #      Sat Oct 04 09:57:21 2014 -0700
>> # Node ID c3bd6d6457bf42d2fbcaba89cf0418a0d0604239
>> # Parent  78c916f24dd99a56e4c29153a5df3bd7d1c40edd
>> revset: allow negative integers to list child revs
>
> Quick reply on various subject.
>
> As X^1 and X^2 return a single revision (per X) (short version for p1(X) 
> and P2(X)) It would be a bad idea to have X^-1 return multiple revision.

I agree.

> first(children(X)) have less good defined semantic as first(parents(X)) 
> as it no deterministic and will change over time. the first parent of a 
> changeset is carved in stone. The amount of Children change over time 
> and with history rewriting, their order change over time. So you cannot 
> really predict the order. You need to (a) have one parent or (b) look 
> the number up (c) use a more precise revsets:
>    children(X) and ::bookmarkname
>    children(X) and desc(yyy)

They should always be returned in the revlog order. That is what we
currently do with referring to children via revision numbers. This would
be no added confusion.

> With evolution, the children revset become less useful when you have 
> unstable changeset. Because you may have obsolete or non obsolete 
> children. (hg next was an alias for `hg log --rev `children(.) - 
> obsolete()` for some time). Handling this requires to use more complex 
> revsets.

Yes, evolution does throw a wrench into thing but that's another patch
series.

> Given all the issue above, I'm not convinced about the benefit of a 
> children append notation. We'll have to mix it with other revset to get 
> something useful in a lot of case. I agree that children(X) is a bit 
> cumbersome. So I support the mpm proposal for c(x))ion so much.

Anyone can use revset alias to make 'c' into 'children'. That's not the
point here.

> However, I'm curious about your use case. Can you details them? So that 
> we have a better idea of the issue you are trying to solve here ?

There are many, many cases of navigating relative to the currently
checked out revision '.'. Given the following DAG:

A <-- X <-- C
B <-/   \-- D

Where A and B are parents of X, and C and D are children of X, where X
is my current changeset, we can (with this proposal) refer to each
changeset A, B, C, and D with X^1, X^2, X^-1, X^-2, respectively.

The most common case for this (and the reason I wrote this patch) was
when I was patch reviewing via 'hg prev' / 'hg next'. So, I would end up
in the middle of some line of history and would want to see the diff of
the next child.

Though, this is not the only case, it is a common one for me (bisection
being another frequent one).

As another (future) example, let's pretend we have '<-' and '->' mean
successor and precursor, respectively, then referring to the changeset
that 'hg evolve' would rebase onto our current changeset:

hg log -r .->^-1

I don't think -> is a good operator but this is just an example.
Pierre-Yves David - Oct. 7, 2014, 7:57 p.m.
On 10/07/2014 11:40 AM, Sean Farley wrote:
>
> Pierre-Yves David writes:
>
>> On 10/04/2014 09:57 AM, Sean Farley wrote:
>>> # HG changeset patch
>>> # User Sean Farley <sean.michael.farley@gmail.com>
>>> # Date 1412441841 25200
>>> #      Sat Oct 04 09:57:21 2014 -0700
>>> # Node ID c3bd6d6457bf42d2fbcaba89cf0418a0d0604239
>>> # Parent  78c916f24dd99a56e4c29153a5df3bd7d1c40edd
>>> revset: allow negative integers to list child revs
>>
>> Quick reply on various subject.
>>
>> As X^1 and X^2 return a single revision (per X) (short version for p1(X)
>> and P2(X)) It would be a bad idea to have X^-1 return multiple revision.
>
> I agree.
>
>> first(children(X)) have less good defined semantic as first(parents(X))
>> as it no deterministic and will change over time. the first parent of a
>> changeset is carved in stone. The amount of Children change over time
>> and with history rewriting, their order change over time. So you cannot
>> really predict the order. You need to (a) have one parent or (b) look
>> the number up (c) use a more precise revsets:
>>     children(X) and ::bookmarkname
>>     children(X) and desc(yyy)
>
> They should always be returned in the revlog order. That is what we
> currently do with referring to children via revision numbers. This would
> be no added confusion.

You got me wrong. Their will of course be returned in revlog order. This 
means that if you have three child A, B, C. You initially have

   children(X) = A, B, C

Then you amend A. So you get

   children(X) = B, C, A

And C get touched. So you get


   children(X) = B, A, C

Then you pull a new version X from someone with a children D. You evolve 
and you end up with:

   children(X) = D, B, A, C

So you cannot blindly rely on c(X, 1) to give you stable result. And 
normal human being have too look up the revset or use more precise revset.

(will get to reply to the rest later)
Sean Farley - Oct. 7, 2014, 8:01 p.m.
Pierre-Yves David writes:

> On 10/07/2014 11:40 AM, Sean Farley wrote:
>>
>> Pierre-Yves David writes:
>>
>>> On 10/04/2014 09:57 AM, Sean Farley wrote:
>>>> # HG changeset patch
>>>> # User Sean Farley <sean.michael.farley@gmail.com>
>>>> # Date 1412441841 25200
>>>> #      Sat Oct 04 09:57:21 2014 -0700
>>>> # Node ID c3bd6d6457bf42d2fbcaba89cf0418a0d0604239
>>>> # Parent  78c916f24dd99a56e4c29153a5df3bd7d1c40edd
>>>> revset: allow negative integers to list child revs
>>>
>>> Quick reply on various subject.
>>>
>>> As X^1 and X^2 return a single revision (per X) (short version for p1(X)
>>> and P2(X)) It would be a bad idea to have X^-1 return multiple revision.
>>
>> I agree.
>>
>>> first(children(X)) have less good defined semantic as first(parents(X))
>>> as it no deterministic and will change over time. the first parent of a
>>> changeset is carved in stone. The amount of Children change over time
>>> and with history rewriting, their order change over time. So you cannot
>>> really predict the order. You need to (a) have one parent or (b) look
>>> the number up (c) use a more precise revsets:
>>>     children(X) and ::bookmarkname
>>>     children(X) and desc(yyy)
>>
>> They should always be returned in the revlog order. That is what we
>> currently do with referring to children via revision numbers. This would
>> be no added confusion.
>
> You got me wrong. Their will of course be returned in revlog order. This 
> means that if you have three child A, B, C. You initially have
>
>    children(X) = A, B, C
>
> Then you amend A. So you get
>
>    children(X) = B, C, A
>
> And C get touched. So you get
>
>
>    children(X) = B, A, C
>
> Then you pull a new version X from someone with a children D. You evolve 
> and you end up with:
>
>    children(X) = D, B, A, C
>
> So you cannot blindly rely on c(X, 1) to give you stable result. And 
> normal human being have too look up the revset or use more precise revset.
>
> (will get to reply to the rest later)

Yes, of course, but this is derailing the current discussion. We have
the concept of local revision numbers and this patch is a way to refer
to that. I would suggest another discussion about the order of
children().
Pierre-Yves David - Oct. 7, 2014, 8:06 p.m.
On 10/07/2014 01:01 PM, Sean Farley wrote:
>
> Pierre-Yves David writes:
>
>> On 10/07/2014 11:40 AM, Sean Farley wrote:
>>>
>>> Pierre-Yves David writes:
>>>
>>>> On 10/04/2014 09:57 AM, Sean Farley wrote:
>>>>> # HG changeset patch
>>>>> # User Sean Farley <sean.michael.farley@gmail.com>
>>>>> # Date 1412441841 25200
>>>>> #      Sat Oct 04 09:57:21 2014 -0700
>>>>> # Node ID c3bd6d6457bf42d2fbcaba89cf0418a0d0604239
>>>>> # Parent  78c916f24dd99a56e4c29153a5df3bd7d1c40edd
>>>>> revset: allow negative integers to list child revs
>>>>
>>>> Quick reply on various subject.
>>>>
>>>> As X^1 and X^2 return a single revision (per X) (short version for p1(X)
>>>> and P2(X)) It would be a bad idea to have X^-1 return multiple revision.
>>>
>>> I agree.
>>>
>>>> first(children(X)) have less good defined semantic as first(parents(X))
>>>> as it no deterministic and will change over time. the first parent of a
>>>> changeset is carved in stone. The amount of Children change over time
>>>> and with history rewriting, their order change over time. So you cannot
>>>> really predict the order. You need to (a) have one parent or (b) look
>>>> the number up (c) use a more precise revsets:
>>>>      children(X) and ::bookmarkname
>>>>      children(X) and desc(yyy)
>>>
>>> They should always be returned in the revlog order. That is what we
>>> currently do with referring to children via revision numbers. This would
>>> be no added confusion.
>>
>> You got me wrong. Their will of course be returned in revlog order. This
>> means that if you have three child A, B, C. You initially have
>>
>>     children(X) = A, B, C
>>
>> Then you amend A. So you get
>>
>>     children(X) = B, C, A
>>
>> And C get touched. So you get
>>
>>
>>     children(X) = B, A, C
>>
>> Then you pull a new version X from someone with a children D. You evolve
>> and you end up with:
>>
>>     children(X) = D, B, A, C
>>
>> So you cannot blindly rely on c(X, 1) to give you stable result. And
>> normal human being have too look up the revset or use more precise revset.
>>
>> (will get to reply to the rest later)
>
> Yes, of course, but this is derailing the current discussion. We have
> the concept of local revision numbers and this patch is a way to refer
> to that. I would suggest another discussion about the order of
> children().

This is not to challenge the order of children(X). This is to point out 
that children can barely be used alone and therefor having a supershort 
version of it is not that useful.
Sean Farley - Oct. 7, 2014, 8:12 p.m.
Pierre-Yves David writes:

> On 10/07/2014 01:01 PM, Sean Farley wrote:
>>
>> Pierre-Yves David writes:
>>
>>> On 10/07/2014 11:40 AM, Sean Farley wrote:
>>>>
>>>> Pierre-Yves David writes:
>>>>
>>>>> On 10/04/2014 09:57 AM, Sean Farley wrote:
>>>>>> # HG changeset patch
>>>>>> # User Sean Farley <sean.michael.farley@gmail.com>
>>>>>> # Date 1412441841 25200
>>>>>> #      Sat Oct 04 09:57:21 2014 -0700
>>>>>> # Node ID c3bd6d6457bf42d2fbcaba89cf0418a0d0604239
>>>>>> # Parent  78c916f24dd99a56e4c29153a5df3bd7d1c40edd
>>>>>> revset: allow negative integers to list child revs
>>>>>
>>>>> Quick reply on various subject.
>>>>>
>>>>> As X^1 and X^2 return a single revision (per X) (short version for p1(X)
>>>>> and P2(X)) It would be a bad idea to have X^-1 return multiple revision.
>>>>
>>>> I agree.
>>>>
>>>>> first(children(X)) have less good defined semantic as first(parents(X))
>>>>> as it no deterministic and will change over time. the first parent of a
>>>>> changeset is carved in stone. The amount of Children change over time
>>>>> and with history rewriting, their order change over time. So you cannot
>>>>> really predict the order. You need to (a) have one parent or (b) look
>>>>> the number up (c) use a more precise revsets:
>>>>>      children(X) and ::bookmarkname
>>>>>      children(X) and desc(yyy)
>>>>
>>>> They should always be returned in the revlog order. That is what we
>>>> currently do with referring to children via revision numbers. This would
>>>> be no added confusion.
>>>
>>> You got me wrong. Their will of course be returned in revlog order. This
>>> means that if you have three child A, B, C. You initially have
>>>
>>>     children(X) = A, B, C
>>>
>>> Then you amend A. So you get
>>>
>>>     children(X) = B, C, A
>>>
>>> And C get touched. So you get
>>>
>>>
>>>     children(X) = B, A, C
>>>
>>> Then you pull a new version X from someone with a children D. You evolve
>>> and you end up with:
>>>
>>>     children(X) = D, B, A, C
>>>
>>> So you cannot blindly rely on c(X, 1) to give you stable result. And
>>> normal human being have too look up the revset or use more precise revset.
>>>
>>> (will get to reply to the rest later)
>>
>> Yes, of course, but this is derailing the current discussion. We have
>> the concept of local revision numbers and this patch is a way to refer
>> to that. I would suggest another discussion about the order of
>> children().
>
> This is not to challenge the order of children(X). This is to point out 
> that children can barely be used alone and therefor having a supershort 
> version of it is not that useful.

I'm surprised you are being this stubborn about it. It is very, very
common to have a set of linear changes. It is even still common to be in
a situation where you only have a reference to the parent of a
changeset.
Augie Fackler - Oct. 8, 2014, 12:37 a.m.
On Oct 7, 2014, at 4:12 PM, Sean Farley <sean.michael.farley@gmail.com> wrote:

>>> Yes, of course, but this is derailing the current discussion. We have
>>> the concept of local revision numbers and this patch is a way to refer
>>> to that. I would suggest another discussion about the order of
>>> children().
>> 
>> This is not to challenge the order of children(X). This is to point out 
>> that children can barely be used alone and therefor having a supershort 
>> version of it is not that useful.
> 
> I'm surprised you are being this stubborn about it. It is very, very
> common to have a set of linear changes. It is even still common to be in
> a situation where you only have a reference to the parent of a
> changeset.

I could see a claim that an "only child of" operator would be more useful than an "arbitrary child" operator (that is, abort if len(children) != 1). Maybe that'd be the useful middle ground here?
Sean Farley - Oct. 8, 2014, 12:44 a.m.
Augie Fackler writes:

> On Oct 7, 2014, at 4:12 PM, Sean Farley <sean.michael.farley@gmail.com> wrote:
>
>>>> Yes, of course, but this is derailing the current discussion. We have
>>>> the concept of local revision numbers and this patch is a way to refer
>>>> to that. I would suggest another discussion about the order of
>>>> children().
>>> 
>>> This is not to challenge the order of children(X). This is to point out 
>>> that children can barely be used alone and therefor having a supershort 
>>> version of it is not that useful.
>> 
>> I'm surprised you are being this stubborn about it. It is very, very
>> common to have a set of linear changes. It is even still common to be in
>> a situation where you only have a reference to the parent of a
>> changeset.
>
> I could see a claim that an "only child of" operator would be more useful than an "arbitrary child" operator (that is, abort if len(children) != 1). Maybe that'd be the useful middle ground here?

I really don't see the problem with an arbitrary child operator. For
most cases, the use would be with one child. If someone wants to use it
for the second child, then that is also deterministic: ordered by local
revnum.
Augie Fackler - Oct. 8, 2014, 1:36 p.m.
On Tue, Oct 7, 2014 at 8:44 PM, Sean Farley
<sean.michael.farley@gmail.com> wrote:
>
> Augie Fackler writes:
>
>> On Oct 7, 2014, at 4:12 PM, Sean Farley <sean.michael.farley@gmail.com> wrote:
>>
>>>>> Yes, of course, but this is derailing the current discussion. We have
>>>>> the concept of local revision numbers and this patch is a way to refer
>>>>> to that. I would suggest another discussion about the order of
>>>>> children().
>>>>
>>>> This is not to challenge the order of children(X). This is to point out
>>>> that children can barely be used alone and therefor having a supershort
>>>> version of it is not that useful.
>>>
>>> I'm surprised you are being this stubborn about it. It is very, very
>>> common to have a set of linear changes. It is even still common to be in
>>> a situation where you only have a reference to the parent of a
>>> changeset.
>>
>> I could see a claim that an "only child of" operator would be more useful than an "arbitrary child" operator (that is, abort if len(children) != 1). Maybe that'd be the useful middle ground here?
>
> I really don't see the problem with an arbitrary child operator. For
> most cases, the use would be with one child. If someone wants to use it
> for the second child, then that is also deterministic: ordered by local
> revnum.


I don't disagree, but I can see Pierre-Yves's position: we are adding
a little bit to the rope of surprising behavior by allowing nth-child
selection, and maybe it's worth avoiding. Was just trying to offer a
suggestion that (in my mind) solves the immediate pain around wanting
a child-of operator (which I do), and Pierre-Yves's worry so we can
make progress.
Pierre-Yves David - Oct. 9, 2014, 2:55 a.m.
On 10/07/2014 11:40 AM, Sean Farley wrote:
>
> Pierre-Yves David writes:
>
>> On 10/04/2014 09:57 AM, Sean Farley wrote:
>>> # HG changeset patch
>>> # User Sean Farley <sean.michael.farley@gmail.com>
>>> # Date 1412441841 25200
>>> #      Sat Oct 04 09:57:21 2014 -0700
>>> # Node ID c3bd6d6457bf42d2fbcaba89cf0418a0d0604239
>>> # Parent  78c916f24dd99a56e4c29153a5df3bd7d1c40edd
>>> revset: allow negative integers to list child revs
>>
>> Quick reply on various subject.
>>
>> As X^1 and X^2 return a single revision (per X) (short version for p1(X)
>> and P2(X)) It would be a bad idea to have X^-1 return multiple revision.
>
> I agree.

Quick dance to highlight we agree on some of this ;-)

>> However, I'm curious about your use case. Can you details them? So that
>> we have a better idea of the issue you are trying to solve here ?
>
> There are many, many cases of navigating relative to the currently
> checked out revision '.'. Given the following DAG:
>
> A <-- X <-- C
> B <-/   \-- D
>
> Where A and B are parents of X, and C and D are children of X, where X
> is my current changeset, we can (with this proposal) refer to each
> changeset A, B, C, and D with X^1, X^2, X^-1, X^-2, respectively.

But X^-1 and X^-2 are going to be unreliable over time (see my other email).

The reason as why I'm asking for usecase is because I, as a hardcore and 
long term user of evolution an hiking along the graph, have rarely been 
found in situation where I could reliably count on children(x).

> The most common case for this (and the reason I wrote this patch) was
> when I was patch reviewing via 'hg prev' / 'hg next'. So, I would end up
> in the middle of some line of history and would want to see the diff of
> the next child.
>
> Though, this is not the only case, it is a common one for me (bisection
> being another frequent one).
>
> As another (future) example, let's pretend we have '<-' and '->' mean
> successor and precursor, respectively, then referring to the changeset
> that 'hg evolve' would rebase onto our current changeset:

(Lets index each paragraph 1, 2 and 3)

I would like to hear more about your bisect usecase (2).

(1) and (3) seems similar to me. In both case, I read them as "I want to 
select the "next" changesets (target of `hg next`). (For (3) this 
requires issue4390 to be implemented).

And given that `hg next` could not stay a simple as `hg up children(.)` 
I'm doubting that an operator for `children` will do the trick here.

Augies proposal made me think that -maybe- we need a `next(x)` revset. 
See other emails for details.

I'm eager to ear about your bisection case.
Pierre-Yves David - Oct. 9, 2014, 2:55 a.m.
On 10/07/2014 05:44 PM, Sean Farley wrote:
>
> Augie Fackler writes:
>
>> On Oct 7, 2014, at 4:12 PM, Sean Farley <sean.michael.farley@gmail.com> wrote:
>>
>>>>> Yes, of course, but this is derailing the current discussion. We have
>>>>> the concept of local revision numbers and this patch is a way to refer
>>>>> to that. I would suggest another discussion about the order of
>>>>> children().
>>>>
>>>> This is not to challenge the order of children(X). This is to point out
>>>> that children can barely be used alone and therefor having a supershort
>>>> version of it is not that useful.
>>>
>>> I'm surprised you are being this stubborn about it. It is very, very
>>> common to have a set of linear changes. It is even still common to be in
>>> a situation where you only have a reference to the parent of a
>>> changeset.

The things I'm fighting againts here, is feature creep. I'm not fan of 
adding new operator because:

1) We have a limited set of char that can be operator.
2) Rarely used operator makes revset harder to read since it is harder 
to remember "::" than to read "ancestors" out. Revset readability is an 
important argument for newbies.

So I'm questioning:

1) The necessity for an operator poking at children in general
2) The fact that this operator will be actually useful alone in most case.

This (2) is the reason why I'm stubborn at pointing all the issue with a 
children operator. And I'll keep pointing at them until I'm under the 
impression that people involved in that discussion have properly 
understood them.

This limitation themselves will maybe not get people to change their 
mind, but they should be aware of them before taking a decision.

>> I could see a claim that an "only child of" operator would be more useful than an "arbitrary child" operator (that is, abort if len(children) != 1). Maybe that'd be the useful middle ground here?

Things are a bit more complex that than. You can have multiple children, 
but only one is non-obsolete:

   o B'
   |
   | o C
   | |
   | x B
   | /
   |/
   A

This is the reason `hg next` exist in the first place. Because 
children(x) was not doing the job at rulling out obsolete changesets 
(and because I wanted ambiguity pointed out.)

Maybe a `next(X)` revset would be useful. It would return the target for 
`hg next` when no ambiguity exists. (I'm not sure what it would do in 
the face of ambiguity).

It could also grow capability to select the changeset that would be 
evolve by an `hg next --evolve` call.

> I really don't see the problem with an arbitrary child operator. For
> most cases, the use would be with one child.

You usecase for it seems very connected to evolution. Where it is fairly 
common end up with more than one changesets.

> If someone wants to use it
> for the second child, then that is also deterministic: ordered by local
> revnum.

Again. The order of children is not deterministic enough to be useful. 
Of course it is stable under exact same condition (because it is ordered 
by revnum). But it far much more unstable other stuff.

For example, `p1(e8832cf1abf6)` will always give you the same result. 
And this is even true in different repository. `children(e8832cf1abf6)` 
is not going to give stable results (in mutable history). While history 
is getting rewritten. revision number of (semantic) changeset changes.

   o   B: fix doc
   |
   | o A: add feature.
   \ /
    o  O: base

At some point of time `first(children(O))` will return `A: add feature`. 
And at some other point of time it may return `B: fix doc` (because `A` 
could have been touched in between, so its revnum was bumped).

Therefore, one can not blindly use children(x) to refer to one in many 
children. Because unlike X^1, X^-1 is not going to return stable result.

(end of explanation of why children give unstable result. Can I get you 
to acknowledge this?)

So whenever there is multiple children involved it is very likely that 
the user have to either:

a) Explicitly look the children
b) Use a more precise revset (eg: `children(x) and ancestors(y)`)

So, in my opinion, the benefit of a short operator is likely to get 
nullified by either and explicit reference (case a) or the need to build 
a complex revset anyway.
Sean Farley - Oct. 9, 2014, 3:09 a.m.
Pierre-Yves David writes:

> On 10/07/2014 05:44 PM, Sean Farley wrote:
>>
>> Augie Fackler writes:
>>
>>> On Oct 7, 2014, at 4:12 PM, Sean Farley <sean.michael.farley@gmail.com> wrote:
>>>
>>>>>> Yes, of course, but this is derailing the current discussion. We have
>>>>>> the concept of local revision numbers and this patch is a way to refer
>>>>>> to that. I would suggest another discussion about the order of
>>>>>> children().
>>>>>
>>>>> This is not to challenge the order of children(X). This is to point out
>>>>> that children can barely be used alone and therefor having a supershort
>>>>> version of it is not that useful.
>>>>
>>>> I'm surprised you are being this stubborn about it. It is very, very
>>>> common to have a set of linear changes. It is even still common to be in
>>>> a situation where you only have a reference to the parent of a
>>>> changeset.
>
> The things I'm fighting againts here, is feature creep. I'm not fan of 
> adding new operator because:

This isn't a new operator. It's extending the use of '^' and doesn't
force a new character.

At this point, I'm only interested in what mpm has to say about it and
what direction he wants to go.
Pierre-Yves David - Oct. 9, 2014, 3:13 a.m.
On 10/08/2014 08:09 PM, Sean Farley wrote:
>
> Pierre-Yves David writes:
>
>> On 10/07/2014 05:44 PM, Sean Farley wrote:
>>>
>>> Augie Fackler writes:
>>>
>>>> On Oct 7, 2014, at 4:12 PM, Sean Farley <sean.michael.farley@gmail.com> wrote:
>>>>
>>>>>>> Yes, of course, but this is derailing the current discussion. We have
>>>>>>> the concept of local revision numbers and this patch is a way to refer
>>>>>>> to that. I would suggest another discussion about the order of
>>>>>>> children().
>>>>>>
>>>>>> This is not to challenge the order of children(X). This is to point out
>>>>>> that children can barely be used alone and therefor having a supershort
>>>>>> version of it is not that useful.
>>>>>
>>>>> I'm surprised you are being this stubborn about it. It is very, very
>>>>> common to have a set of linear changes. It is even still common to be in
>>>>> a situation where you only have a reference to the parent of a
>>>>> changeset.
>>
>> The things I'm fighting againts here, is feature creep. I'm not fan of
>> adding new operator because:
>
> This isn't a new operator. It's extending the use of '^' and doesn't
> force a new character.
>
> At this point, I'm only interested in what mpm has to say about it and
> what direction he wants to go.

Can I get you to look at the rest of the email and acknowledge the other 
points?

Patch

diff --git a/mercurial/revset.py b/mercurial/revset.py
--- a/mercurial/revset.py
+++ b/mercurial/revset.py
@@ -1250,11 +1250,11 @@  def parentspec(repo, subset, x, n):
     ``set^1`` (or ``set^``), ``set^2``
     First or second parent, respectively, of all changesets in set.
     """
     try:
         n = int(n[1])
-        if n not in (0, 1, 2):
+        if n > 2:
             raise ValueError
     except (TypeError, ValueError):
         raise error.ParseError(_("^ expects a number 0, 1, or 2"))
     ps = set()
     cl = repo.changelog
@@ -1265,10 +1265,16 @@  def parentspec(repo, subset, x, n):
             ps.add(cl.parentrevs(r)[0])
         elif n == 2:
             parents = cl.parentrevs(r)
             if len(parents) > 1:
                 ps.add(parents[1])
+        else: # negative number means the nth-child
+            children = cl.children(repo[r].node())
+            idx = -n-1
+            if children and idx < len(children):
+                ps.add(repo[children[idx]].rev())
+
     return subset & ps
 
 def present(repo, subset, x):
     """``present(set)``
     An empty set, if any revision in set isn't found; otherwise,
diff --git a/tests/test-revset.t b/tests/test-revset.t
--- a/tests/test-revset.t
+++ b/tests/test-revset.t
@@ -778,10 +778,18 @@  multiple revspecs
   4
   5
   6
   7
 
+test getting child revs
+
+  $ log 'merge()~3^-1'
+  2
+  $ log 'merge()~3^-2'
+  3
+
+
 test usage in revpair (with "+")
 
 (real pair)
 
   $ hg diff -r 'tip^^' -r 'tip'