diff --git a/hgext/mq.py b/hgext/mq.py --- a/hgext/mq.py +++ b/hgext/mq.py @@ -1029,15 +1029,17 @@ class queue(object): # go backwards with qpush) if patch: info = self.isapplied(patch) - if info: - if info[0] < len(self.applied) - 1: - raise util.Abort( - _("cannot push to a previous patch: %s") % patch) + if info and info[0] >= len(self.applied) - 1: self.ui.warn( _('qpush: %s is already at the top\n') % patch) return 0 + pushable, reason = self.pushable(patch) - if not pushable: + if pushable: + if self.series.index(patch) < self.series_end(): + raise util.Abort( + _("cannot push to a previous patch: %s") % patch) + else: if reason: reason = _('guarded by %r') % reason else: diff --git a/tests/test-mq-qpush-fail.t b/tests/test-mq-qpush-fail.t --- a/tests/test-mq-qpush-fail.t +++ b/tests/test-mq-qpush-fail.t @@ -88,3 +88,49 @@ qpush should fail the same way as below applying patch1 unable to read patch1 [1] + +Test qpush to a patch below the currently applied patch. + + $ hg qq -c guardedseriesorder + $ hg qnew a + $ hg qguard +block + $ hg qnew b + $ hg qnew c + + $ hg qpop -a + popping c + popping b + popping a + patch queue now empty + +try to push and pop while a is guarded + + $ hg qpush a + cannot push 'a' - guarded by ['+block'] + [1] + $ hg qpush -a + applying b + patch b is empty + applying c + patch c is empty + now at: c + +now try it when a is unguarded, and we're at the top of the queue + $ hg qsel block + number of guarded, applied patches has changed from 1 to 0 + $ hg qpush b + abort: cannot push to a previous patch: b + [255] + $ hg qpush a + abort: cannot push to a previous patch: a + [255] + +and now we try it one more time with a unguarded, while we're not at the top of the queue + + $ hg qpop b + popping c + now at: b + $ hg qpush a + abort: cannot push to a previous patch: a + [255] +