[PATCH] transplant: permit merge changesets via --parent

Steven Stallion sstallion at gmail.com
Sun Apr 8 19:43:53 CDT 2012


# HG changeset patch
# User Steven Stallion <sstallion at gmail.com>
# Date 1333932216 25200
# Node ID 3979508e3822d65024de83a7add1d2adbfa2f3bf
# Parent  329887a7074c8e49e73fa76712d8d45aee0d0fd7
transplant: permit merge changesets via --parent

This change permits the transplant extension to operate on merge
changesets by way of --parent.  This is particularly useful for
workflows which cherrypick branch merges rather than each commit
within a branch.

diff -r 329887a7074c -r 3979508e3822 hgext/transplant.py
--- a/hgext/transplant.py	Fri Apr 06 15:18:14 2012 -0500
+++ b/hgext/transplant.py	Sun Apr 08 17:43:36 2012 -0700
@@ -121,10 +121,21 @@
                     continue
 
                 parents = source.changelog.parents(node)
+                if len(parents) > 1:
+                    if not opts.get('parent'):
+                        raise util.Abort(
+                            _('cannot transplant a merge changeset'))
+                    parent = source.lookup(opts['parent'])
+                    if parent not in parents:
+                        raise util.Abort(_('%s is not a parent of %s') %
+                                         (short(parent), short(node)))	 
+                else:
+                    parent = parents[0]
+
                 if not opts.get('filter'):
                     # If the changeset parent is the same as the
                     # wdir's parent, just pull it.
-                    if parents[0] == p1:
+                    if parent == p1:
                         pulls.append(node)
                         p1 = node
                         continue
@@ -144,36 +155,30 @@
                     if not hasnode(repo, node):
                         repo.pull(source, heads=[node])
 
-                if parents[1] != revlog.nullid:
-                    self.ui.note(_('skipping merge changeset %s:%s\n')
-                                 % (rev, short(node)))
-                    patchfile = None
-                else:
-                    fd, patchfile = tempfile.mkstemp(prefix='hg-transplant-')
-                    fp = os.fdopen(fd, 'w')
-                    gen = patch.diff(source, parents[0], node, opts=diffopts)
-                    for chunk in gen:
-                        fp.write(chunk)
-                    fp.close()
+                fd, patchfile = tempfile.mkstemp(prefix='hg-transplant-')
+                fp = os.fdopen(fd, 'w')
+                gen = patch.diff(source, parent, node, opts=diffopts)
+                for chunk in gen:
+                    fp.write(chunk)
+                fp.close()
 
                 del revmap[rev]
-                if patchfile or domerge:
-                    try:
-                        n = self.applyone(repo, node,
-                                          source.changelog.read(node),
-                                          patchfile, merge=domerge,
-                                          log=opts.get('log'),
-                                          filter=opts.get('filter'))
-                        if n and domerge:
-                            self.ui.status(_('%s merged at %s\n') % (revstr,
-                                      short(n)))
-                        elif n:
-                            self.ui.status(_('%s transplanted to %s\n')
-                                           % (short(node),
-                                              short(n)))
-                    finally:
-                        if patchfile:
-                            os.unlink(patchfile)
+                try:
+                    n = self.applyone(repo, node,
+                                      source.changelog.read(node),
+                                      patchfile, merge=domerge,
+                                      log=opts.get('log'),
+                                      filter=opts.get('filter'))
+                    if n and domerge:
+                        self.ui.status(_('%s merged at %s\n') % (revstr,
+                                  short(n)))
+                    elif n:
+                        self.ui.status(_('%s transplanted to %s\n')
+                                       % (short(node),
+                                          short(n)))
+                finally:
+                    if patchfile:
+                        os.unlink(patchfile)
             tr.close()
             if pulls:
                 repo.pull(source, heads=pulls)
@@ -295,19 +300,30 @@
     def recover(self, repo):
         '''commit working directory using journal metadata'''
         node, user, date, message, parents = self.readlog()
-        merge = len(parents) == 2
+        merge = False
 
         if not user or not date or not message or not parents[0]:
             raise util.Abort(_('transplant log file is corrupt'))
+                
+        if len(parents) > 1:
+            if opts.get('parent'):
+                parent = source.lookup(opts['parent'])
+                if parent not in parents:
+                    raise util.Abort(_('%s is not a parent of %s') %
+                                     (short(parent), short(node)))
+            else:
+                merge = True
+        if not parent:
+            parent = parents[0]
 
         extra = {'transplant_source': node}
         wlock = repo.wlock()
         try:
             p1, p2 = repo.dirstate.parents()
-            if p1 != parents[0]:
+            if p1 != parent:
                 raise util.Abort(
                     _('working dir not at transplant parent %s') %
-                                 revlog.hex(parents[0]))
+                                 revlog.hex(parent))
             if merge:
                 repo.dirstate.setparents(p1, parents[1])
             n = repo.commit(message, user, date, extra=extra,
@@ -468,6 +484,8 @@
     ('a', 'all', None, _('pull all changesets up to BRANCH')),
     ('p', 'prune', [], _('skip over REV'), _('REV')),
     ('m', 'merge', [], _('merge at REV'), _('REV')),
+    ('', 'parent', '',                                                                                                                  
+     _('parent to choose when transplanting merge'), _('REV')), 
     ('e', 'edit', False, _('invoke editor on commit messages')),
     ('', 'log', None, _('append transplant info to log message')),
     ('c', 'continue', None, _('continue last transplant session '
@@ -510,6 +528,9 @@
     of a merged transplant, and you can merge descendants of them
     normally instead of transplanting them.
 
+    Merge changesets may be transplanted directly by specifying the
+    proper parent changeset by calling :hg: `transplant --parent`.
+
     If no merges or revisions are provided, :hg:`transplant` will
     start an interactive changeset browser.
 


More information about the Mercurial-devel mailing list