Rev 3546: Handle executable bit changes as well. in http://bzr.arbash-meinel.com/branches/bzr/1.7-dev/merge_lca_multi

John Arbash Meinel john at arbash-meinel.com
Wed Jul 30 00:03:09 BST 2008


At http://bzr.arbash-meinel.com/branches/bzr/1.7-dev/merge_lca_multi

------------------------------------------------------------
revno: 3546
revision-id: john at arbash-meinel.com-20080729230216-xt8zje18edlwsnb7
parent: john at arbash-meinel.com-20080729221933-eecf0fzftxi014wc
committer: John Arbash Meinel <john at arbash-meinel.com>
branch nick: merge_lca_multi
timestamp: Tue 2008-07-29 18:02:16 -0500
message:
  Handle executable bit changes as well.
-------------- next part --------------
=== modified file 'bzrlib/merge.py'
--- a/bzrlib/merge.py	2008-07-29 22:19:33 +0000
+++ b/bzrlib/merge.py	2008-07-29 23:02:16 +0000
@@ -760,15 +760,13 @@
                     sha1_winner = Merge3Merger._lca_multi_way(
                         (base_ie.text_sha1, lca_sha1s),
                         other_ie.text_sha1, this_ie.text_sha1)
-                    # XXX: This should be tested before we include it, not
-                    #      sure how to actually get a test written for this.
-                    # exec_winner = Merge3Merger._lca_multi_way(
-                    #     (base_ie.executable, lca_executable),
-                    #     other_ie.executable, this_ie.executable)
+                    exec_winner = Merge3Merger._lca_multi_way(
+                        (base_ie.executable, lca_executable),
+                        other_ie.executable, this_ie.executable)
                     if (parent_id_winner == 'this' and name_winner == 'this'
-                        and sha1_winner == 'this'):
-                        # No kind, parent, name, content change for OTHER, so
-                        # this node is not considered interesting
+                        and sha1_winner == 'this' and exec_winner == 'this'):
+                        # No kind, parent, name, exec, or content change for
+                        # OTHER, so this node is not considered interesting
                         continue
                     if sha1_winner == 'this':
                         content_changed = False

=== modified file 'bzrlib/tests/test_merge.py'
--- a/bzrlib/tests/test_merge.py	2008-07-29 22:19:33 +0000
+++ b/bzrlib/tests/test_merge.py	2008-07-29 23:02:16 +0000
@@ -1446,7 +1446,8 @@
         self.addCleanup(builder.finish_series)
         return builder
 
-    def do_merge(self, builder, other_revision_id):
+    def get_wt_from_builder(self, builder):
+        """Get a real WorkingTree from the builder."""
         the_branch = builder.get_branch()
         wt = the_branch.bzrdir.create_workingtree()
         # XXX: This is a little bit ugly, but we are holding the branch
@@ -1456,6 +1457,10 @@
         wt._branch = the_branch
         wt.lock_write()
         self.addCleanup(wt.unlock)
+        return wt
+
+    def do_merge(self, builder, other_revision_id):
+        wt = self.get_wt_from_builder(builder)
         merger = _mod_merge.Merger.from_revision_ids(progress.DummyProgress(),
             wt, other_revision_id)
         merger.merge_type = _mod_merge.Merge3Merger
@@ -1502,16 +1507,82 @@
         builder.build_snapshot('D-id', ['B-id', 'C-id'], [])
         wt, conflicts = self.do_merge(builder, 'F-id')
         self.assertEqual(0, conflicts)
-        # The merge should have simply update the contents of 'a'
+        # The merge should simply recognize that the final rename takes
+        # precedence
         self.assertEqual('baz', wt.id2path('foo-id'))
 
+    def test_other_deletes_lca_renames(self):
+        # This test would cause a merge conflict, unless we use the lca trees
+        # to determine the real ancestry
+        #   A       Path at 'foo'
+        #  / \
+        # B   C     Path renamed to 'bar' in B
+        # |\ /|
+        # | X |
+        # |/ \|
+        # D   E     Path at 'bar' in D and E
+        #     |
+        #     F     F deletes 'bar'
+        builder = self.get_builder()
+        builder.build_snapshot('A-id', None,
+            [('add', (u'', 'a-root-id', 'directory', None)),
+             ('add', (u'foo', 'foo-id', 'file', 'a\nb\nc\n'))])
+        builder.build_snapshot('C-id', ['A-id'], [])
+        builder.build_snapshot('B-id', ['A-id'],
+            [('rename', ('foo', 'bar'))])
+        builder.build_snapshot('E-id', ['C-id', 'B-id'], # merge the rename
+            [('rename', ('foo', 'bar'))])
+        builder.build_snapshot('F-id', ['E-id'],
+            [('unversion', 'foo-id')])
+        builder.build_snapshot('D-id', ['B-id', 'C-id'], [])
+        wt, conflicts = self.do_merge(builder, 'F-id')
+        self.assertEqual(0, conflicts)
+        self.assertRaises(errors.NoSuchId, wt.id2path, 'foo-id')
+
+    def test_executable_changes(self):
+        #   A       Path at 'foo'
+        #  / \
+        # B   C 
+        # |\ /|
+        # | X |
+        # |/ \|
+        # D   E
+        #     |
+        #     F     Executable bit changed
+        builder = self.get_builder()
+        builder.build_snapshot('A-id', None,
+            [('add', (u'', 'a-root-id', 'directory', None)),
+             ('add', (u'foo', 'foo-id', 'file', 'a\nb\nc\n'))])
+        builder.build_snapshot('C-id', ['A-id'], [])
+        builder.build_snapshot('B-id', ['A-id'], [])
+        builder.build_snapshot('D-id', ['B-id', 'C-id'], [])
+        builder.build_snapshot('E-id', ['C-id', 'B-id'], [])
+        # Have to use a real WT, because BranchBuilder doesn't support exec bit
+        wt = self.get_wt_from_builder(builder)
+        tt = transform.TreeTransform(wt)
+        try:
+            tt.set_executability(True, tt.trans_id_tree_file_id('foo-id'))
+            tt.apply()
+        except:
+            tt.finalize()
+            raise
+        self.assertTrue(wt.is_executable('foo-id'))
+        wt.commit('F-id', rev_id='F-id')
+        # Reset to D, so that we can merge F
+        wt.set_parent_ids(['D-id'])
+        wt.branch.set_last_revision_info(3, 'D-id')
+        wt.revert()
+        self.assertFalse(wt.is_executable('foo-id'))
+        conflicts = wt.merge_from_branch(wt.branch, to_revision='F-id')
+        self.assertEqual(0, conflicts)
+        self.assertTrue(wt.is_executable('foo-id'))
+
 
     # TODO: cases to test
     #       simple criss-cross LCAS identical, BASE different
     #       x-x changed from BASE but identical for all LCAs and tips
     #               should be possible with the same trick of 'not-in-base'
     #               using a double criss-cross
-    #       x-x kind-change
     #       x-x LCAs differ, one in ancestry of other for a given file
     #       x-x file missing in LCA
     #       x-x Reverted back to BASE text



More information about the bazaar-commits mailing list