Patchwork [1,of,9,PoC] mq2: proof of concept for improving mq - starting point and tests

login
register
mail settings
Submitter Mads Kiilerich
Date Aug. 29, 2014, 8:59 a.m.
Message ID <e426af93a42f11fb1877.1409302758@localhost.localdomain>
Download mbox | patch
Permalink /patch/5610/
State Deferred
Headers show

Comments

Mads Kiilerich - Aug. 29, 2014, 8:59 a.m.
# HG changeset patch
# User Mads Kiilerich <madski@unity3d.com>
# Date 1409301979 -7200
#      Fri Aug 29 10:46:19 2014 +0200
# Node ID e426af93a42f11fb187793904b743b5b4341af6e
# Parent  926bc0d3b595caf37c5d70833a347eb43285de2f
mq2: proof of concept for improving mq - starting point and tests

These days it is trendy to bash mq and try to kill it. Instead, let's create
something better and let the winner win and let the loser go somewhere else and
die a quiet death.

Let's try to evolve and improve mq and give people the choice of using the tool
they prefer.

I kind of see mq as a tool for efficiently locally working on a number of
patches, while I more more see evolve as a tool modifying history under my
feet.

Problems/design goals to address:
 * Improve mq and try to remain backwards compatible.
 * Use merge and merge tools instead of patches and .rej files.
 * Better meta history without using tracked queues.
 * Consider evolve and the mindset that comes with it, be compatible or
   bridge the gab to it.

The basic ideas are:
 * Keep "stripped" (especially qpopped) changesets around instead of stripping
   them.
 * If possible, use these changesets for grafting when "qpushing".
 * Update patch files with reference to the last changeset it was qpushed as.
 * Get "rid" of qpopped changesets when they no longer are referenced -
   currently by using obsolete, could also strip them at that point.

Current issues:
 * Needs real testing.
 * Needs better error handling.
 * Better handling of the 'qpush failed with .rej files' scenario.
 ** It will now use merge - which is nice but requires test updates.
 ** How to represent that state (use nullid or a commit of something random?).
 ** How to continue from that state (qrefresh should pick it up).
 * Collision with already obsoleted changesets. Is that because obsolete markers
   are a bad solution to the problem ... or solving the wrong problem?
 * Some .unfiltered() has been added in various places. Is it just because
   this filtered hack is a *** hack or is there something wrong?

These changes are done incrementally in code, causing some test churn that mostly
ends up going away again. That is mostly because we start keeping "stripped"
changesets before we start hiding them.
Matt Mackall - Aug. 30, 2014, 12:50 p.m.
On Fri, 2014-08-29 at 10:59 +0200, Mads Kiilerich wrote:
> # HG changeset patch
> # User Mads Kiilerich <madski@unity3d.com>
> # Date 1409301979 -7200
> #      Fri Aug 29 10:46:19 2014 +0200
> # Node ID e426af93a42f11fb187793904b743b5b4341af6e
> # Parent  926bc0d3b595caf37c5d70833a347eb43285de2f
> mq2: proof of concept for improving mq - starting point and tests

I guess. But I think we want it to be opt-in. That means that if people
don't already have obsolete markers and don't have evolve enabled, they
continue to get the old, hard history-rewriting.
Gregory Szorc - Sept. 9, 2014, 6:17 p.m.
As much as I personally dislike many aspects of mq, there are people 
(especially at Mozilla) that cling to it and this patch series offers 
some ideas that would go a long way towards making the mq workflow more 
compatible with Mozilla's wants.

Namely:

1) Our new code review tool is obsolescence aware. When creating reviews 
of commits that have obsolescence data, the workflow is vastly simpler 
since we can get the commit mapping from history rewriting from 
obsolescence. Maintaining this from mq is slightly more difficult since 
it requires storing patch names. Patch names are neither versioned nor 
consistent, so things break down when people collaborate on reviews. 
(We're trying to avoid writing heuristic-based commit mapping for as 
long as possible.)

