Patchwork [4,of,4] revset: introduce a 'foo#stack[n]' subscript relation to access stack revisions

login
register
mail settings
Submitter Anton Shestakov
Date Sept. 23, 2019, 3:39 a.m.
Message ID <ab8f097abacb8ce0f9ce.1569209992@df1>
Download mbox | patch
Permalink /patch/41733/
State Accepted
Headers show

Comments

Anton Shestakov - Sept. 23, 2019, 3:39 a.m.
# HG changeset patch
# User Anton Shestakov <av6@dwimlabs.net>
# Date 1569139969 -25200
#      Sun Sep 22 15:12:49 2019 +0700
# Node ID ab8f097abacb8ce0f9cea2bce0924bb2fd3261a2
# Parent  07af98a1e730c1ffa6911c9ab2cdcc06d4ffe52d
# EXP-Topic stack-object
revset: introduce a 'foo#stack[n]' subscript relation to access stack revisions

The idea behind making n = 0 cases special is that stack base should be
accessible, but only when users ask for it explicitly.
Yuya Nishihara - Sept. 23, 2019, 12:58 p.m.
On Mon, 23 Sep 2019 10:39:52 +0700, Anton Shestakov wrote:
> # HG changeset patch
> # User Anton Shestakov <av6@dwimlabs.net>
> # Date 1569139969 -25200
> #      Sun Sep 22 15:12:49 2019 +0700
> # Node ID ab8f097abacb8ce0f9cea2bce0924bb2fd3261a2
> # Parent  07af98a1e730c1ffa6911c9ab2cdcc06d4ffe52d
> # EXP-Topic stack-object
> revset: introduce a 'foo#stack[n]' subscript relation to access stack revisions
> 
> The idea behind making n = 0 cases special is that stack base should be
> accessible, but only when users ask for it explicitly.

> +def stackrel(repo, subset, x, rel, z, order):
> +    a, b = getintrange(z,
> +                       _('relation subscript must be an integer or a range'),
> +                       _('relation subscript bounds must be integers'),
> +                       deffirst=None,
> +                       deflast=None)
> +
> +    s = getset(repo, fullreposet(repo), x)
> +    if not s:
> +        return baseset()
> +
> +    def getrange(st, a, b):
> +        start = 1 if a is None else a
> +        end = len(st.indexedrevs) if b is None else b + 1

I feel it's weird that stack[:] doesn't include stack[0].
Pierre-Yves David - Sept. 24, 2019, 7:16 p.m.
On 9/23/19 2:58 PM, Yuya Nishihara wrote:
> On Mon, 23 Sep 2019 10:39:52 +0700, Anton Shestakov wrote:
>> # HG changeset patch
>> # User Anton Shestakov <av6@dwimlabs.net>
>> # Date 1569139969 -25200
>> #      Sun Sep 22 15:12:49 2019 +0700
>> # Node ID ab8f097abacb8ce0f9cea2bce0924bb2fd3261a2
>> # Parent  07af98a1e730c1ffa6911c9ab2cdcc06d4ffe52d
>> # EXP-Topic stack-object
>> revset: introduce a 'foo#stack[n]' subscript relation to access stack revisions
>>
>> The idea behind making n = 0 cases special is that stack base should be
>> accessible, but only when users ask for it explicitly.
> 
>> +def stackrel(repo, subset, x, rel, z, order):
>> +    a, b = getintrange(z,
>> +                       _('relation subscript must be an integer or a range'),
>> +                       _('relation subscript bounds must be integers'),
>> +                       deffirst=None,
>> +                       deflast=None)
>> +
>> +    s = getset(repo, fullreposet(repo), x)
>> +    if not s:
>> +        return baseset()
>> +
>> +    def getrange(st, a, b):
>> +        start = 1 if a is None else a
>> +        end = len(st.indexedrevs) if b is None else b + 1
> 
> I feel it's weird that stack[:] doesn't include stack[0].

[0] is the "root" of the stack, but not part of it. It is handy to have 
it around when one want to insert and initial commit or test thing 
without any of the stack changes, however it not part of the stack.

For example if you want to update all changesets in the stack you could 
do `hg metaedit --rev '.#stack[:]' --user foobar`. You don't want to 
select s0 it might even be a public changesets.

