convert/bzr: correctly handle divergent nested renames (issue3089) stable
authorPatrick Mezard <pmezard@gmail.com>
Tue, 08 Nov 2011 17:08:58 +0100
branchstable
changeset 15461 6ba2fc0a87ab
parent 15430 54c0517c0fe8
child 15462 2b1ec74c961f
convert/bzr: correctly handle divergent nested renames (issue3089) With renames like: a -> b a/c -> a/c We were ignoring or duplicating the second one instead of leaving files unchanged or moving them to their proper destination only. To avoid this, we process the files in reverse lexicographic order, from most to least specific change, and ignore files already processed. v2: - Add a test - Change "reverse=1" into "reverse=True"
hgext/convert/bzr.py
tests/test-convert-bzr-directories.t
--- a/hgext/convert/bzr.py	Fri Nov 04 10:31:38 2011 +0100
+++ b/hgext/convert/bzr.py	Tue Nov 08 17:08:58 2011 +0100
@@ -173,8 +173,14 @@
         revid = current._revision_id
         changes = []
         renames = {}
+        seen = set()
+        # Process the entries by reverse lexicographic name order to
+        # handle nested renames correctly, most specific first.
+        curchanges = sorted(current.iter_changes(origin),
+                            key=lambda c: c[1][0] or c[1][1],
+                            reverse=True)
         for (fileid, paths, changed_content, versioned, parent, name,
-            kind, executable) in current.iter_changes(origin):
+            kind, executable) in curchanges:
 
             if paths[0] == u'' or paths[1] == u'':
                 # ignore changes to tree root
@@ -188,7 +194,8 @@
                     # so it can be removed.
                     changes.append((self.recode(paths[0]), revid))
 
-                if None not in paths and paths[0] != paths[1]:
+                if kind[0] == 'directory' and None not in paths:
+                    renaming = paths[0] != paths[1]
                     # neither an add nor an delete - a move
                     # rename all directory contents manually
                     subdir = origin.inventory.path2id(paths[0])
@@ -198,6 +205,16 @@
                         if entry.kind == 'directory':
                             continue
                         frompath = self.recode(paths[0] + '/' + name)
+                        if frompath in seen:
+                            # Already handled by a more specific change entry
+                            # This is important when you have:
+                            # a => b
+                            # a/c => a/c
+                            # Here a/c must not be renamed into b/c
+                            continue
+                        seen.add(frompath)
+                        if not renaming:
+                            continue
                         topath = self.recode(paths[1] + '/' + name)
                         # register the files as changed
                         changes.append((frompath, revid))
@@ -215,6 +232,7 @@
 
             # we got unicode paths, need to convert them
             path, topath = [self.recode(part) for part in paths]
+            seen.add(path or topath)
 
             if topath is None:
                 # file deleted
--- a/tests/test-convert-bzr-directories.t	Fri Nov 04 10:31:38 2011 +0100
+++ b/tests/test-convert-bzr-directories.t	Tue Nov 08 17:08:58 2011 +0100
@@ -149,3 +149,45 @@
   644   second/something
   644   third/dummy
   $ cd ..
+
+divergent nested renames (issue3089)
+
+  $ mkdir test-divergent-renames
+  $ cd test-divergent-renames
+  $ bzr init -q source
+  $ cd source
+  $ mkdir -p a/c
+  $ echo a > a/fa
+  $ echo c > a/c/fc
+  $ bzr add -q a
+  $ bzr commit -q -m 'Initial layout'
+  $ bzr mv a b
+  a => b
+  $ mkdir a
+  $ bzr add a
+  adding a
+  $ bzr mv b/c a/c
+  b/c => a/c
+  $ bzr status
+  added:
+    a/
+  renamed:
+    a/ => b/
+    a/c/ => a/c/
+  $ bzr commit -q -m 'Divergent renames'
+  $ cd ..
+  $ hg convert source source-hg
+  initializing destination source-hg repository
+  scanning source...
+  sorting...
+  converting...
+  1 Initial layout
+  0 Divergent renames
+  $ hg -R source-hg st -C --change 1
+  A b/fa
+    a/fa
+  R a/fa
+  $ hg -R source-hg manifest -r 1
+  a/c/fc
+  b/fa
+  $ cd ..