diff --git a/hgext/mq.py b/hgext/mq.py --- a/hgext/mq.py +++ b/hgext/mq.py @@ -1006,7 +1006,7 @@ class queue(object): raise util.Abort(_("patch %s not in series") % patch) def push(self, repo, patch=None, force=False, list=False, - mergeq=None, all=False, move=False): + mergeq=None, all=False, move=False, exact=False): diffopts = self.diffopts() wlock = repo.wlock() try: @@ -1015,7 +1015,7 @@ class queue(object): heads += ls if not heads: heads = [nullid] - if repo.dirstate.parents()[0] not in heads: + if repo.dirstate.parents()[0] not in heads and not exact: self.ui.status(_("(working directory not at a head)\n")) if not self.series: @@ -1062,6 +1062,18 @@ class queue(object): if not force: self.check_localchanges(repo) + if exact: + if move: + raise util.Abort(_("cannot use --exact and --move together")) + if self.applied: + raise util.Abort(_("cannot push --exact with applied patches")) + root = self.series[start] + target = patchheader(self.join(root), self.plainmode).parent + if not target: + raise util.Abort(_("%s does not have a parent recorded" % root)) + if not repo[target] == repo['.']: + hg.update(repo, target) + if move: if not patch: raise util.Abort(_("please specify the patch to move")) @@ -2338,7 +2350,8 @@ def push(ui, repo, patch=None, **opts): mergeq = queue(ui, repo.join(""), newpath) ui.warn(_("merging with queue at: %s\n") % mergeq.path) ret = q.push(repo, patch, force=opts.get('force'), list=opts.get('list'), - mergeq=mergeq, all=opts.get('all'), move=opts.get('move')) + mergeq=mergeq, all=opts.get('all'), move=opts.get('move'), + exact=opts.get('exact')) return ret def pop(ui, repo, patch=None, **opts): @@ -3114,6 +3127,7 @@ cmdtable = { "^qpush": (push, [('f', 'force', None, _('apply on top of local changes')), + ('e', 'exact', None, _('apply the target patch to its recorded parent')), ('l', 'list', None, _('list patch name in commit text')), ('a', 'all', None, _('apply all patches')), ('m', 'merge', None, _('merge from another queue (DEPRECATED)')), diff --git a/tests/test-mq-qpush-exact.t b/tests/test-mq-qpush-exact.t new file mode 100644 --- /dev/null +++ b/tests/test-mq-qpush-exact.t @@ -0,0 +1,290 @@ + $ echo "[extensions]" >> $HGRCPATH + $ echo "mq=" >> $HGRCPATH + $ echo "graphlog=" >> $HGRCPATH + +make a test repository that looks like this: + +o 2:28bc7b1afd6a +| +| @ 1:d7fe2034f71b +|/ +o 0/62ecad8b70e5 + + $ hg init r0 + $ cd r0 + $ touch f0 + $ hg ci -m0 -Aq + $ touch f1 + $ hg ci -m1 -Aq + + $ hg update 0 -q + $ touch f2 + $ hg ci -m2 -Aq + $ hg update 1 -q + +make some patches with a parent: 1:d7fe2034f71b -> p0 -> p1 + + $ echo cp0 >> fp0 + $ hg add fp0 + $ hg qnew p0 -d "0 0" + + $ echo cp1 >> fp1 + $ hg add fp1 + $ hg qnew p1 -d "0 0" + + $ hg qpop -aq + patch queue now empty + +qpush --exact when at the parent + + $ hg update 1 -q + $ hg qpush -e + applying p0 + now at: p0 + $ hg parents -qr qbase + 1:d7fe2034f71b + $ hg qpop -aq + patch queue now empty + + $ hg qpush -e p0 + applying p0 + now at: p0 + $ hg parents -qr qbase + 1:d7fe2034f71b + $ hg qpop -aq + patch queue now empty + + $ hg qpush -e p1 + applying p0 + applying p1 + now at: p1 + $ hg parents -qr qbase + 1:d7fe2034f71b + $ hg qpop -aq + patch queue now empty + + $ hg qpush -ea + applying p0 + applying p1 + now at: p1 + $ hg parents -qr qbase + 1:d7fe2034f71b + $ hg qpop -aq + patch queue now empty + +qpush --exact when at another rev + + $ hg update 0 -q + $ hg qpush -e + 1 files updated, 0 files merged, 0 files removed, 0 files unresolved + applying p0 + now at: p0 + $ hg parents -qr qbase + 1:d7fe2034f71b + $ hg qpop -aq + patch queue now empty + + $ hg update 0 -q + $ hg qpush -e p0 + 1 files updated, 0 files merged, 0 files removed, 0 files unresolved + applying p0 + now at: p0 + $ hg parents -qr qbase + 1:d7fe2034f71b + $ hg qpop -aq + patch queue now empty + + $ hg update 0 -q + $ hg qpush -e p1 + 1 files updated, 0 files merged, 0 files removed, 0 files unresolved + applying p0 + applying p1 + now at: p1 + $ hg parents -qr qbase + 1:d7fe2034f71b + $ hg qpop -aq + patch queue now empty + + $ hg update 0 -q + $ hg qpush -ea + 1 files updated, 0 files merged, 0 files removed, 0 files unresolved + applying p0 + applying p1 + now at: p1 + $ hg parents -qr qbase + 1:d7fe2034f71b + $ hg qpop -aq + patch queue now empty + +qpush --exact while crossing branches + + $ hg update 2 -q + $ hg qpush -e + 1 files updated, 0 files merged, 1 files removed, 0 files unresolved + applying p0 + now at: p0 + $ hg parents -qr qbase + 1:d7fe2034f71b + $ hg qpop -aq + patch queue now empty + + $ hg update 2 -q + $ hg qpush -e p0 + 1 files updated, 0 files merged, 1 files removed, 0 files unresolved + applying p0 + now at: p0 + $ hg parents -qr qbase + 1:d7fe2034f71b + $ hg qpop -aq + patch queue now empty + + $ hg update 2 -q + $ hg qpush -e p1 + 1 files updated, 0 files merged, 1 files removed, 0 files unresolved + applying p0 + applying p1 + now at: p1 + $ hg parents -qr qbase + 1:d7fe2034f71b + $ hg qpop -aq + patch queue now empty + + $ hg update 2 -q + $ hg qpush -ea + 1 files updated, 0 files merged, 1 files removed, 0 files unresolved + applying p0 + applying p1 + now at: p1 + $ hg parents -qr qbase + 1:d7fe2034f71b + $ hg qpop -aq + patch queue now empty + +qpush --exact --force with changes to an unpatched file + + $ hg update 1 -q + $ echo c0 >> f0 + $ hg qpush -e + abort: local changes found, refresh first + [255] + $ hg qpush -ef + applying p0 + now at: p0 + $ cat f0 + c0 + $ rm f0 + $ touch f0 + $ hg qpop -aq + patch queue now empty + + $ hg update 1 -q + $ echo c0 >> f0 + $ hg qpush -e p1 + abort: local changes found, refresh first + [255] + $ hg qpush -e p1 -f + applying p0 + applying p1 + now at: p1 + $ cat f0 + c0 + $ rm f0 + $ touch f0 + $ hg qpop -aq + patch queue now empty + +qpush --exact --force with changes to a patched file + + $ hg update 1 -q + $ echo cp0-bad >> fp0 + $ hg add fp0 + $ hg qpush -e + abort: local changes found, refresh first + [255] + $ hg qpush -ef + applying p0 + file fp0 already exists + 1 out of 1 hunks FAILED -- saving rejects to file fp0.rej + patch failed, unable to continue (try -v) + patch failed, rejects left in working dir + errors during apply, please fix and refresh p0 + [2] + $ cat fp0 + cp0-bad + $ cat fp0.rej + --- fp0 + +++ fp0 + @@ -0,0 +1,1 @@ + +cp0 + $ hg qpop -aqf + patch queue now empty + $ rm fp0 + $ rm fp0.rej + + $ hg update 1 -q + $ echo cp1-bad >> fp1 + $ hg add fp1 + $ hg qpush -e p1 + abort: local changes found, refresh first + [255] + $ hg qpush -e p1 -f + applying p0 + applying p1 + file fp1 already exists + 1 out of 1 hunks FAILED -- saving rejects to file fp1.rej + patch failed, unable to continue (try -v) + patch failed, rejects left in working dir + errors during apply, please fix and refresh p1 + [2] + $ cat fp1 + cp1-bad + $ cat fp1.rej + --- fp1 + +++ fp1 + @@ -0,0 +1,1 @@ + +cp1 + $ hg qpop -aqf + patch queue now empty + $ rm fp1 + $ rm fp1.rej + +qpush --exact when already at a patch + + $ hg update 1 + 0 files updated, 0 files merged, 0 files removed, 0 files unresolved + $ hg qpush -e p0 + applying p0 + now at: p0 + $ hg qpush -e p1 + abort: cannot push --exact with applied patches + [255] + $ hg qpop -aq + patch queue now empty + +qpush --exact --move should fail + + $ hg qpush -e --move p1 + abort: cannot use --exact and --move together + [255] + +qpush --exact a patch without a parent recorded + + $ hg qpush -q + now at: p0 + $ grep -v '# Parent' .hg/patches/p0 > p0.new + $ mv p0.new .hg/patches/p0 + $ hg qpop -aq + patch queue now empty + $ hg qpush -e + abort: p0 does not have a parent recorded + [255] + $ hg qpush -e p0 + abort: p0 does not have a parent recorded + [255] + $ hg qpush -e p1 + abort: p0 does not have a parent recorded + [255] + $ hg qpush -ea + abort: p0 does not have a parent recorded + [255] +