Cheers,
Yuya Nishihara - Sept. 24, 2019, 11:25 p.m.
On Tue, 24 Sep 2019 21:16:53 +0200, Pierre-Yves David wrote:
> On 9/23/19 2:58 PM, Yuya Nishihara wrote:
> > On Mon, 23 Sep 2019 10:39:52 +0700, Anton Shestakov wrote:
> >> # HG changeset patch
> >> # User Anton Shestakov <av6@dwimlabs.net>
> >> # Date 1569139969 -25200
> >> #      Sun Sep 22 15:12:49 2019 +0700
> >> # Node ID ab8f097abacb8ce0f9cea2bce0924bb2fd3261a2
> >> # Parent  07af98a1e730c1ffa6911c9ab2cdcc06d4ffe52d
> >> # EXP-Topic stack-object
> >> revset: introduce a 'foo#stack[n]' subscript relation to access stack revisions
> >>
> >> The idea behind making n = 0 cases special is that stack base should be
> >> accessible, but only when users ask for it explicitly.
> > 
> >> +def stackrel(repo, subset, x, rel, z, order):
> >> +    a, b = getintrange(z,
> >> +                       _('relation subscript must be an integer or a range'),
> >> +                       _('relation subscript bounds must be integers'),
> >> +                       deffirst=None,
> >> +                       deflast=None)
> >> +
> >> +    s = getset(repo, fullreposet(repo), x)
> >> +    if not s:
> >> +        return baseset()
> >> +
> >> +    def getrange(st, a, b):
> >> +        start = 1 if a is None else a
> >> +        end = len(st.indexedrevs) if b is None else b + 1
> > 
> > I feel it's weird that stack[:] doesn't include stack[0].
> 
> [0] is the "root" of the stack, but not part of it. It is handy to have 
> it around when one want to insert and initial commit or test thing 
> without any of the stack changes, however it not part of the stack.
> 
> For example if you want to update all changesets in the stack you could 
> do `hg metaedit --rev '.#stack[:]' --user foobar`. You don't want to 
> select s0 it might even be a public changesets.

I understand that. My point is it may be confusing if foo[:] includes #foo[0],
but #bar[:] doesn't.
Pierre-Yves David - Sept. 25, 2019, 12:48 a.m.
On 9/25/19 1:25 AM, Yuya Nishihara wrote:
> On Tue, 24 Sep 2019 21:16:53 +0200, Pierre-Yves David wrote:
>> On 9/23/19 2:58 PM, Yuya Nishihara wrote:
>>> On Mon, 23 Sep 2019 10:39:52 +0700, Anton Shestakov wrote:
>>>> # HG changeset patch
>>>> # User Anton Shestakov <av6@dwimlabs.net>
>>>> # Date 1569139969 -25200
>>>> #      Sun Sep 22 15:12:49 2019 +0700
>>>> # Node ID ab8f097abacb8ce0f9cea2bce0924bb2fd3261a2
>>>> # Parent  07af98a1e730c1ffa6911c9ab2cdcc06d4ffe52d
>>>> # EXP-Topic stack-object
>>>> revset: introduce a 'foo#stack[n]' subscript relation to access stack revisions
>>>>
>>>> The idea behind making n = 0 cases special is that stack base should be
>>>> accessible, but only when users ask for it explicitly.
>>>
>>>> +def stackrel(repo, subset, x, rel, z, order):
>>>> +    a, b = getintrange(z,
>>>> +                       _('relation subscript must be an integer or a range'),
>>>> +                       _('relation subscript bounds must be integers'),
>>>> +                       deffirst=None,
>>>> +                       deflast=None)
>>>> +
>>>> +    s = getset(repo, fullreposet(repo), x)
>>>> +    if not s:
>>>> +        return baseset()
>>>> +
>>>> +    def getrange(st, a, b):
>>>> +        start = 1 if a is None else a
>>>> +        end = len(st.indexedrevs) if b is None else b + 1
>>>
>>> I feel it's weird that stack[:] doesn't include stack[0].
>>
>> [0] is the "root" of the stack, but not part of it. It is handy to have
>> it around when one want to insert and initial commit or test thing
>> without any of the stack changes, however it not part of the stack.
>>
>> For example if you want to update all changesets in the stack you could
>> do `hg metaedit --rev '.#stack[:]' --user foobar`. You don't want to
>> select s0 it might even be a public changesets.
> 
> I understand that. My point is it may be confusing if foo[:] includes #foo[0],
> but #bar[:] doesn't.

