[PATCH RFC] show: implement "stack" view

Augie Fackler raf at durin42.com
Sun Jun 18 21:53:30 EDT 2017


On Sat, Jun 17, 2017 at 01:02:49PM -0600, Gregory Szorc wrote:
> # HG changeset patch
> # User Gregory Szorc <gregory.szorc at gmail.com>
> # Date 1497726059 21600
> #      Sat Jun 17 13:00:59 2017 -0600
> # Node ID c9a3d8cdbb925614419216d6e99d9a70f03d926d
> # Parent  9fcb6df413c9ca475e705ecc15df07584dadb0c1
> show: implement "stack" view
>
> People often want to know what they are working on *now*. As part of
> this, they also commonly want to know how that work is related to other
> changesets in the repo so they can perform common actions like rebase,
> histedit, and merge.
>
> `hg show work` made headway into this space. However, it is geared
> towards a complete repo view as opposed to just the current line of
> work. If you have a lot of in-flight work or the repo has many heads,
> the output can be overwhelming. The closest thing Mercurial has to
> "show me the current thing I'm working on" that doesn't require custom
> revsets is `hg qseries`. And this requires MQ, which completely changes
> workflows and repository behavior and has horrible performance on large
> repos. But as sub-optimal as MQ is, it does some things right, such as
> expose a model of the repo that is easy for people to reason about.
> This simplicity is why I think a lot of people prefer to use MQ, despite
> its shortcomings.
>
> One common development workflow is to author a series of linear
> changesets, using bookmarks, branches, anonymous heads, or even topics
> (3rd party extension). I'll call this a "stack."

We don't use the term stack yet in Mercurial, other than (oddly
enough!) the help for MQ. I'm not wholly opposed to coming up with a
noun for this (stack might even be the right choice), but I think it
might be worth doing a survey of the existing terms of art for this in
our features (eg I know patchbomb calls it a series - that might be
the only other place this is explicitly named right now?)

> You periodically
> rewrite history in place (using `hg histedit`) and reparent the stack
> against newer changesets (using `hg rebase`). This workflow can be
> difficult because there is no obvious way to quickly see the current
> "stack" nor its relation to other changesets. Figuring out arguments to
> `hg rebase` can be difficult and may require highlighting and pasting
> multiple changeset nodes to construct a command.
>
> The goal of this commit is to make stack based workflows simpler
> by exposing a view of the current stack and its relationship to
> other releant changesets, notably the parent of the base changeset
> in the stack and newer heads that the stack could be rebased or merged
> into.
>
> Introduced is the `hg show stack` view. Essentially, it finds all
> mutable changesets from the working directory revision in both
> directions, stopping at a merge or branch point. This limits the
> revisions to a DAG linear range.

Does this have some affordance so that other extensions
(remote{names,branches} specifically come to mind) can redefine the
stack boundary? On Mercurial itself just sniffing for draft changes
will show a lot of things I don't care about anymore since they're
pushed upstream. :)

>
> The stack is rendered as a concise list of changesets. Alongside the
> stack is a visualization of the DAG, similar to `hg log -G`.