2) Merge handling. One of Mozilla's top complaints about Mercurial is 
merge handling. I suspect most of the complainers are people using mq 
and not getting the superior merge tool experience. I'd love to see mq 
play nicer with merging and not produce .rej files.

I also think that bridging the gap between evolve and mq is a worthy 
goal. Some people just like thinking about mq-style heads as separate 
from the "core" repo data. It seems to be easier for them to grok.

I feel that a lot of people at Mozilla will cling to mq despite advances 
in bookmarks workflows, etc. I would prefer to support these users with 
mq++ over mq-current. I therefore support this patch series.

On 8/29/14 1:59 AM, Mads Kiilerich wrote:
> # HG changeset patch
> # User Mads Kiilerich <madski@unity3d.com>
> # Date 1409301979 -7200
> #      Fri Aug 29 10:46:19 2014 +0200
> # Node ID e426af93a42f11fb187793904b743b5b4341af6e
> # Parent  926bc0d3b595caf37c5d70833a347eb43285de2f
> mq2: proof of concept for improving mq - starting point and tests
>
> These days it is trendy to bash mq and try to kill it. Instead, let's create
> something better and let the winner win and let the loser go somewhere else and
> die a quiet death.
>
> Let's try to evolve and improve mq and give people the choice of using the tool
> they prefer.
>
> I kind of see mq as a tool for efficiently locally working on a number of
> patches, while I more more see evolve as a tool modifying history under my
> feet.
>
> Problems/design goals to address:
>   * Improve mq and try to remain backwards compatible.
>   * Use merge and merge tools instead of patches and .rej files.
>   * Better meta history without using tracked queues.
>   * Consider evolve and the mindset that comes with it, be compatible or
>     bridge the gab to it.
>
> The basic ideas are:
>   * Keep "stripped" (especially qpopped) changesets around instead of stripping
>     them.
>   * If possible, use these changesets for grafting when "qpushing".
>   * Update patch files with reference to the last changeset it was qpushed as.
>   * Get "rid" of qpopped changesets when they no longer are referenced -
>     currently by using obsolete, could also strip them at that point.
>
> Current issues:
>   * Needs real testing.
>   * Needs better error handling.
>   * Better handling of the 'qpush failed with .rej files' scenario.
>   ** It will now use merge - which is nice but requires test updates.
>   ** How to represent that state (use nullid or a commit of something random?).
>   ** How to continue from that state (qrefresh should pick it up).
>   * Collision with already obsoleted changesets. Is that because obsolete markers
>     are a bad solution to the problem ... or solving the wrong problem?
>   * Some .unfiltered() has been added in various places. Is it just because
>     this filtered hack is a *** hack or is there something wrong?
>
> These changes are done incrementally in code, causing some test churn that mostly
> ends up going away again. That is mostly because we start keeping "stripped"
> changesets before we start hiding them.
>
> diff --git a/tests/test-mq2.t b/tests/test-mq2.t
> new file mode 100644
> --- /dev/null
> +++ b/tests/test-mq2.t
> @@ -0,0 +1,153 @@
> +  $ checkundo()
> +  > {
> +  >     if [ -f .hg/store/undo ]; then
> +  >     echo ".hg/store/undo still exists after $1"
> +  >     fi
> +  > }
> +
> +  $ echo "[extensions]" >> $HGRCPATH
> +  $ echo "mq=" >> $HGRCPATH
> +
> +  $ echo "[mq]" >> $HGRCPATH
> +  $ echo "plain=false" >> $HGRCPATH
> +
> +  $ echo "[diff]" >> $HGRCPATH
> +  $ echo "git=true" >> $HGRCPATH
> +
> +  $ hg init a
> +  $ cd a
> +  $ echo a > a
> +  $ hg ci -Ama
> +  adding a
> +
> +  $ hg qnew b -d '314159265 0'
> +  $ echo b > b
> +  $ hg add b
> +  $ cat .hg/patches/b
> +  # HG changeset patch
> +  # Parent cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b
> +  # Date 314159265 0
> +
> +  $ hg qref -m b -d '47 0'
> +  $ cat .hg/patches/b
> +  # HG changeset patch
> +  # Parent cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b
> +  # Date 47 0
> +  b
> +
> +  diff --git a/b b/b
> +  new file mode 100644
> +  --- /dev/null
> +  +++ b/b
> +  @@ -0,0 +1,1 @@
> +  +b
> +
> +  $ echo a2 >> a
> +  $ hg qnew a2 -m a2 -d '117 0'
> +
> +  $ hg log -G --template "{rev} {node|short} {phase} {desc|firstline}\n"
> +  @  2 757e6e08e7eb draft a2
> +  |
> +  o  1 3506c28d72aa draft b
> +  |
> +  o  0 cb9a9f314b8b draft a
> +
> +
> +  $ hg qpop
> +  popping a2
> +  now at: b
> +
> +  $ cat .hg/patches/status
> +  3506c28d72aa3a31f8ce50ca4cfcb812af131450:b
> +
> +  $ hg log -G --template "{rev} {node|short} {phase} {desc|firstline}\n"
> +  @  1 3506c28d72aa draft b
> +  |
> +  o  0 cb9a9f314b8b draft a
> +
> +
> +  $ hg qpush
> +  applying a2
> +  now at: a2
> +
> +  $ cat .hg/patches/status
> +  3506c28d72aa3a31f8ce50ca4cfcb812af131450:b
> +  757e6e08e7eb6b956e2d583ff4d7450d392f8a13:a2
> +
> +  $ hg log -G --template "{rev} {node|short} {phase} {desc|firstline}\n"
> +  @  2 757e6e08e7eb draft a2
> +  |
> +  o  1 3506c28d72aa draft b
> +  |
> +  o  0 cb9a9f314b8b draft a
> +
> +
> +  $ hg qpop -a
> +  popping a2
> +  popping b
> +  patch queue now empty
> +  $ sed -i 1iyada a
> +  $ hg ci -m yada
> +
> +  $ hg log -G --template "{rev} {node|short} {phase} {desc|firstline}\n"
> +  @  1 dfa6dafa9c6c draft yada
> +  |
> +  o  0 cb9a9f314b8b draft a
> +
> +
> +  $ cat .hg/patches/b
> +  # HG changeset patch
> +  # Parent cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b
> +  # Date 47 0
> +  b
> +
> +  diff --git a/b b/b
> +  new file mode 100644
> +  --- /dev/null
> +  +++ b/b
> +  @@ -0,0 +1,1 @@
> +  +b
> +  $ hg qpush
> +  applying b
> +  now at: b
> +  $ cat .hg/patches/b
> +  # HG changeset patch
> +  # Parent cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b
> +  # Date 47 0
> +  b
> +
> +  diff --git a/b b/b
> +  new file mode 100644
> +  --- /dev/null
> +  +++ b/b
> +  @@ -0,0 +1,1 @@
> +  +b
> +
> +  $ hg qpush
> +  applying a2
> +  now at: a2
> +  $ hg log -G --template "{rev} {node|short} {phase} {desc|firstline}\n"
> +  @  3 cd192c2f0104 draft a2
> +  |
> +  o  2 c27d00b1f47f draft b
> +  |
> +  o  1 dfa6dafa9c6c draft yada
> +  |
> +  o  0 cb9a9f314b8b draft a
> +
> +
> +  $ hg qap
> +  b
> +  a2
> +  $ hg qpop -a
> +  popping a2
> +  popping b
> +  patch queue now empty
> +  $ hg qrm b
> +  $ hg qrm a2
> +(should also have stripped b that couldn't be stripped before)
> +  $ hg log -G --template "{rev} {node|short} {phase} {desc|firstline}\n"
> +  @  1 dfa6dafa9c6c draft yada
> +  |
> +  o  0 cb9a9f314b8b draft a
> +
> _______________________________________________
> Mercurial-devel mailing list
> Mercurial-devel@selenic.com
> http://selenic.com/mailman/listinfo/mercurial-devel
>
Pierre-Yves David - Sept. 11, 2014, 4:47 p.m.
While I recognize that having a modern MQ is very tempting, but I also 
doubtful that something useful may be achieved.


First, MQ is a very old extension that has some old properties which are 
unfriendly to distribution.

The main example of that is that MQ preserves hash, if you add a files, 
qrefresh, remove the file, refresh you end up with the exact same hash. 
This is not compatible with the append only model that DVCS needs (and 
evolution uses). I'm certain that we have a significant user base that 
rely on this behavior.

There is some other small examples like the fact that MQ always create 
changesets at the top of your repo. There are some people out there 
using the reverse index notation (-1, -2, -3) to refer to their MQ patches.

One could argues that this is part of the "grey interface" of MQ and 
that people should not rely on it. But people rely on it for almost 10 
years making it hard for us to change anything.


Second, Mercurial itself has a very low grasp on what happens in the MQ 
world. MQ is based on an external storage that people can touch 
directly. And people actively do that.Ppatches can be dropped without 
using qfinished, the whole MQ state may be revert to a previous state, 
patches are exchange between repo etc. Creating sensible obsolescence 
marker in that context is very hard. Preserving the property discussed 
before (hash preservation, …) is probably impossible.


As a result, I really fear that deep changes to MQ will break our user 
and provide an incomplete result that will behave properly in 75% or the 
case and lead to terrible terrible confusing for our user in the 25% 
other case.


So, if anything is attempted to build a MQ2, I think it should be done 
in a external extension. If we achieve a properly working results, we 
will patch the bundle MQ easily. And we can easily drop the experiment 
if it proves to be a dead end.


Some a of the idea in this series makes sense and will work in most case 
(hidding instead of stripping, using three way merge (possibly from a 
bundle?)) but I question the usefulness of keeping afloat a not so good 
UI that does not play nice will other history rewriting tool of 
Mercurial. I would rather see people focus their effort on extract the 
good idea of MQ in better UI. But, well, if someone what to give a try 
for building MQ2, why not.

On 09/09/2014 07:17 PM, Gregory Szorc wrote:
> As much as I personally dislike many aspects of mq, there are people
> (especially at Mozilla) that cling to it and this patch series offers
> some ideas that would go a long way towards making the mq workflow more
> compatible with Mozilla's wants.
>
> Namely:
>
> 1) Our new code review tool is obsolescence aware. When creating reviews
> of commits that have obsolescence data, the workflow is vastly simpler
> since we can get the commit mapping from history rewriting from
> obsolescence. Maintaining this from mq is slightly more difficult since
> it requires storing patch names. Patch names are neither versioned nor
> consistent, so things break down when people collaborate on reviews.
> (We're trying to avoid writing heuristic-based commit mapping for as
> long as possible.)
>
> 2) Merge handling. One of Mozilla's top complaints about Mercurial is
> merge handling. I suspect most of the complainers are people using mq
> and not getting the superior merge tool experience. I'd love to see mq
> play nicer with merging and not produce .rej files.
>
> I also think that bridging the gap between evolve and mq is a worthy
> goal. Some people just like thinking about mq-style heads as separate
> from the "core" repo data. It seems to be easier for them to grok.
>
> I feel that a lot of people at Mozilla will cling to mq despite advances
> in bookmarks workflows, etc. I would prefer to support these users with
> mq++ over mq-current. I therefore support this patch series.
>
> On 8/29/14 1:59 AM, Mads Kiilerich wrote:
>> # HG changeset patch
>> # User Mads Kiilerich <madski@unity3d.com>
>> # Date 1409301979 -7200
>> #      Fri Aug 29 10:46:19 2014 +0200
>> # Node ID e426af93a42f11fb187793904b743b5b4341af6e
>> # Parent  926bc0d3b595caf37c5d70833a347eb43285de2f
>> mq2: proof of concept for improving mq - starting point and tests
>>
>> These days it is trendy to bash mq and try to kill it. Instead, let's
>> create
>> something better and let the winner win and let the loser go somewhere
>> else and
>> die a quiet death.
>>
>> Let's try to evolve and improve mq and give people the choice of using
>> the tool
>> they prefer.
>>
>> I kind of see mq as a tool for efficiently locally working on a number of
>> patches, while I more more see evolve as a tool modifying history
>> under my
>> feet.
>>
>> Problems/design goals to address:
>>   * Improve mq and try to remain backwards compatible.
>>   * Use merge and merge tools instead of patches and .rej files.
>>   * Better meta history without using tracked queues.
>>   * Consider evolve and the mindset that comes with it, be compatible or
>>     bridge the gab to it.
>>
>> The basic ideas are:
>>   * Keep "stripped" (especially qpopped) changesets around instead of
>> stripping
>>     them.
>>   * If possible, use these changesets for grafting when "qpushing".
>>   * Update patch files with reference to the last changeset it was
>> qpushed as.
>>   * Get "rid" of qpopped changesets when they no longer are referenced -
>>     currently by using obsolete, could also strip them at that point.
>>
>> Current issues:
>>   * Needs real testing.
>>   * Needs better error handling.
>>   * Better handling of the 'qpush failed with .rej files' scenario.
>>   ** It will now use merge - which is nice but requires test updates.
>>   ** How to represent that state (use nullid or a commit of something
>> random?).
>>   ** How to continue from that state (qrefresh should pick it up).
>>   * Collision with already obsoleted changesets. Is that because
>> obsolete markers
>>     are a bad solution to the problem ... or solving the wrong problem?
>>   * Some .unfiltered() has been added in various places. Is it just
>> because
>>     this filtered hack is a *** hack or is there something wrong?
>>
>> These changes are done incrementally in code, causing some test churn
>> that mostly
>> ends up going away again. That is mostly because we start keeping
>> "stripped"
>> changesets before we start hiding them.
>>
>> diff --git a/tests/test-mq2.t b/tests/test-mq2.t
>> new file mode 100644
>> --- /dev/null
>> +++ b/tests/test-mq2.t
>> @@ -0,0 +1,153 @@
>> +  $ checkundo()
>> +  > {
>> +  >     if [ -f .hg/store/undo ]; then
>> +  >     echo ".hg/store/undo still exists after $1"
>> +  >     fi
>> +  > }
>> +
>> +  $ echo "[extensions]" >> $HGRCPATH
>> +  $ echo "mq=" >> $HGRCPATH
>> +
>> +  $ echo "[mq]" >> $HGRCPATH
>> +  $ echo "plain=false" >> $HGRCPATH
>> +
>> +  $ echo "[diff]" >> $HGRCPATH
>> +  $ echo "git=true" >> $HGRCPATH
>> +
>> +  $ hg init a
>> +  $ cd a
>> +  $ echo a > a
>> +  $ hg ci -Ama
>> +  adding a
>> +
>> +  $ hg qnew b -d '314159265 0'
>> +  $ echo b > b
>> +  $ hg add b
>> +  $ cat .hg/patches/b
>> +  # HG changeset patch
>> +  # Parent cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b
>> +  # Date 314159265 0
>> +
>> +  $ hg qref -m b -d '47 0'
>> +  $ cat .hg/patches/b
>> +  # HG changeset patch
>> +  # Parent cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b
>> +  # Date 47 0
>> +  b
>> +
>> +  diff --git a/b b/b
>> +  new file mode 100644
>> +  --- /dev/null
>> +  +++ b/b
>> +  @@ -0,0 +1,1 @@
>> +  +b
>> +
>> +  $ echo a2 >> a
>> +  $ hg qnew a2 -m a2 -d '117 0'
>> +
>> +  $ hg log -G --template "{rev} {node|short} {phase} {desc|firstline}\n"
>> +  @  2 757e6e08e7eb draft a2
>> +  |
>> +  o  1 3506c28d72aa draft b
>> +  |
>> +  o  0 cb9a9f314b8b draft a
>> +
>> +
>> +  $ hg qpop
>> +  popping a2
>> +  now at: b
>> +
>> +  $ cat .hg/patches/status
>> +  3506c28d72aa3a31f8ce50ca4cfcb812af131450:b
>> +
>> +  $ hg log -G --template "{rev} {node|short} {phase} {desc|firstline}\n"
>> +  @  1 3506c28d72aa draft b
>> +  |
>> +  o  0 cb9a9f314b8b draft a
>> +
>> +
>> +  $ hg qpush
>> +  applying a2
>> +  now at: a2
>> +
>> +  $ cat .hg/patches/status
>> +  3506c28d72aa3a31f8ce50ca4cfcb812af131450:b
>> +  757e6e08e7eb6b956e2d583ff4d7450d392f8a13:a2
>> +
>> +  $ hg log -G --template "{rev} {node|short} {phase} {desc|firstline}\n"
>> +  @  2 757e6e08e7eb draft a2
>> +  |
>> +  o  1 3506c28d72aa draft b
>> +  |
>> +  o  0 cb9a9f314b8b draft a
>> +
>> +
>> +  $ hg qpop -a
>> +  popping a2
>> +  popping b
>> +  patch queue now empty
>> +  $ sed -i 1iyada a
>> +  $ hg ci -m yada
>> +
>> +  $ hg log -G --template "{rev} {node|short} {phase} {desc|firstline}\n"
>> +  @  1 dfa6dafa9c6c draft yada
>> +  |
>> +  o  0 cb9a9f314b8b draft a
>> +
>> +
>> +  $ cat .hg/patches/b
>> +  # HG changeset patch
>> +  # Parent cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b
>> +  # Date 47 0
>> +  b
>> +
>> +  diff --git a/b b/b
>> +  new file mode 100644
>> +  --- /dev/null
>> +  +++ b/b
>> +  @@ -0,0 +1,1 @@
>> +  +b
>> +  $ hg qpush
>> +  applying b
>> +  now at: b
>> +  $ cat .hg/patches/b
>> +  # HG changeset patch
>> +  # Parent cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b
>> +  # Date 47 0
>> +  b
>> +
>> +  diff --git a/b b/b
>> +  new file mode 100644
>> +  --- /dev/null
>> +  +++ b/b
>> +  @@ -0,0 +1,1 @@
>> +  +b
>> +
>> +  $ hg qpush
>> +  applying a2
>> +  now at: a2
>> +  $ hg log -G --template "{rev} {node|short} {phase} {desc|firstline}\n"
>> +  @  3 cd192c2f0104 draft a2
>> +  |
>> +  o  2 c27d00b1f47f draft b
>> +  |
>> +  o  1 dfa6dafa9c6c draft yada
>> +  |
>> +  o  0 cb9a9f314b8b draft a
>> +
>> +
>> +  $ hg qap
>> +  b
>> +  a2
>> +  $ hg qpop -a
>> +  popping a2
>> +  popping b
>> +  patch queue now empty
>> +  $ hg qrm b
>> +  $ hg qrm a2
>> +(should also have stripped b that couldn't be stripped before)
>> +  $ hg log -G --template "{rev} {node|short} {phase} {desc|firstline}\n"
>> +  @  1 dfa6dafa9c6c draft yada
>> +  |
>> +  o  0 cb9a9f314b8b draft a
>> +
>> _______________________________________________
>> Mercurial-devel mailing list
>> Mercurial-devel@selenic.com
>> http://selenic.com/mailman/listinfo/mercurial-devel
>>
>
> _______________________________________________
> Mercurial-devel mailing list
> Mercurial-devel@selenic.com
> http://selenic.com/mailman/listinfo/mercurial-devel

Patch

diff --git a/tests/test-mq2.t b/tests/test-mq2.t
new file mode 100644
--- /dev/null
+++ b/tests/test-mq2.t
@@ -0,0 +1,153 @@ 
+  $ checkundo()
+  > {
+  >     if [ -f .hg/store/undo ]; then
+  >     echo ".hg/store/undo still exists after $1"
+  >     fi
+  > }
+
+  $ echo "[extensions]" >> $HGRCPATH
+  $ echo "mq=" >> $HGRCPATH
+
+  $ echo "[mq]" >> $HGRCPATH
+  $ echo "plain=false" >> $HGRCPATH
+
+  $ echo "[diff]" >> $HGRCPATH
+  $ echo "git=true" >> $HGRCPATH
+
+  $ hg init a
+  $ cd a
+  $ echo a > a
+  $ hg ci -Ama
+  adding a
+
+  $ hg qnew b -d '314159265 0'
+  $ echo b > b
+  $ hg add b
+  $ cat .hg/patches/b
+  # HG changeset patch
+  # Parent cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b
+  # Date 314159265 0
+  
+  $ hg qref -m b -d '47 0'
+  $ cat .hg/patches/b
+  # HG changeset patch
+  # Parent cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b
+  # Date 47 0
+  b
+  
+  diff --git a/b b/b
+  new file mode 100644
+  --- /dev/null
+  +++ b/b
+  @@ -0,0 +1,1 @@
+  +b
+
+  $ echo a2 >> a
+  $ hg qnew a2 -m a2 -d '117 0'
+
+  $ hg log -G --template "{rev} {node|short} {phase} {desc|firstline}\n"
+  @  2 757e6e08e7eb draft a2
+  |
+  o  1 3506c28d72aa draft b
+  |
+  o  0 cb9a9f314b8b draft a
+  
+
+  $ hg qpop
+  popping a2
+  now at: b
+
+  $ cat .hg/patches/status
+  3506c28d72aa3a31f8ce50ca4cfcb812af131450:b
+
+  $ hg log -G --template "{rev} {node|short} {phase} {desc|firstline}\n"
+  @  1 3506c28d72aa draft b
+  |
+  o  0 cb9a9f314b8b draft a
+  
+
+  $ hg qpush
+  applying a2
+  now at: a2
+
+  $ cat .hg/patches/status
+  3506c28d72aa3a31f8ce50ca4cfcb812af131450:b
+  757e6e08e7eb6b956e2d583ff4d7450d392f8a13:a2
+
+  $ hg log -G --template "{rev} {node|short} {phase} {desc|firstline}\n"
+  @  2 757e6e08e7eb draft a2
+  |
+  o  1 3506c28d72aa draft b
+  |
+  o  0 cb9a9f314b8b draft a
+  
+
+  $ hg qpop -a
+  popping a2
+  popping b
+  patch queue now empty
+  $ sed -i 1iyada a
+  $ hg ci -m yada
+
+  $ hg log -G --template "{rev} {node|short} {phase} {desc|firstline}\n"
+  @  1 dfa6dafa9c6c draft yada
+  |
+  o  0 cb9a9f314b8b draft a
+  
+
+  $ cat .hg/patches/b
+  # HG changeset patch
+  # Parent cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b
+  # Date 47 0
+  b
+  
+  diff --git a/b b/b
+  new file mode 100644
+  --- /dev/null
+  +++ b/b
+  @@ -0,0 +1,1 @@
+  +b
+  $ hg qpush
+  applying b
+  now at: b
+  $ cat .hg/patches/b
+  # HG changeset patch
+  # Parent cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b
+  # Date 47 0
+  b
+  
+  diff --git a/b b/b
+  new file mode 100644
+  --- /dev/null
+  +++ b/b
+  @@ -0,0 +1,1 @@
+  +b
+
+  $ hg qpush
+  applying a2
+  now at: a2
+  $ hg log -G --template "{rev} {node|short} {phase} {desc|firstline}\n"
+  @  3 cd192c2f0104 draft a2
+  |
+  o  2 c27d00b1f47f draft b
+  |
+  o  1 dfa6dafa9c6c draft yada
+  |
+  o  0 cb9a9f314b8b draft a
+  
+
+  $ hg qap
+  b
+  a2
+  $ hg qpop -a
+  popping a2
+  popping b
+  patch queue now empty
+  $ hg qrm b
+  $ hg qrm a2
+(should also have stripped b that couldn't be stripped before)
+  $ hg log -G --template "{rev} {node|short} {phase} {desc|firstline}\n"
+  @  1 dfa6dafa9c6c draft yada
+  |
+  o  0 cb9a9f314b8b draft a
+