I suspect we already have a "every namespace behave differently 
situation". The "generation" namespace is not table indexing ".#g[0]" is 
".", and ".#g[X]' might return more than on revision.

Alternatively, maybe stacks needs a different syntax ?

--
Pierre-Yves David
Anton Shestakov - Sept. 25, 2019, 10:20 a.m.
On Wed, 25 Sep 2019 02:48:09 +0200
Pierre-Yves David <pierre-yves.david@ens-lyon.org> wrote:

> On 9/25/19 1:25 AM, Yuya Nishihara wrote:
> > On Tue, 24 Sep 2019 21:16:53 +0200, Pierre-Yves David wrote:  
> >> On 9/23/19 2:58 PM, Yuya Nishihara wrote:  
> >>> On Mon, 23 Sep 2019 10:39:52 +0700, Anton Shestakov wrote:  
> >>>> # HG changeset patch
> >>>> # User Anton Shestakov <av6@dwimlabs.net>
> >>>> # Date 1569139969 -25200
> >>>> #      Sun Sep 22 15:12:49 2019 +0700
> >>>> # Node ID ab8f097abacb8ce0f9cea2bce0924bb2fd3261a2
> >>>> # Parent  07af98a1e730c1ffa6911c9ab2cdcc06d4ffe52d
> >>>> # EXP-Topic stack-object
> >>>> revset: introduce a 'foo#stack[n]' subscript relation to access stack revisions
> >>>>
> >>>> The idea behind making n = 0 cases special is that stack base should be
> >>>> accessible, but only when users ask for it explicitly.  
> >>>  
> >>>> +def stackrel(repo, subset, x, rel, z, order):
> >>>> +    a, b = getintrange(z,
> >>>> +                       _('relation subscript must be an integer or a range'),
> >>>> +                       _('relation subscript bounds must be integers'),
> >>>> +                       deffirst=None,
> >>>> +                       deflast=None)
> >>>> +
> >>>> +    s = getset(repo, fullreposet(repo), x)
> >>>> +    if not s:
> >>>> +        return baseset()
> >>>> +
> >>>> +    def getrange(st, a, b):
> >>>> +        start = 1 if a is None else a
> >>>> +        end = len(st.indexedrevs) if b is None else b + 1  
> >>>
> >>> I feel it's weird that stack[:] doesn't include stack[0].  
> >>
> >> [0] is the "root" of the stack, but not part of it. It is handy to have
> >> it around when one want to insert and initial commit or test thing
> >> without any of the stack changes, however it not part of the stack.
> >>
> >> For example if you want to update all changesets in the stack you could
> >> do `hg metaedit --rev '.#stack[:]' --user foobar`. You don't want to
> >> select s0 it might even be a public changesets.  
> > 
> > I understand that. My point is it may be confusing if foo[:] includes #foo[0],
> > but #bar[:] doesn't.  
> 
> I suspect we already have a "every namespace behave differently 
> situation". The "generation" namespace is not table indexing ".#g[0]" is 
> ".", and ".#g[X]' might return more than on revision.

Yeah, the problem with handling [0] in this special way is usability.
We do want to access stack base sometimes, but it's also not a part of a
stack. So we obviously can't leave it to users to just write a revset to
pick stack base, but it's also cumbersome to write "foo#s[:] - foo#s[0]"
every time you want to pick the whole stack. Maybe removing subscript
would make it more special (and somewhat less confusing), like
"foo#stack"? That's my only idea so far, and I'm not a fan of it.

> Alternatively, maybe stacks needs a different syntax ?

