Rev 6059: Fix first half of the bug by producing a 'duplicate' conflict instead of a 'content' one when the file has been replaced in THIS and modified in OTHER. in file:///home/vila/src/bzr/bugs/880701-resolve-duplicate/

Vincent Ladeuil v.ladeuil+lp at free.fr
Wed Oct 26 15:23:50 UTC 2011


At file:///home/vila/src/bzr/bugs/880701-resolve-duplicate/

------------------------------------------------------------
revno: 6059
revision-id: v.ladeuil+lp at free.fr-20111026152349-kgcy2ja8gjti5o1b
parent: v.ladeuil+lp at free.fr-20111026152224-mpk1o7wpz6qbpm5p
committer: Vincent Ladeuil <v.ladeuil+lp at free.fr>
branch nick: 880701-resolve-duplicate
timestamp: Wed 2011-10-26 17:23:49 +0200
message:
  Fix first half of the bug by producing a 'duplicate' conflict instead of a 'content' one when the file has been replaced in THIS and modified in OTHER.
-------------- next part --------------
=== modified file 'bzrlib/merge.py'
--- a/bzrlib/merge.py	2011-07-06 09:22:00 +0000
+++ b/bzrlib/merge.py	2011-10-26 15:23:49 +0000
@@ -591,11 +591,11 @@
                 else:
                     self.base_rev_id = self.revision_graph.find_unique_lca(
                                             *lcas)