Assuming this retains the same lack of BC that we're embracing in `hg
show`, I'm happy to land something eagerly and iterate (my nagging
concerns about noun choice aside.)

[... elided entire implementation, which I didn't read yet ...]

> diff --git a/tests/test-show-stack.t b/tests/test-show-stack.t
> new file mode 100644
> --- /dev/null
> +++ b/tests/test-show-stack.t
> @@ -0,0 +1,235 @@
> +  $ cat >> $HGRCPATH << EOF
> +  > [extensions]
> +  > show =
> +  > EOF
> +
> +  $ hg init repo0
> +  $ cd repo0
> +
> +Empty repo / no checkout results in error
> +
> +  $ hg show stack
> +  abort: stack view only available when there is a working directory
> +  [255]
> +
> +Stack displays single draft changeset as root revision
> +
> +  $ echo 0 > foo
> +  $ hg -q commit -A -m 'commit 0'
> +  $ hg show stack
> +    @  9f171 commit 0
> +
> +Stack displays multiple draft changesets
> +
> +  $ echo 1 > foo
> +  $ hg commit -m 'commit 1'
> +  $ echo 2 > foo
> +  $ hg commit -m 'commit 2'
> +  $ echo 3 > foo
> +  $ hg commit -m 'commit 3'
> +  $ echo 4 > foo
> +  $ hg commit -m 'commit 4'
> +  $ hg show stack
> +    @  2737b commit 4
> +    o  d1a69 commit 3
> +    o  128c8 commit 2
> +    o  181cc commit 1
> +    o  9f171 commit 0
> +
> +Public parent of draft base is displayed, separated from stack
> +
> +  $ hg phase --public -r 0
> +  $ hg show stack
> +    @  2737b commit 4
> +    o  d1a69 commit 3
> +    o  128c8 commit 2
> +    o  181cc commit 1
> +   /   (stack base)
> +  o  9f171 commit 0
> +
> +  $ hg phase --public -r 1
> +  $ hg show stack
> +    @  2737b commit 4
> +    o  d1a69 commit 3
> +    o  128c8 commit 2
> +   /   (stack base)
> +  o  181cc commit 1
> +
> +Draft descendants are shown
> +
> +  $ hg -q up 2
> +  $ hg show stack
> +    o  2737b commit 4
> +    o  d1a69 commit 3
> +    @  128c8 commit 2
> +   /   (stack base)
> +  o  181cc commit 1
> +
> +  $ hg -q up 3
> +  $ hg show stack
> +    o  2737b commit 4
> +    @  d1a69 commit 3
> +    o  128c8 commit 2
> +   /   (stack base)
> +  o  181cc commit 1
> +
> +working dir on public changeset should display special message
> +
> +  $ hg -q up 1
> +  $ hg show stack
> +  (empty stack; working directory is a published changeset)
> +
> +Branch point in descendants displayed at top of graph
> +
> +  $ hg -q up 3
> +  $ echo b > foo
> +  $ hg commit -m 'commit 5 (new dag branch)'
> +  created new head
> +  $ hg -q up 2
> +  $ hg show stack
> +   \ /  (multiple children)
> +    |
> +    o  d1a69 commit 3
> +    @  128c8 commit 2
> +   /   (stack base)
> +  o  181cc commit 1
> +
> +  $ cd ..
> +
> +Base is stopped at merges
> +
> +  $ hg init merge-base
> +  $ cd merge-base
> +  $ echo 0 > foo
> +  $ hg -q commit -A -m initial
> +  $ echo h1 > foo
> +  $ hg commit -m 'head 1'
> +  $ hg -q up 0
> +  $ echo h2 > foo
> +  $ hg -q commit -m 'head 2'
> +  $ hg phase --public -r 0:tip
> +  $ hg -q up 1
> +  $ hg merge -t :local 2
> +  0 files updated, 1 files merged, 0 files removed, 0 files unresolved
> +  (branch merge, don't forget to commit)
> +  $ hg commit -m 'merge heads'
> +
> +TODO doesn't yet handle case where wdir is a draft merge
> +
> +  $ hg show stack
> +    @  8ee90 merge heads
> +   /   (stack base)
> +  o  59478 head 1
> +
> +  $ echo d1 > foo
> +  $ hg commit -m 'draft 1'
> +  $ echo d2 > foo
> +  $ hg commit -m 'draft 2'
> +
> +  $ hg show stack
> +    @  430d5 draft 2
> +    o  787b1 draft 1
> +   /   (stack base)
> +  o  8ee90 merge heads
> +
> +  $ cd ..
> +
> +Now move on to stacks when there are more commits after the base branchpoint
> +
> +  $ hg init public-rebase
> +  $ cd public-rebase
> +  $ echo 0 > foo
> +  $ hg -q commit -A -m 'base'
> +  $ hg phase --public -r .
> +  $ echo d1 > foo
> +  $ hg commit -m 'draft 1'
> +  $ echo d2 > foo
> +  $ hg commit -m 'draft 2'
> +  $ hg -q up 0
> +  $ echo 1 > foo
> +  $ hg commit -m 'new 1'
> +  created new head
> +  $ echo 2 > foo
> +  $ hg commit -m 'new 2'
> +  $ hg -q up 2
> +
> +Newer draft heads don't impact output
> +
> +  $ hg show stack
> +    @  eaffc draft 2
> +    o  2b218 draft 1
> +   /   (stack base)
> +  o  b66bb base
> +
> +Newer public heads are rendered
> +
> +  $ hg phase --public -r '::tip'
> +
> +  $ hg show stack
> +    (new heads)
> +
> +    o  baa4b new 2
> +   /    (2 commits ahead)
> +  :
> +  : (current stack)
> +  :
> +  : @  eaffc draft 2
> +  : o  2b218 draft 1
> +  :/   (stack base)
> +  o  b66bb base
> +
> +If rebase is available, we show a hint how to rebase to that head
> +
> +  $ hg --config extensions.rebase= show stack
> +    (new heads)
> +
> +    o  baa4b new 2
> +   /    (2 commits ahead)
> +  :     hg rebase -s 2b218 -d baa4b
> +  :
> +  : (current stack)
> +  :
> +  : @  eaffc draft 2
> +  : o  2b218 draft 1
> +  :/   (stack base)
> +  o  b66bb base
> +
> +Similar tests but for multiple heads
> +
> +  $ hg -q up 0
> +  $ echo h2 > foo
> +  $ hg -q commit -m 'new head 2'
> +  $ hg phase --public -r .
> +  $ hg -q up 2
> +
> +  $ hg show stack
> +    (new heads)
> +
> +    o  baa4b new 2
> +   /    (2 commits ahead)
> +  : o  9a848 new head 2
> +  :/    (1 commits ahead)
> +  :
> +  : (current stack)
> +  :
> +  : @  eaffc draft 2
> +  : o  2b218 draft 1
> +  :/   (stack base)
> +  o  b66bb base
> +
> +  $ hg --config extensions.rebase= show stack
> +    (new heads)
> +
> +    o  baa4b new 2
> +   /    (2 commits ahead)
> +  :     hg rebase -s 2b218 -d baa4b
> +  : o  9a848 new head 2
> +  :/    (1 commits ahead)
> +  :     hg rebase -s 2b218 -d 9a848
> +  :
> +  : (current stack)
> +  :
> +  : @  eaffc draft 2
> +  : o  2b218 draft 1
> +  :/   (stack base)
> +  o  b66bb base
> _______________________________________________
> Mercurial-devel mailing list
> Mercurial-devel at mercurial-scm.org
> https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel


More information about the Mercurial-devel mailing list