While we decide that, I've pushed a V2 of this series, it doesn't
include #stack[] (i.e. just patches 2 and 3 of the V1 with feedback
addressed). It's not much, but it will allow me to start making stack
implementation in topic extension use bits of stack in core.
Yuya Nishihara - Sept. 25, 2019, 12:04 p.m.
On Wed, 25 Sep 2019 18:20:11 +0800, Anton Shestakov wrote:
> On Wed, 25 Sep 2019 02:48:09 +0200
> Pierre-Yves David <pierre-yves.david@ens-lyon.org> wrote:
> > On 9/25/19 1:25 AM, Yuya Nishihara wrote:
> > > On Tue, 24 Sep 2019 21:16:53 +0200, Pierre-Yves David wrote:  
> > >> On 9/23/19 2:58 PM, Yuya Nishihara wrote:  
> > >>> On Mon, 23 Sep 2019 10:39:52 +0700, Anton Shestakov wrote:  
> > >>>> # HG changeset patch
> > >>>> # User Anton Shestakov <av6@dwimlabs.net>
> > >>>> # Date 1569139969 -25200
> > >>>> #      Sun Sep 22 15:12:49 2019 +0700
> > >>>> # Node ID ab8f097abacb8ce0f9cea2bce0924bb2fd3261a2
> > >>>> # Parent  07af98a1e730c1ffa6911c9ab2cdcc06d4ffe52d
> > >>>> # EXP-Topic stack-object
> > >>>> revset: introduce a 'foo#stack[n]' subscript relation to access stack revisions
> > >>>>
> > >>>> The idea behind making n = 0 cases special is that stack base should be
> > >>>> accessible, but only when users ask for it explicitly.  
> > >>>  
> > >>>> +def stackrel(repo, subset, x, rel, z, order):
> > >>>> +    a, b = getintrange(z,
> > >>>> +                       _('relation subscript must be an integer or a range'),
> > >>>> +                       _('relation subscript bounds must be integers'),
> > >>>> +                       deffirst=None,
> > >>>> +                       deflast=None)
> > >>>> +
> > >>>> +    s = getset(repo, fullreposet(repo), x)
> > >>>> +    if not s:
> > >>>> +        return baseset()
> > >>>> +
> > >>>> +    def getrange(st, a, b):
> > >>>> +        start = 1 if a is None else a
> > >>>> +        end = len(st.indexedrevs) if b is None else b + 1  
> > >>>
> > >>> I feel it's weird that stack[:] doesn't include stack[0].  
> > >>
> > >> [0] is the "root" of the stack, but not part of it. It is handy to have
> > >> it around when one want to insert and initial commit or test thing
> > >> without any of the stack changes, however it not part of the stack.
> > >>
> > >> For example if you want to update all changesets in the stack you could
> > >> do `hg metaedit --rev '.#stack[:]' --user foobar`. You don't want to
> > >> select s0 it might even be a public changesets.  
> > > 
> > > I understand that. My point is it may be confusing if foo[:] includes #foo[0],
> > > but #bar[:] doesn't.  
> > 
> > I suspect we already have a "every namespace behave differently 
> > situation". The "generation" namespace is not table indexing ".#g[0]" is 
> > ".", and ".#g[X]' might return more than on revision.

Yep, but I feel x[:] should return everything in 'x' because the range
operator works in that way.

> Yeah, the problem with handling [0] in this special way is usability.
> We do want to access stack base sometimes, but it's also not a part of a
> stack. So we obviously can't leave it to users to just write a revset to
> pick stack base, but it's also cumbersome to write "foo#s[:] - foo#s[0]"
> every time you want to pick the whole stack.

Just 'foo#s[1:]'?

> Maybe removing subscript
> would make it more special (and somewhat less confusing), like
> "foo#stack"? That's my only idea so far, and I'm not a fan of it.

