changeset 16400:f2ba409dbb0f

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.
author Steven Stallion <sstallion@gmail.com>
date Tue, 10 Apr 2012 23:24:12 -0700
parents 7416ce2c7887
children c292bbbcf10c
files hgext/transplant.py tests/test-transplant.t
diffstat 2 files changed, 87 insertions(+), 6 deletions(-) [+]
line wrap: on
line diff
--- a/hgext/transplant.py	Thu Apr 12 20:22:18 2012 -0500
+++ b/hgext/transplant.py	Tue Apr 10 23:24:12 2012 -0700
@@ -144,14 +144,26 @@
                     if not hasnode(repo, node):
                         repo.pull(source, heads=[node])
 
+                skipmerge = False
                 if parents[1] != revlog.nullid:
-                    self.ui.note(_('skipping merge changeset %s:%s\n')
-                                 % (rev, short(node)))
+                    if not opts.get('parent'):
+                        self.ui.note(_('skipping merge changeset %s:%s\n')
+                                     % (rev, short(node)))
+                        skipmerge = True
+                    else:
+                        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 skipmerge:
                     patchfile = None
                 else:
                     fd, patchfile = tempfile.mkstemp(prefix='hg-transplant-')
                     fp = os.fdopen(fd, 'w')
-                    gen = patch.diff(source, parents[0], node, opts=diffopts)
+                    gen = patch.diff(source, parent, node, opts=diffopts)
                     for chunk in gen:
                         fp.write(chunk)
                     fp.close()
@@ -295,19 +307,29 @@
     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'))
 
+        parent = parents[0]
+        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
+
         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 +490,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 +534,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.
 
--- a/tests/test-transplant.t	Thu Apr 12 20:22:18 2012 -0500
+++ b/tests/test-transplant.t	Tue Apr 10 23:24:12 2012 -0700
@@ -424,3 +424,57 @@
   a\r (esc)
   b\r (esc)
   $ cd ..
+
+test transplant with merge changeset is skipped
+
+  $ hg init merge1a
+  $ cd merge1a
+  $ echo a > a
+  $ hg ci -Am a
+  adding a
+  $ hg branch b
+  marked working directory as branch b
+  (branches are permanent and global, did you want a bookmark?)
+  $ hg ci -m branchb
+  $ echo b > b
+  $ hg ci -Am b
+  adding b
+  $ hg update default
+  0 files updated, 0 files merged, 1 files removed, 0 files unresolved
+  $ hg merge b
+  1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+  (branch merge, don't forget to commit)
+  $ hg ci -m mergeb
+  $ cd ..
+
+  $ hg init merge1b
+  $ cd merge1b
+  $ hg transplant -s ../merge1a tip
+
+test transplant with merge changeset accepts --parent
+
+  $ hg init merge2a
+  $ cd merge2a
+  $ echo a > a
+  $ hg ci -Am a
+  adding a
+  $ hg branch b
+  marked working directory as branch b
+  (branches are permanent and global, did you want a bookmark?)
+  $ hg ci -m branchb
+  $ echo b > b
+  $ hg ci -Am b
+  adding b
+  $ hg update default
+  0 files updated, 0 files merged, 1 files removed, 0 files unresolved
+  $ hg merge b
+  1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+  (branch merge, don't forget to commit)
+  $ hg ci -m mergeb
+  $ cd ..
+
+  $ hg init merge2b
+  $ cd merge2b
+  $ hg transplant -s ../merge2a --parent 0 tip
+  applying be9f9b39483f
+  be9f9b39483f transplanted to 9959e51f94d1