-                sorted_lca_keys = self.revision_graph.find_merge_order(                
+                sorted_lca_keys = self.revision_graph.find_merge_order(
                     revisions[0], lcas)
                 if self.base_rev_id == _mod_revision.NULL_REVISION:
                     self.base_rev_id = sorted_lca_keys[0]
-                
+
             if self.base_rev_id == _mod_revision.NULL_REVISION:
                 raise errors.UnrelatedBranches()
             if self._is_criss_cross:
@@ -604,7 +604,8 @@
                 trace.mutter('Criss-cross lcas: %r' % lcas)
                 if self.base_rev_id in lcas:
                     trace.mutter('Unable to find unique lca. '
-                                 'Fallback %r as best option.' % self.base_rev_id)
+                                 'Fallback %r as best option.'
+                                 % self.base_rev_id)
                 interesting_revision_ids = set(lcas)
                 interesting_revision_ids.add(self.base_rev_id)
                 interesting_trees = dict((t.get_revision_id(), t)
@@ -689,7 +690,8 @@
                     continue
                 sub_merge = Merger(sub_tree.branch, this_tree=sub_tree)
                 sub_merge.merge_type = self.merge_type
-                other_branch = self.other_branch.reference_parent(file_id, relpath)
+                other_branch = self.other_branch.reference_parent(file_id,
+                                                                  relpath)
                 sub_merge.set_other_revision(other_revision, other_branch)
                 base_revision = self.base_tree.get_reference_revision(file_id)
                 sub_merge.base_tree = \
@@ -1387,18 +1389,35 @@
             if hook_status != 'not_applicable':
                 # Don't try any more hooks, this one applies.
                 break
+        keep_this = False
         result = "modified"
         if hook_status == 'not_applicable':
-            # This is a contents conflict, because none of the available
-            # functions could merge it.
             result = None
             name = self.tt.final_name(trans_id)
             parent_id = self.tt.final_parent(trans_id)
-            if self.this_tree.has_id(file_id):
-                self.tt.unversion_file(trans_id)
-            file_group = self._dump_conflicts(name, parent_id, file_id,
-                                              set_version=True)
-            self._raw_conflicts.append(('contents conflict', file_group))
+            duplicate = False
+            this_kind = this_pair[0]
+            if this_kind is None: # file_id is not in this
+                # Is the name used for a different file_id ?
+                dupe_path = self.other_tree.id2path(file_id)
+                this_id = self.this_tree.path2id(dupe_path)
+                duplicate = this_id is not None
+            if duplicate:
+                # Two entries for the same path
+                keep_this = True
+                # versioning the merged file will trigger a duplicate conflict
+                self.tt.version_file(file_id, trans_id)
+                transform.create_from_tree(
+                    self.tt, trans_id, self.other_tree, file_id,
+                    filter_tree_path=self._get_filter_tree_path(file_id))
+            else:
+                if this_kind is not None:
+                    self.tt.unversion_file(trans_id)
+                # This is a contents conflict, because none of the available
+                # functions could merge it.
+                file_group = self._dump_conflicts(name, parent_id, file_id,
+                                                  set_version=True)
+                self._raw_conflicts.append(('contents conflict', file_group))
         elif hook_status == 'success':
             self.tt.create_file(lines, trans_id)
         elif hook_status == 'conflicted':
@@ -1420,36 +1439,23 @@
             raise AssertionError('unknown hook_status: %r' % (hook_status,))
         if not self.this_tree.has_id(file_id) and result == "modified":
             self.tt.version_file(file_id, trans_id)
-        # The merge has been performed, so the old contents should not be
-        # retained.
-        self.tt.delete_contents(trans_id)
+        if not keep_this:
+            # The merge has been performed, so the old contents should not be
+            # retained.
+            self.tt.delete_contents(trans_id)
         return result
 
     def _default_other_winner_merge(self, merge_hook_params):
         """Replace this contents with other."""
         file_id = merge_hook_params.file_id
         trans_id = merge_hook_params.trans_id
-        file_in_this = self.this_tree.has_id(file_id)
         if self.other_tree.has_id(file_id):
             # OTHER changed the file
-            wt = self.this_tree
-            if wt.supports_content_filtering():
-                # We get the path from the working tree if it exists.
-                # That fails though when OTHER is adding a file, so
-                # we fall back to the other tree to find the path if
-                # it doesn't exist locally.
-                try:
-                    filter_tree_path = wt.id2path(file_id)
-                except errors.NoSuchId:
-                    filter_tree_path = self.other_tree.id2path(file_id)
-            else:
-                # Skip the id2path lookup for older formats
-                filter_tree_path = None
-            transform.create_from_tree(self.tt, trans_id,
-                             self.other_tree, file_id,
-                             filter_tree_path=filter_tree_path)
+            transform.create_from_tree(
+                self.tt, trans_id, self.other_tree, file_id,
+                filter_tree_path=self._get_filter_tree_path(file_id))
             return 'done', None
-        elif file_in_this:
+        elif self.this_tree.has_id(file_id):
             # OTHER deleted the file
             return 'delete', None
         else:
@@ -1529,6 +1535,23 @@
                                               other_lines)
             file_group.append(trans_id)
 
+
+    def _get_filter_tree_path(self, file_id):
+        wt = self.this_tree
+        if wt.supports_content_filtering():
+            # We get the path from the working tree if it exists.
+            # That fails though when OTHER is adding a file, so
+            # we fall back to the other tree to find the path if
+            # it doesn't exist locally.
+            try:
+                filter_tree_path = wt.id2path(file_id)
+            except errors.NoSuchId:
+                filter_tree_path = self.other_tree.id2path(file_id)
+        else:
+            # Skip the id2path lookup for older formats
+            filter_tree_path = None
+        return filter_tree_path
+
     def _dump_conflicts(self, name, parent_id, file_id, this_lines=None,
                         base_lines=None, other_lines=None, set_version=False,
                         no_base=False):
@@ -1652,10 +1675,12 @@
                 for trans_id in conflict[1]:
                     file_id = self.tt.final_file_id(trans_id)
                     if file_id is not None:
+                        # Ok we found the relevant file-id
                         break
                 path = fp.get_path(trans_id)
                 for suffix in ('.BASE', '.THIS', '.OTHER'):
                     if path.endswith(suffix):
+                        # Here is the raw path
                         path = path[:-len(suffix)]
                         break
                 c = _mod_conflicts.Conflict.factory(conflict_type,



More information about the bazaar-commits mailing list