Another (somewhat weird) idea. foo#stack[base] to populate the base revision.
The 'base' symbol is something like 'null' in plain revsets. Say, it's the -1
index, but -$integer is handled as a negative array indexing, so only the 'base'
symbol can allow us to access the stack[-1] value.
Pierre-Yves David - Sept. 27, 2019, 10:13 a.m.
On 9/25/19 2:04 PM, Yuya Nishihara wrote:
> On Wed, 25 Sep 2019 18:20:11 +0800, Anton Shestakov wrote:
>> On Wed, 25 Sep 2019 02:48:09 +0200
>> Pierre-Yves David <pierre-yves.david@ens-lyon.org> wrote:
>>> On 9/25/19 1:25 AM, Yuya Nishihara wrote:
>>>> On Tue, 24 Sep 2019 21:16:53 +0200, Pierre-Yves David wrote:
>>>>> On 9/23/19 2:58 PM, Yuya Nishihara wrote:
>>>>>> On Mon, 23 Sep 2019 10:39:52 +0700, Anton Shestakov wrote:
>>>>>>> # HG changeset patch
>>>>>>> # User Anton Shestakov <av6@dwimlabs.net>
>>>>>>> # Date 1569139969 -25200
>>>>>>> #      Sun Sep 22 15:12:49 2019 +0700
>>>>>>> # Node ID ab8f097abacb8ce0f9cea2bce0924bb2fd3261a2
>>>>>>> # Parent  07af98a1e730c1ffa6911c9ab2cdcc06d4ffe52d
>>>>>>> # EXP-Topic stack-object
>>>>>>> revset: introduce a 'foo#stack[n]' subscript relation to access stack revisions
>>>>>>>
>>>>>>> The idea behind making n = 0 cases special is that stack base should be
>>>>>>> accessible, but only when users ask for it explicitly.
>>>>>>   
>>>>>>> +def stackrel(repo, subset, x, rel, z, order):
>>>>>>> +    a, b = getintrange(z,
>>>>>>> +                       _('relation subscript must be an integer or a range'),
>>>>>>> +                       _('relation subscript bounds must be integers'),
>>>>>>> +                       deffirst=None,
>>>>>>> +                       deflast=None)
>>>>>>> +
>>>>>>> +    s = getset(repo, fullreposet(repo), x)
>>>>>>> +    if not s:
>>>>>>> +        return baseset()
>>>>>>> +
>>>>>>> +    def getrange(st, a, b):
>>>>>>> +        start = 1 if a is None else a
>>>>>>> +        end = len(st.indexedrevs) if b is None else b + 1
>>>>>>
>>>>>> I feel it's weird that stack[:] doesn't include stack[0].
>>>>>
>>>>> [0] is the "root" of the stack, but not part of it. It is handy to have
>>>>> it around when one want to insert and initial commit or test thing
>>>>> without any of the stack changes, however it not part of the stack.
>>>>>
>>>>> For example if you want to update all changesets in the stack you could
>>>>> do `hg metaedit --rev '.#stack[:]' --user foobar`. You don't want to
>>>>> select s0 it might even be a public changesets.
>>>>
>>>> I understand that. My point is it may be confusing if foo[:] includes #foo[0],
>>>> but #bar[:] doesn't.
>>>
>>> I suspect we already have a "every namespace behave differently
>>> situation". The "generation" namespace is not table indexing ".#g[0]" is
>>> ".", and ".#g[X]' might return more than on revision.
> 
> Yep, but I feel x[:] should return everything in 'x' because the range
> operator works in that way.
> 
>> Yeah, the problem with handling [0] in this special way is usability.
>> We do want to access stack base sometimes, but it's also not a part of a
>> stack. So we obviously can't leave it to users to just write a revset to
>> pick stack base, but it's also cumbersome to write "foo#s[:] - foo#s[0]"
>> every time you want to pick the whole stack.
> 
> Just 'foo#s[1:]'?
> 
>> Maybe removing subscript
>> would make it more special (and somewhat less confusing), like
>> "foo#stack"? That's my only idea so far, and I'm not a fan of it.
> 
> Another (somewhat weird) idea. foo#stack[base] to populate the base revision.
> The 'base' symbol is something like 'null' in plain revsets. Say, it's the -1
> index, but -$integer is handled as a negative array indexing, so only the 'base'
> symbol can allow us to access the stack[-1] value.

That would work. the "0" value is special, so we can use special symbol. 
It could also open the door to express base for other roots (when the 
stack is not linear (yet)).

That said, I feel it is important to keep stack index starting at 1 (so 
no using 0 at all). Most UI we already have around stack/series (eg: 
patchbomb) start indexing to #1)
Pierre-Yves David - Nov. 5, 2019, 4:42 p.m.
Yuya and I talked about it at the sprint. The conclusion that that both 
the `r#stack` and `r#stack[base]` approach are valid. We are leaning 
toward using `r#stack`.

Anton, can you move in that direction ?

