Rev 3797: CommitBuilder.record_iter_changes handles changed-in-branch directories. in http://people.ubuntu.com/~robertc/baz2.0/commit-iterchanges

Robert Collins robertc at robertcollins.net
Tue Dec 2 04:24:59 GMT 2008


At http://people.ubuntu.com/~robertc/baz2.0/commit-iterchanges

------------------------------------------------------------
revno: 3797
revision-id: robertc at robertcollins.net-20081202042455-a6okdxpxxn378vnz
parent: robertc at robertcollins.net-20081202030120-vjnhyq08x1v0yg6l
committer: Robert Collins <robertc at robertcollins.net>
branch nick: commit-iterchanges
timestamp: Tue 2008-12-02 15:24:55 +1100
message:
  CommitBuilder.record_iter_changes handles changed-in-branch directories.
modified:
  bzrlib/repository.py           rev_storage.py-20051111201905-119e9401e46257e3
  bzrlib/tests/per_repository/test_commit_builder.py test_commit_builder.py-20060606110838-76e3ra5slucqus81-1
=== modified file 'bzrlib/repository.py'
--- a/bzrlib/repository.py	2008-12-02 02:43:39 +0000
+++ b/bzrlib/repository.py	2008-12-02 04:24:55 +0000
@@ -532,6 +532,9 @@
         # file_id -> change map, change is fileid, paths, changed, versioneds,
         # parents, names, kinds, executables
         merged_ids = {}
+        # file_id -> revision_id -> inventory entry, for entries in parent
+        # trees that are not parents[0]
+        parent_entries = {}
         if len(self.parents) > 1:
             revtrees = list(self.repository.revision_trees(self.parents))
             repo_basis = revtrees[0]
@@ -547,8 +550,10 @@
                                 change[3].revision]
                         else:
                             merged_ids[change[2]] = [change[3].revision]
+                        parent_entries[change[2]] = {change[3].revision:change[3]}
                     else:
                         merged_ids[change[2]].append(change[3].revision)
+                        parent_entries[change[2]][change[3].revision] = change[3]
         else:
             merged_ids = {}
         changes= {}
@@ -558,7 +563,11 @@
                 change[0], [basis_inv[change[0]].revision])
         unchanged_merged = set(merged_ids) - set(changes)
         for file_id in unchanged_merged:
-            # Record a merged version with the current content from basis.
+            # Record a merged version of these items that did not change vs the
+            # basis. This can be either identical parallel changes, or a revert
+            # of a specific file after a merge. The recorded content will be
+            # that of the current tree (which is the same as the basis), but
+            # the per-file graph will reflect a merge.
             # NB:XXX: We are reconstructing path information we had, this
             # should be preserved instead.
             # inv delta  change: (file_id, (path_in_source, path_in_target),
@@ -582,6 +591,13 @@
         modified_rev = self._new_revision_id
         for change, head_candidates in changes.values():
             if change[3][1]: # versioned in target.
