diff hggit/git_handler.py @ 406:50698ff64c41

Fix round-trip fidelity for merges of converged files.
author Christian Walther <cwalther@gmx.ch>
date Tue, 24 May 2011 20:04:10 +0200
parents f17ca8ed620c
children 2dcfd4bbfc1a
line wrap: on
line diff
--- a/hggit/git_handler.py	Sun May 22 20:49:17 2011 +0200
+++ b/hggit/git_handler.py	Tue May 24 20:04:10 2011 +0200
@@ -499,14 +499,38 @@
 
         oldenc = self.swap_out_encoding()
 
+        def findconvergedfiles(p1, p2):
+            # If any files have the same contents in both parents of a merge
+            # (and are therefore not reported as changed by Git) but are at
+            # different file revisions in Mercurial (because they arrived at
+            # those contents in different ways), we need to include them in
+            # the list of changed files so that Mercurial can join up their
+            # filelog histories (same as if the merge was done in Mercurial to
+            # begin with).
+            if p2 == nullid:
+                return []
+            manifest1 = self.repo.changectx(p1).manifest()
+            manifest2 = self.repo.changectx(p2).manifest()
+            return [path for path, node1 in manifest1.iteritems()
+                    if path not in files and manifest2.get(path, node1) != node1]
+
         def getfilectx(repo, memctx, f):
-            delete, mode, sha = files[f]
-            if delete:
-                raise IOError
+            info = files.get(f)
+            if info != None:
+                # it's a file reported as modified from Git
+                delete, mode, sha = info
+                if delete:
+                    raise IOError
 
-            data = self.git[sha].data
-            copied_path = hg_renames.get(f)
-            e = self.convert_git_int_mode(mode)
+                data = self.git[sha].data
+                copied_path = hg_renames.get(f)
+                e = self.convert_git_int_mode(mode)
+            else:
+                # it's a converged file
+                fc = context.filectx(self.repo, f, changeid=memctx.p1().rev())
+                data = fc.data()
+                e = fc.flags()
+                copied_path = fc.renamed()
 
             return context.memfilectx(f, data, 'l' in e, 'x' in e, copied_path)
 
@@ -517,8 +541,9 @@
         if len(gparents) > 1:
             # merge, possibly octopus
             def commit_octopus(p1, p2):
-                ctx = context.memctx(self.repo, (p1, p2), text, list(files), getfilectx,
-                                     author, date, {'hg-git': 'octopus'})
+                ctx = context.memctx(self.repo, (p1, p2), text,
+                                     list(files) + findconvergedfiles(p1, p2),
+                                     getfilectx, author, date, {'hg-git': 'octopus'})
                 return hex(self.repo.commitctx(ctx))
 
             octopus = len(gparents) > 2
@@ -567,8 +592,9 @@
         if not (repo_contains(p1) and repo_contains(p2)):
             raise hgutil.Abort(_('you appear to have run strip - '
                                  'please run hg git-cleanup'))
-        ctx = context.memctx(self.repo, (p1, p2), text, list(files), getfilectx,
-                             author, date, extra)
+        ctx = context.memctx(self.repo, (p1, p2), text,
+                             list(files) + findconvergedfiles(p1, p2),
+                             getfilectx, author, date, extra)
 
         node = self.repo.commitctx(ctx)