convert: hg.clonebranches must pull missing parents (issue941)
authorPatrick Mezard <pmezard@gmail.com>
Sat, 26 Jan 2008 19:55:04 +0100
changeset 5934 e495f3f35b2d
parent 5920 5df7cb799baf
child 5935 0973501e5f4a
child 5959 0162c6cc045e
convert: hg.clonebranches must pull missing parents (issue941)
hgext/convert/common.py
hgext/convert/convcmd.py
hgext/convert/hg.py
tests/test-convert-clonebranches
tests/test-convert-clonebranches.out
--- a/hgext/convert/common.py	Tue Jan 22 00:16:50 2008 +0100
+++ b/hgext/convert/common.py	Sat Jan 26 19:55:04 2008 +0100
@@ -167,12 +167,11 @@
         tags: {tagname: sink_rev_id, ...}"""
         raise NotImplementedError()
 
-    def setbranch(self, branch, pbranch, parents):
+    def setbranch(self, branch, pbranches):
         """Set the current branch name. Called before the first putfile
         on the branch.
         branch: branch name for subsequent commits
-        pbranch: branch name of parent commit
-        parents: destination revisions of parent"""
+        pbranches: (converted parent revision, parent branch) tuples"""
         pass
 
     def setfilemapmode(self, active):
--- a/hgext/convert/convcmd.py	Tue Jan 22 00:16:50 2008 +0100
+++ b/hgext/convert/convcmd.py	Sat Jan 26 19:55:04 2008 +0100
@@ -222,15 +222,14 @@
             self.mapentry(rev, dest)
             return
         files, copies = changes
-        parents = [self.map[r] for r in commit.parents]
+        pbranches = []
         if commit.parents:
-            prev = commit.parents[0]
-            if prev not in self.commitcache:
-                self.cachecommit(prev)
-            pbranch = self.commitcache[prev].branch
-        else:
-            pbranch = None
-        self.dest.setbranch(commit.branch, pbranch, parents)
+            for prev in commit.parents:
+                if prev not in self.commitcache:
+                    self.cachecommit(prev)
+                pbranches.append((self.map[prev], 
+                                  self.commitcache[prev].branch))
+        self.dest.setbranch(commit.branch, pbranches)
         for f, v in files:
             filenames.append(f)
             try:
@@ -246,6 +245,7 @@
                         # Merely marks that a copy happened.
                         self.dest.copyfile(copyf, f)
 
+        parents = [b[0] for b in pbranches]
         newnode = self.dest.putcommit(filenames, parents, commit)
         self.mapentry(rev, newnode)
 
--- a/hgext/convert/hg.py	Tue Jan 22 00:16:50 2008 +0100
+++ b/hgext/convert/hg.py	Sat Jan 26 19:55:04 2008 +0100
@@ -80,30 +80,43 @@
         except OSError:
             pass
 
-    def setbranch(self, branch, pbranch, parents):
-        if (not self.clonebranches) or (branch == self.lastbranch):
+    def setbranch(self, branch, pbranches):
+        if not self.clonebranches:
             return
 
+        setbranch = (branch != self.lastbranch)
         self.lastbranch = branch
-        self.after()
         if not branch:
             branch = 'default'
-        if not pbranch:
-            pbranch = 'default'
+        pbranches = [(b[0], b[1] and b[1] or 'default') for b in pbranches]
+        pbranch = pbranches and pbranches[0][1] or 'default'
 
         branchpath = os.path.join(self.path, branch)
-        try:
-            self.repo = hg.repository(self.ui, branchpath)
-        except:
-            if not parents:
+        if setbranch:
+            self.after()
+            try:
+                self.repo = hg.repository(self.ui, branchpath)
+            except:
                 self.repo = hg.repository(self.ui, branchpath, create=True)
-            else:
-                self.ui.note(_('cloning branch %s to %s\n') % (pbranch, branch))
-                hg.clone(self.ui, os.path.join(self.path, pbranch),
-                         branchpath, rev=parents, update=False,
-                         stream=True)
-                self.repo = hg.repository(self.ui, branchpath)
-        self.before()
+            self.before()
+
+        # pbranches may bring revisions from other branches (merge parents)
+        # Make sure we have them, or pull them.
+        missings = {}
+        for b in pbranches:
+            try:
+                self.repo.lookup(b[0])
+            except:
+                missings.setdefault(b[1], []).append(b[0])
+        
+        if missings:
+            self.after()
+            for pbranch, heads in missings.iteritems():
+                pbranchpath = os.path.join(self.path, pbranch)
+                prepo = hg.repository(self.ui, pbranchpath)
+                self.ui.note(_('pulling from %s into %s\n') % (pbranch, branch))
+                self.repo.pull(prepo, [prepo.lookup(h) for h in heads])
+            self.before()
 
     def putcommit(self, files, parents, commit):
         seen = {}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/test-convert-clonebranches	Sat Jan 26 19:55:04 2008 +0100
@@ -0,0 +1,54 @@
+#!/bin/sh
+
+echo "[extensions]" >> $HGRCPATH
+echo "hgext.convert = " >> $HGRCPATH
+echo "[convert]" >> $HGRCPATH
+echo "hg.tagsbranch=0" >> $HGRCPATH
+
+hg init source
+cd source
+echo a > a
+hg ci -qAm adda
+# Add a merge with one parent in the same branch
+echo a >> a
+hg ci -qAm changea
+hg up -qC 0
+hg branch branch0
+echo b > b
+hg ci -qAm addb
+hg up -qC
+hg merge
+hg ci -qm mergeab
+hg tag -ql mergeab
+cd ..
+
+# Miss perl... sometimes
+cat > filter.py <<EOF
+import sys, re
+
+r = re.compile(r'^(?:\d+|pulling from)')
+sys.stdout.writelines([l for l in sys.stdin if r.search(l)])
+EOF
+
+echo % convert
+hg convert -v --config convert.hg.clonebranches=1 source dest |
+    python filter.py
+
+# Add a merge with both parents and child in different branches
+cd source
+hg branch branch1
+echo a > file1
+hg ci -qAm c1
+hg up -qC mergeab
+hg branch branch2
+echo a > file2
+hg ci -qAm c2
+hg merge branch1
+hg branch branch3
+hg ci -qAm c3
+cd ..
+
+echo % incremental conversion
+hg convert -v --config convert.hg.clonebranches=1 source dest |
+    python filter.py
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/test-convert-clonebranches.out	Sat Jan 26 19:55:04 2008 +0100
@@ -0,0 +1,29 @@
+marked working directory as branch branch0
+1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+(branch merge, don't forget to commit)
+% convert
+3 adda
+2 addb
+pulling from default into branch0
+1 changesets found
+1 changea
+0 mergeab
+pulling from default into branch0
+1 changesets found
+marked working directory as branch branch1
+marked working directory as branch branch2
+1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+(branch merge, don't forget to commit)
+marked working directory as branch branch3
+% incremental conversion
+2 c1
+pulling from branch0 into branch1
+2 changesets found
+1 c2
+pulling from branch0 into branch2
+2 changesets found
+0 c3
+pulling from branch2 into branch3
+3 changesets found
+pulling from branch1 into branch3
+1 changesets found