+                # Several things may be happening here:
+                # We may have a fork in the per-file graph
+                #  - record a change with the content from tree
+                # We may have a change against < all trees  
+                #  - carry over the tree that hasn't changed
+                # We may have a change against all trees
+                #  - record the change with the content from tree
                 kind = change[6][1]
                 file_id = change[0]
                 entry = _entry_factory[kind](file_id, change[5][1],
@@ -593,10 +609,37 @@
                     if head_candidate in head_set:
                         heads.append(head_candidate)
                         head_set.remove(head_candidate)
-                # Populate the entry
-                if change[2]:
-                    # From disk.
-                    if kind == 'file':
+                carried_over = False
+                if len(heads) == 1 and len(head_candidates) > 1:
+                    # Could be a carry-over situation:
+                    parent_entry = parent_entries[file_id].get(heads[0], None)
+                    if parent_entry is None:
+                        # The parent iter_changes was called against is the one
+                        # that is the per-file head, so any change is relevant
+                        # iter_changes is valid.
+                        carry_over_possible = False
+                    else:
+                        # could be a carry over situation
+                        # A change against the basis may just indicate a merge,
+                        # we need to check the content against the source of the
+                        # merge to determine if it was changed after the merge
+                        # or carried over.
+                        if (parent_entry.parent_id != entry.parent_id or
+                            parent_entry.name != entry.name):
+                            # Metadata common to all entries has changed
+                            # against per-file parent
+                            carry_over_possible = False
+                        else:
+                            carry_over_possible = True
+                        # per-type checks for changes against the parent_entry
+                        # are done below.
+                else:
+                    # Cannot be a carry-over situation
+                    carry_over_possible = False
+                # Populate the entry in the delta
+                if kind == 'file':
+                    if change[2]:
+                        # From disk.
                         if change[7][0]:
                             entry.executable = True
                         else:
@@ -609,21 +652,8 @@
                             file_obj.close()
                         entry.text_sha1, entry.text_size = self._add_text_to_weave(
                             file_id, lines, heads, None)
-                    elif kind == 'symlink':
-                        # Wants a path hint?
-                        entry.symlink_target = tree.get_symlink_target(file_id)
-                        self._add_text_to_weave(change[0], [], heads, None)
-                    elif kind == 'directory':
-                        # Nothing to set.
-                        import pdb;pdb.set_trace()
-                        pass
-                    elif kind == 'tree-reference':
-                        import pdb;pdb.set_trace()
                     else:
-                        raise AssertionError('unknown kind %r' % kind)
-                else:
-                    # From basis.
-                    if kind == 'file':
+                        # From basis.
                         if change[7][1]:
                             entry.executable = True
                         else:
@@ -635,19 +665,30 @@
                             basis_file.close()
                         entry.text_sha1, entry.text_size = self._add_text_to_weave(
                             file_id, lines, heads, None)
-                    elif kind == 'symlink':
+                elif kind == 'symlink':
+                    if change[2]:
+                        # Wants a path hint?
+                        entry.symlink_target = tree.get_symlink_target(file_id)
+                        self._add_text_to_weave(change[0], [], heads, None)
+                    else:
                         entry.symlink_target = basis_inv[file_id].symlink_target
                         self._add_text_to_weave(change[0], [], heads, None)
-                    elif kind == 'directory':
+                elif kind == 'directory':
+                    if carry_over_possible:
+                        carried_over = True
+                        entry.revision = parent_entry.revision
+                    else:
                         # Nothing to set on the entry.
                         # XXX: split into the Root and nonRoot versions.
                         if change[1][1] != '' or self.repository.supports_rich_root():
                             self._add_text_to_weave(change[0], [], heads, None)
-                    elif kind == 'tree-reference':
+                elif kind == 'tree-reference':
+                    if change[2]:
                         import pdb;pdb.set_trace()
-                    else:
+                else:
                         raise AssertionError('unknown kind %r' % kind)
-                entry.revision = modified_rev
+                if not carried_over:
+                    entry.revision = modified_rev
             else:
                 entry = None
             new_path = change[1][1]

=== modified file 'bzrlib/tests/per_repository/test_commit_builder.py'
--- a/bzrlib/tests/per_repository/test_commit_builder.py	2008-12-02 03:01:20 +0000
+++ b/bzrlib/tests/per_repository/test_commit_builder.py	2008-12-02 04:24:55 +0000
@@ -755,14 +755,16 @@
                 changes)
             delta = builder.basis_delta
             delta_dict = dict((change[2], change) for change in delta)
-            version_recorded = tree.path2id(new_name) in delta_dict
+            file_id = tree.path2id(new_name)
+            version_recorded = (file_id in delta_dict and
+                delta_dict[file_id][3] is not None and
+                delta_dict[file_id][3].revision == builder._new_revision_id)
             if records_version:
                 self.assertTrue(version_recorded)
             else:
                 self.assertFalse(version_recorded)
             builder.finish_inventory()
             new_inventory = builder.revision_tree().inventory
-            file_id = tree.path2id(new_name)
             new_entry = new_inventory[file_id]
             if delta_against_basis:
                 expected_delta = (name, new_name, file_id, new_entry)
@@ -899,12 +901,18 @@
         self._commit_sprout_rename_merge(tree1, 'link',
             mini_commit=self.mini_commit_record_iter_changes)
 
-    def _commit_sprout_rename_merge_converged(self, tree1, name):
+    def _commit_sprout_rename_merge_converged(self, tree1, name,
+        mini_commit=None):
+        # Make a merge which just incorporates a change from a branch:
+        # The per-file graph is straight line, and no alteration occurs
+        # in the inventory.
         rev1, tree2 = self._commit_sprout(tree1, name)
         # change on the other side to merge back
         rev2 = self._rename_in_tree(tree2, name)
         tree1.merge_from_branch(tree2.branch)
-        rev3 = self.mini_commit(tree1, name, 'new_' + name, False)
+        if mini_commit is None:
+            mini_commit = self.mini_commit
+        rev3 = mini_commit(tree1, name, 'new_' + name, False)
         tree3, = self._get_revtrees(tree1, [rev2])
         self.assertEqual(rev2, tree3.inventory[name + 'id'].revision)
         file_id = name + 'id'
@@ -919,6 +927,13 @@
         self.build_tree(['t1/dir/'])
         self._commit_sprout_rename_merge_converged(tree1, 'dir')
 
+    def test_last_modified_revision_after_converged_merge_dir_changes_ric(self):
+        # merge a dir changes the last modified.
+        tree1 = self.make_branch_and_tree('t1')
+        self.build_tree(['t1/dir/'])
+        self._commit_sprout_rename_merge_converged(tree1, 'dir',
+            mini_commit=self.mini_commit_record_iter_changes)
+
     def test_last_modified_revision_after_converged_merge_file_changes(self):
         # merge a file changes the last modified.
         tree1 = self.make_branch_and_tree('t1')




More information about the bazaar-commits mailing list