On 9/27/19 12:13 PM, Pierre-Yves David wrote:
> 
> 
> On 9/25/19 2:04 PM, Yuya Nishihara wrote:
>> On Wed, 25 Sep 2019 18:20:11 +0800, Anton Shestakov wrote:
>>> On Wed, 25 Sep 2019 02:48:09 +0200
>>> Pierre-Yves David <pierre-yves.david@ens-lyon.org> wrote:
>>>> On 9/25/19 1:25 AM, Yuya Nishihara wrote:
>>>>> On Tue, 24 Sep 2019 21:16:53 +0200, Pierre-Yves David wrote:
>>>>>> On 9/23/19 2:58 PM, Yuya Nishihara wrote:
>>>>>>> On Mon, 23 Sep 2019 10:39:52 +0700, Anton Shestakov wrote:
>>>>>>>> # HG changeset patch
>>>>>>>> # User Anton Shestakov <av6@dwimlabs.net>
>>>>>>>> # Date 1569139969 -25200
>>>>>>>> #      Sun Sep 22 15:12:49 2019 +0700
>>>>>>>> # Node ID ab8f097abacb8ce0f9cea2bce0924bb2fd3261a2
>>>>>>>> # Parent  07af98a1e730c1ffa6911c9ab2cdcc06d4ffe52d
>>>>>>>> # EXP-Topic stack-object
>>>>>>>> revset: introduce a 'foo#stack[n]' subscript relation to access 
>>>>>>>> stack revisions
>>>>>>>>
>>>>>>>> The idea behind making n = 0 cases special is that stack base 
>>>>>>>> should be
>>>>>>>> accessible, but only when users ask for it explicitly.
>>>>>>>> +def stackrel(repo, subset, x, rel, z, order):
>>>>>>>> +    a, b = getintrange(z,
>>>>>>>> +                       _('relation subscript must be an integer 
>>>>>>>> or a range'),
>>>>>>>> +                       _('relation subscript bounds must be 
>>>>>>>> integers'),
>>>>>>>> +                       deffirst=None,
>>>>>>>> +                       deflast=None)
>>>>>>>> +
>>>>>>>> +    s = getset(repo, fullreposet(repo), x)
>>>>>>>> +    if not s:
>>>>>>>> +        return baseset()
>>>>>>>> +
>>>>>>>> +    def getrange(st, a, b):
>>>>>>>> +        start = 1 if a is None else a
>>>>>>>> +        end = len(st.indexedrevs) if b is None else b + 1
>>>>>>>
>>>>>>> I feel it's weird that stack[:] doesn't include stack[0].
>>>>>>
>>>>>> [0] is the "root" of the stack, but not part of it. It is handy to 
>>>>>> have
>>>>>> it around when one want to insert and initial commit or test thing
>>>>>> without any of the stack changes, however it not part of the stack.
>>>>>>
>>>>>> For example if you want to update all changesets in the stack you 
>>>>>> could
>>>>>> do `hg metaedit --rev '.#stack[:]' --user foobar`. You don't want to
>>>>>> select s0 it might even be a public changesets.
>>>>>
>>>>> I understand that. My point is it may be confusing if foo[:] 
>>>>> includes #foo[0],
>>>>> but #bar[:] doesn't.
>>>>
>>>> I suspect we already have a "every namespace behave differently
>>>> situation". The "generation" namespace is not table indexing 
>>>> ".#g[0]" is
>>>> ".", and ".#g[X]' might return more than on revision.
>>
>> Yep, but I feel x[:] should return everything in 'x' because the range
>> operator works in that way.
>>
>>> Yeah, the problem with handling [0] in this special way is usability.
>>> We do want to access stack base sometimes, but it's also not a part of a
>>> stack. So we obviously can't leave it to users to just write a revset to
>>> pick stack base, but it's also cumbersome to write "foo#s[:] - foo#s[0]"
>>> every time you want to pick the whole stack.
>>
>> Just 'foo#s[1:]'?
>>
>>> Maybe removing subscript
>>> would make it more special (and somewhat less confusing), like
>>> "foo#stack"? That's my only idea so far, and I'm not a fan of it.
>>
>> Another (somewhat weird) idea. foo#stack[base] to populate the base 
>> revision.
>> The 'base' symbol is something like 'null' in plain revsets. Say, it's 
>> the -1
>> index, but -$integer is handled as a negative array indexing, so only 
>> the 'base'
>> symbol can allow us to access the stack[-1] value.
> 
> That would work. the "0" value is special, so we can use special symbol. 
> It could also open the door to express base for other roots (when the 
> stack is not linear (yet)).
> 
> That said, I feel it is important to keep stack index starting at 1 (so 
> no using 0 at all). Most UI we already have around stack/series (eg: 
> patchbomb) start indexing to #1)
> 
>

Patch

diff --git a/mercurial/revset.py b/mercurial/revset.py
--- a/mercurial/revset.py
+++ b/mercurial/revset.py
@@ -284,6 +284,43 @@  def generationsrel(repo, subset, x, rel,
 
     return subset & s
 
+def stackrel(repo, subset, x, rel, z, order):
+    a, b = getintrange(z,
+                       _('relation subscript must be an integer or a range'),
+                       _('relation subscript bounds must be integers'),
+                       deffirst=None,
+                       deflast=None)
+
+    s = getset(repo, fullreposet(repo), x)
+    if not s:
+        return baseset()
+
+    def getrange(st, a, b):
+        start = 1 if a is None else a
+        end = len(st.indexedrevs) if b is None else b + 1
+        return range(start, end)
+
+    revs = []
+    for r in s:
+        st = stackmod.stack(repo, rev=r)
+        for n in getrange(st, a, b):
+            if abs(n) >= len(st.indexedrevs):
+                # also means stack base is not accessible with n < 0, which
+                # is by design
+                continue
+            if n == 0 and b != 0 and a != 0:
+                # quirk: we don't want stack base unless specifically asked
+                # for it (at least one of the indices is 0)
+                continue
+            rev = st.indexedrevs[n]
+            if rev == node.nullrev and n == 0:
+                # we also don't want stack base if it's nullrev
+                continue
+            if rev not in revs:
+                revs.append(rev)
+
+    return subset & baseset(revs)
+
 def relsubscriptset(repo, subset, x, y, z, order):
     # this is pretty basic implementation of 'x#y[z]' operator, still
     # experimental so undocumented. see the wiki for further ideas.
@@ -2345,6 +2382,8 @@  methods = {
 subscriptrelations = {
     "g": generationsrel,
     "generations": generationsrel,
+    "s": stackrel,
+    "stack": stackrel,
 }
 
 def lookupfn(repo):
diff --git a/tests/test-stack.t b/tests/test-stack.t
--- a/tests/test-stack.t
+++ b/tests/test-stack.t
@@ -69,7 +69,7 @@  Check that stack doesn't include public 
 Simple test
 -----------
 
-'stack()' list all changeset in the branch
+'stack()' revset lists all changeset in the branch
 
   $ hg branch
   foo
@@ -84,6 +84,48 @@  Simple test
   |
   ~
 
+'#stack[]' (as well as '#s[]') revset relation works
+
+  $ hg log -r 'foo#stack[0]'
+  1 other public c_b
+  $ hg log -r 'foo#stack[1]'
+  2 foo draft c_c
+  $ hg log -r 'foo#stack[2]'
+  3 foo draft c_d
+  $ hg log -r 'foo#stack[-1]'
+  5 foo draft c_f
+  $ hg log -r 'foo#stack[-2]'
+  4 foo draft c_e
+
+  $ hg log -r 'foo#s[0:0]'
+  1 other public c_b
+  $ hg log -r 'foo#s[:]'
+  2 foo draft c_c
+  3 foo draft c_d
+  4 foo draft c_e
+  5 foo draft c_f
+  $ hg log -r 'foo#s[:3]'
+  2 foo draft c_c
+  3 foo draft c_d
+  4 foo draft c_e
+  $ hg log -r 'foo#s[3:]'
+  4 foo draft c_e
+  5 foo draft c_f
+  $ hg log -r 'foo#s[0:1]'
+  1 other public c_b
+  2 foo draft c_c
+  $ hg log -r 'foo#s[-1:0]'
+  1 other public c_b
+  5 foo draft c_f
+  $ hg log -r 'foo#s[-4:4]'
+  2 foo draft c_c
+  3 foo draft c_d
+  4 foo draft c_e
+  5 foo draft c_f
+
+  $ hg log -r 'all()#s[9999]'
+  $ hg log -r 'all()#s[-9999]'
+
 Case with some of the branch unstable
 ------------------------------------