Rev 2926: Fix bug #114615 by teaching unversion() to not touch renamed entries. in http://bzr.arbash-meinel.com/branches/bzr/0.92-dev/bogus_removal_114615

John Arbash Meinel john at arbash-meinel.com
Tue Oct 23 22:11:41 BST 2007


At http://bzr.arbash-meinel.com/branches/bzr/0.92-dev/bogus_removal_114615

------------------------------------------------------------
revno: 2926
revision-id:john at arbash-meinel.com-20071023211052-ru4vxnhwb0vpemz4
parent: john at arbash-meinel.com-20071023195147-echbf8brs44uifo4
committer: John Arbash Meinel <john at arbash-meinel.com>
branch nick: bogus_removal_114615
timestamp: Tue 2007-10-23 16:10:52 -0500
message:
  Fix bug #114615 by teaching unversion() to not touch renamed entries.
modified:
  bzrlib/dirstate.py             dirstate.py-20060728012006-d6mvoihjb3je9peu-1
  bzrlib/tests/workingtree_implementations/test_commit.py test_commit.py-20060421013633-1610ec2331c8190f
  bzrlib/workingtree_4.py        workingtree_4.py-20070208044105-5fgpc5j3ljlh5q6c-1
-------------- next part --------------
=== modified file 'bzrlib/dirstate.py'
--- a/bzrlib/dirstate.py	2007-10-23 19:51:47 +0000
+++ b/bzrlib/dirstate.py	2007-10-23 21:10:52 +0000
@@ -1967,10 +1967,7 @@
         # build up paths that this id will be left at after the change is made,
         # so we can update their cross references in tree 0
         all_remaining_keys = set()
-        # If the working tree claims it is present, don't worry about it,
-        # because we are removing it. But if it is a rename, we need to remove
-        # the actual location.
-        details = current_old[1][0]
+        # Dont check the working tree, because it's going.
         for details in current_old[1][1:]:
             if details[0] not in ('a', 'r'): # absent, relocated
                 all_remaining_keys.add(current_old[0])
@@ -2002,6 +1999,8 @@
                 self._find_entry_index(update_key, self._dirblocks[update_block_index][1])
             assert present, 'could not find entry for %s' % (update_key,)
             update_tree_details = self._dirblocks[update_block_index][1][update_entry_index][1]
+            # it must not be absent at the moment
+            assert update_tree_details[0][0] != 'a' # absent
             update_tree_details[0] = DirState.NULL_PARENT_DETAILS
         self._dirblock_state = DirState.IN_MEMORY_MODIFIED
         return last_reference

=== modified file 'bzrlib/tests/workingtree_implementations/test_commit.py'
--- a/bzrlib/tests/workingtree_implementations/test_commit.py	2007-10-23 19:51:47 +0000
+++ b/bzrlib/tests/workingtree_implementations/test_commit.py	2007-10-23 21:10:52 +0000
@@ -21,6 +21,7 @@
 from bzrlib import (
     branch,
     bzrdir,
+    conflicts,
     errors,
     osutils,
     revision as _mod_revision,
@@ -135,6 +136,64 @@
                           ('dir2/a', 'f1-id'),
                          ], paths)
 
+    def test_no_autodelete_alternate_renamed(self):
+        # Test for bug #114615
+        tree_a = self.make_branch_and_tree('A')
+        self.build_tree(['A/a/', 'A/a/m', 'A/a/n'])
+        tree_a.add(['a', 'a/m', 'a/n'], ['a-id', 'm-id', 'n-id'])
+        tree_a.commit('init')
+
+        tree_a.lock_read()
+        try:
+            root_id = tree_a.inventory.root.file_id
+        finally:
+            tree_a.unlock()
+
+        tree_b = tree_a.bzrdir.sprout('B').open_workingtree()
+        self.build_tree(['B/xyz/'])
+        tree_b.add(['xyz'], ['xyz-id'])
+        tree_b.rename_one('a/m', 'xyz/m')
+        osutils.rmtree('B/a')
+        tree_b.commit('delete in B')
+
+        paths = [(path, ie.file_id)
+                 for path, ie in tree_b.iter_entries_by_dir()]
+        self.assertEqual([('', root_id),
+                          ('xyz', 'xyz-id'),
+                          ('xyz/m', 'm-id'),
+                         ], paths)
+
+        self.build_tree_contents([('A/a/n', 'new contents for n\n')])
+        tree_a.commit('change n in A')
+
+        # Merging from A should introduce conflicts because 'n' was modified
+        # and removed, so 'a' needs to be restored.
+        num_conflicts = tree_b.merge_from_branch(tree_a.branch)
+        self.assertEqual(3, num_conflicts)
+        paths = [(path, ie.file_id)
+                 for path, ie in tree_b.iter_entries_by_dir()]
+        self.assertEqual([('', root_id),
+                          ('a', 'a-id'),
+                          ('xyz', 'xyz-id'),
+                          ('a/n.OTHER', 'n-id'),
+                          ('xyz/m', 'm-id'),
+                         ], paths)
+        osutils.rmtree('B/a')
+        try:
+            # bzr resolve --all
+            tree_b.set_conflicts(conflicts.ConflictList())
+        except errors.UnsupportedOperation:
+            # On WT2, set_conflicts is unsupported, but the rmtree has the same
+            # effect.
+            pass
+        tree_b.commit('autoremove a, without touching xyz/m')
+        paths = [(path, ie.file_id)
+                 for path, ie in tree_b.iter_entries_by_dir()]
+        self.assertEqual([('', root_id),
+                          ('xyz', 'xyz-id'),
+                          ('xyz/m', 'm-id'),
+                         ], paths)
+
     def test_commit_sets_last_revision(self):
         tree = self.make_branch_and_tree('tree')
         committed_id = tree.commit('foo', rev_id='foo')

=== modified file 'bzrlib/workingtree_4.py'
--- a/bzrlib/workingtree_4.py	2007-10-17 17:03:06 +0000
+++ b/bzrlib/workingtree_4.py	2007-10-23 21:10:52 +0000
@@ -1189,7 +1189,8 @@
                     # Mark this file id as having been removed
                     entry = block[1][entry_index]
                     ids_to_unversion.discard(entry[0][2])
-                    if (entry[1][0][0] == 'a'
+                    if (entry[1][0][0] in 'ar' # don't remove absent or renamed
+                                               # entries
                         or not state._make_absent(entry)):
                         entry_index += 1
                 # go to the next block. (At the moment we dont delete empty



More information about the bazaar-commits mailing list