# HG changeset patch
# User Gilles Moris <gilles.moris@free.fr>
# Date 1204580451 -3600
# Node ID cff2b5369db1ec9db2ed35f22a87087abdfd55a9
# Parent  b193a6e591319726e8ccd0b4322f9b4785f59390
qrebase command

diff -r b193a6e59131 -r cff2b5369db1 hgext/mq.py
--- a/hgext/mq.py	Mon Mar 03 21:48:43 2008 +0100
+++ b/hgext/mq.py	Mon Mar 03 22:40:51 2008 +0100
@@ -32,7 +32,7 @@ from mercurial.i18n import _
 from mercurial.i18n import _
 from mercurial import commands, cmdutil, hg, patch, revlog, util
 from mercurial import repair
-import os, sys, re, errno
+import os, sys, re, errno, shutil
 
 commands.norepo += " qclone"
 
@@ -1705,6 +1705,97 @@ def new(ui, repo, patch, *args, **opts):
     q.save_dirty()
     return 0
 
+def rebase(ui, repo, *args, **opts):
+    """rebase the patch queue on a different revision
+
+    The patch queue will be merged in the given revision.
+    See http://www.selenic.com/mercurial/wiki/index.cgi/MqMerge
+    If no revision is specified, and the repository contains exactly
+    one head on the current branch, this head will be selected.
+    """
+    # check for clean work tree
+    cmdutil.bail_if_changed(repo)
+    # check for mq existence
+    if opts['name']:
+        q = queue(ui, repo.join(""), repo.join(opts['name']))
+    else:
+        q = queue(ui, repo.join(""))
+
+    if not q.series:
+        raise util.Abort(_('No patches to rebase'))
+    patch = q.series[-1]
+
+    # find where to rebase
+    if not args:
+        # find heads from the current branch that are not in mq
+        curbranch = repo.dirstate.branch()
+        mqnodes = [revlog.bin(p.rev) for p in q.applied]
+        heads = [head for head in repo.heads()
+                 if head not in mqnodes and
+                 repo.changectx(repo.changelog.rev(head)).branch() == curbranch]
+        if len(heads) > 1:
+            raise util.Abort(_('More than 1 head: please give the revision to which to rebase'))
+        elif len(heads) == 0:
+            raise util.Abort('No head to rebase to has been found')
+        else:
+            rev = heads[0]
+    else:
+        if len(args) > 1:
+            raise util.Abort(_('Give as only arguments the rev where to rebase'))
+        rev = args[0]
+        # check revision validity
+        repo.lookup(rev)
+
+    # possibly jump to the base, otherwise use current node
+    if opts['rebase_from']:
+        if q.applied:
+            q.pop(repo, None, force=None, update=True, all=True)
+            q.save_dirty()
+        hg.clean(repo, opts['rebase_from'], show_stats=False)
+    
+    # hg qpush -a
+    if q.push(repo, patch, None, None, None):
+        raise util.Abort(_('Could not apply all the patches in queue'))
+
+    # hg qsave
+    if q.save(repo):
+        raise util.Abort(_('Could not save patch queue'))
+    q.save_dirty()
+    # hg qsave -c
+    path = q.path
+    newpath = savename(path)
+    util.copyfiles(path, newpath)
+    # hg qsave -e
+    os.unlink(q.join(q.status_path))
+
+    # hg update -C
+    hg.clean(repo, rev, show_stats=False)
+
+    # qsave moved the queue, so we need to reread it
+    if opts['name']:
+        q = queue(ui, repo.join(""), repo.join(opts['name']))
+    else:
+        q = queue(ui, repo.join(""))
+    # hg qpush -a -m
+    mergeq = queue(ui, repo.join(""), newpath)
+    if q.push(repo, patch, force=None, list=None, mergeq=mergeq):
+        raise util.Abort(_('Could not merge the queue'))
+
+    # hg qpop -a
+    ret = q.pop(repo, None, force=None, update=True, all=True)
+    q.save_dirty()
+    if ret:
+        raise util.Abort(_('Could not clean up the queue'))
+    # hg qpop -a -n patches.N
+    ret = mergeq.pop(repo, None, force=None, update=False, all=True)
+    mergeq.save_dirty()
+    if ret:
+        raise util.Abort(_('Could not clean up the merge queue'))
+    # rm -rf patches.N
+    shutil.rmtree(newpath)
+    
+    return ret
+
 def refresh(ui, repo, *pats, **opts):
     """update the current patch
 
@@ -2309,6 +2400,12 @@ cmdtable = {
           ('m', 'merge', None, _('merge from another queue')),
           ('n', 'name', '', _('merge queue name'))],
          _('hg qpush [-f] [-l] [-a] [-m] [-n NAME] [PATCH | INDEX]')),
+    "^qrebase":
+        (rebase,
+         [('n', 'name', '', _('queue to be rebased')),
+          ('b', 'rebase-from', '', _('revision from which the queue previously applied'))
+          ],
+         _('hg qrebase [-n NAME] [-b FROM_REV] [TO_REV]')),
     "^qrefresh":
         (refresh,
          [('e', 'edit', None, _('edit commit message')),

