changeset 6645:37eedb1a1848

mq: introduce the qfinish command
author Dirkjan Ochtman <dirkjan@ochtman.nl>
date Tue, 03 Jun 2008 09:34:14 +0200
parents 8c01ce1f2530
children 9eb274d773d9 602f7c1ab954
files hgext/mq.py tests/test-mq-qdelete tests/test-mq-qdelete.out tests/test-mq.out
diffstat 4 files changed, 121 insertions(+), 9 deletions(-) [+]
line wrap: on
line diff
--- a/hgext/mq.py	Tue Jun 03 12:27:48 2008 +0200
+++ b/hgext/mq.py	Tue Jun 03 09:34:14 2008 +0200
@@ -535,6 +535,41 @@
                 break
         return (err, n)
 
+    def _clean_series(self, patches):
+        indices = [self.find_series(p) for p in patches]
+        indices.sort()
+        for i in indices[-1::-1]:
+            del self.full_series[i]
+        self.parse_series()
+        self.series_dirty = 1
+
+    def finish(self, repo, revs):
+        revs.sort()
+        firstrev = repo.changelog.rev(revlog.bin(self.applied[0].rev))
+        appliedbase = 0
+        patches = []
+        for rev in revs:
+            if rev < firstrev:
+                raise util.Abort(_('revision %d is not managed') % rev)
+            base = revlog.bin(self.applied[appliedbase].rev)
+            node = repo.changelog.node(rev)
+            if node != base:
+                raise util.Abort(_('cannot delete revision %d above '
+                                   'applied patches') % rev)
+            patches.append(self.applied[appliedbase].name)
+            appliedbase += 1
+
+        r = self.qrepo()
+        if r:
+            r.remove(patches, True)
+        else:
+            for p in patches:
+                os.unlink(self.join(p))
+
+        del self.applied[:appliedbase]
+        self.applied_dirty = 1
+        self._clean_series(patches)
+
     def delete(self, repo, patches, opts):
         if not patches and not opts.get('rev'):
             raise util.Abort(_('qdelete requires at least one revision or '
@@ -580,12 +615,7 @@
         if appliedbase:
             del self.applied[:appliedbase]
             self.applied_dirty = 1
-        indices = [self.find_series(p) for p in realpatches]
-        indices.sort()
-        for i in indices[-1::-1]:
-            del self.full_series[i]
-        self.parse_series()
-        self.series_dirty = 1
+        self._clean_series(realpatches)
 
     def check_toppatch(self, repo):
         if len(self.applied) > 0:
@@ -1497,9 +1527,8 @@
     the --rev parameter. At least one patch or revision is required.
 
     With --rev, mq will stop managing the named revisions (converting
-    them to regular mercurial changesets). The patches must be applied
-    and at the base of the stack. This option is useful when the patches
-    have been applied upstream.
+    them to regular mercurial changesets). The qfinish command should be
+    used as an alternative for qdel -r, as the latter option is deprecated.
 
     With --keep, the patch files are preserved in the patch directory."""
     q = repo.mq
@@ -2185,6 +2214,34 @@
         finally:
             q.save_dirty()
 
+def finish(ui, repo, *revrange, **opts):
+    """move applied patches into repository history
+
+    Finishes the specified revisions (corresponding to applied patches) by
+    moving them out of mq control into regular repository history.
+
+    Accepts a revision range or the --all option. If --all is specified, all
+    applied mq revisions are removed from mq control. Otherwise, the given
+    revisions must be at the base of the stack of applied patches.
+
+    This can be especially useful if your changes have been applied to an
+    upstream repository, or if you are about to push your changes to upstream.
+    """
+    if not opts['applied'] and not revrange:
+        raise util.Abort(_('no revisions specified'))
+    elif opts['applied']:
+        revrange = ('qbase:qtip',) + revrange
+
+    q = repo.mq
+    if not q.applied:
+        ui.status(_('no patches applied\n'))
+        return 0
+
+    revs = cmdutil.revrange(repo, revrange)
+    q.finish(repo, revs)
+    q.save_dirty()
+    return 0
+
 def reposetup(ui, repo):
     class mqrepo(repo.__class__):
         def abort_if_wdir_patched(self, errmsg, force=False):
@@ -2395,4 +2452,8 @@
          _('hg strip [-f] [-b] [-n] REV')),
     "qtop": (top, [] + seriesopts, _('hg qtop [-s]')),
     "qunapplied": (unapplied, [] + seriesopts, _('hg qunapplied [-s] [PATCH]')),
+    "qfinish":
+        (finish,
+         [('a', 'applied', None, _('finish all applied changesets'))],
+         _('hg qfinish [-a] [REV...]')),
 }
--- a/tests/test-mq-qdelete	Tue Jun 03 12:27:48 2008 +0200
+++ b/tests/test-mq-qdelete	Tue Jun 03 09:34:14 2008 +0200
@@ -35,3 +35,33 @@
 hg qdel -r qbase:e
 hg qapplied
 hg log --template '{rev} {desc}\n'
+
+cd ..
+hg init b
+cd b
+
+echo 'base' > base
+hg ci -Ambase
+
+hg qfinish
+hg qfinish -a
+
+hg qnew a
+hg qnew b
+hg qnew c
+
+hg qfinish 0
+hg qfinish b
+
+hg qpop
+hg qfinish -a c
+hg qpush
+
+hg qfinish qbase:b
+hg qapplied
+hg log --template '{rev} {desc}\n'
+
+hg qfinish -a c
+hg qapplied
+hg log --template '{rev} {desc}\n'
+ls .hg/patches
--- a/tests/test-mq-qdelete.out	Tue Jun 03 12:27:48 2008 +0200
+++ b/tests/test-mq-qdelete.out	Tue Jun 03 09:34:14 2008 +0200
@@ -22,3 +22,23 @@
 2 [mq]: d
 1 [mq]: a
 0 base
+adding base
+abort: no revisions specified
+no patches applied
+abort: revision 0 is not managed
+abort: cannot delete revision 2 above applied patches
+Now at: b
+abort: unknown revision 'c'!
+applying c
+Now at: c
+c
+3 imported patch c
+2 [mq]: b
+1 [mq]: a
+0 base
+3 imported patch c
+2 [mq]: b
+1 [mq]: a
+0 base
+series
+status
--- a/tests/test-mq.out	Tue Jun 03 12:27:48 2008 +0200
+++ b/tests/test-mq.out	Tue Jun 03 09:34:14 2008 +0200
@@ -29,6 +29,7 @@
  qcommit      commit changes in the queue repository
  qdelete      remove patches from queue
  qdiff        diff of the current patch and subsequent modifications
+ qfinish      move applied patches into repository history
  qfold        fold the named patches into the current patch
  qgoto        push or pop patches until named patch is at top of stack
  qguard       set or print guards for a patch