Rev 2770: Merge bzr.dev via the commit branch. in http://people.ubuntu.com/~robertc/baz2.0/repository

Robert Collins robertc at robertcollins.net
Fri Sep 21 07:25:09 BST 2007


At http://people.ubuntu.com/~robertc/baz2.0/repository

------------------------------------------------------------
revno: 2770
revision-id: robertc at robertcollins.net-20070921062446-thh851c7u8d1o6xn
parent: robertc at robertcollins.net-20070921013648-i9w180g6ea73w9mf
parent: robertc at robertcollins.net-20070921061031-p945q13ra1jjcli2
committer: Robert Collins <robertc at robertcollins.net>
branch nick: repository
timestamp: Fri 2007-09-21 16:24:46 +1000
message:
  Merge bzr.dev via the commit branch.
modified:
  NEWS                           NEWS-20050323055033-4e00b5db738777ff
  bzrlib/commit.py               commit.py-20050511101309-79ec1a0168e0e825
  bzrlib/dirstate.py             dirstate.py-20060728012006-d6mvoihjb3je9peu-1
  bzrlib/inventory.py            inventory.py-20050309040759-6648b84ca2005b37
  bzrlib/osutils.py              osutils.py-20050309040759-eeaff12fbf77ac86
  bzrlib/repository.py           rev_storage.py-20051111201905-119e9401e46257e3
  bzrlib/tests/inventory_implementations/basics.py basics.py-20070903044446-kdjwbiu1p1zi9phs-1
  bzrlib/tests/repository_implementations/test_commit_builder.py test_commit_builder.py-20060606110838-76e3ra5slucqus81-1
  bzrlib/tests/test_osutils.py   test_osutils.py-20051201224856-e48ee24c12182989
  bzrlib/tests/workingtree_implementations/test_commit.py test_commit.py-20060421013633-1610ec2331c8190f
  bzrlib/workingtree_4.py        workingtree_4.py-20070208044105-5fgpc5j3ljlh5q6c-1
    ------------------------------------------------------------
    revno: 2592.1.25.2.7.1.28.1.6.1.3.1.9.2.1.3.74.1.51
    revision-id: robertc at robertcollins.net-20070921061031-p945q13ra1jjcli2
    parent: robertc at robertcollins.net-20070917061036-fzr1h7zs9b3rr573
    parent: pqm at pqm.ubuntu.com-20070921051316-85muv96iv0duh31j
    committer: Robert Collins <robertc at robertcollins.net>
    branch nick: commit
    timestamp: Fri 2007-09-21 16:10:31 +1000
    message:
      Merge bzr.dev.
    added:
      bzrlib/reconfigure.py          reconfigure.py-20070908040425-6ykgo7escxhyrg9p-1
      bzrlib/tests/blackbox/test_reconfigure.py test_reconfigure.py-20070908173426-khfo5fi2rgzgtwj3-1
      bzrlib/tests/test_reconfigure.py test_reconfigure.py-20070908040425-6ykgo7escxhyrg9p-2
      doc/developers/authentication-ring.txt authring.txt-20070718200437-q5tdik0ne6lor86d-1
    modified:
      NEWS                           NEWS-20050323055033-4e00b5db738777ff
      bzrlib/annotate.py             annotate.py-20050922133147-7c60541d2614f022
      bzrlib/builtins.py             builtins.py-20050830033751-fc01482b9ca23183
      bzrlib/bzrdir.py               bzrdir.py-20060131065624-156dfea39c4387cb
      bzrlib/commit.py               commit.py-20050511101309-79ec1a0168e0e825
      bzrlib/dirstate.py             dirstate.py-20060728012006-d6mvoihjb3je9peu-1
      bzrlib/errors.py               errors.py-20050309040759-20512168c4e14fbd
      bzrlib/index.py                index.py-20070712131115-lolkarso50vjr64s-1
      bzrlib/inventory.py            inventory.py-20050309040759-6648b84ca2005b37
      bzrlib/knit.py                 knit.py-20051212171256-f056ac8f0fbe1bd9
      bzrlib/merge.py                merge.py-20050513021216-953b65a438527106
      bzrlib/osutils.py              osutils.py-20050309040759-eeaff12fbf77ac86
      bzrlib/remote.py               remote.py-20060720103555-yeeg2x51vn0rbtdp-1
      bzrlib/repository.py           rev_storage.py-20051111201905-119e9401e46257e3
      bzrlib/symbol_versioning.py    symbol_versioning.py-20060105104851-9ecf8af605d15a80
      bzrlib/tests/HttpServer.py     httpserver.py-20061012142527-m1yxdj1xazsf8d7s-1
      bzrlib/tests/__init__.py       selftest.py-20050531073622-8d0e3c8845c97a64
      bzrlib/tests/blackbox/__init__.py __init__.py-20051128053524-eba30d8255e08dc3
      bzrlib/tests/blackbox/test_commit.py test_commit.py-20060212094538-ae88fc861d969db0
      bzrlib/tests/blackbox/test_log.py test_log.py-20060112090212-78f6ea560c868e24
      bzrlib/tests/blackbox/test_merge.py test_merge.py-20060323225809-9bc0459c19917f41
      bzrlib/tests/blackbox/test_missing.py test_missing.py-20051211212735-a2cf4c1840bb84c4
      bzrlib/tests/bzrdir_implementations/test_bzrdir.py test_bzrdir.py-20060131065642-0ebeca5e30e30866
      bzrlib/tests/interversionedfile_implementations/test_join.py test_join.py-20060302012326-9b5e9b0f0a03fedc
      bzrlib/tests/inventory_implementations/basics.py basics.py-20070903044446-kdjwbiu1p1zi9phs-1
      bzrlib/tests/repository_implementations/test_commit_builder.py test_commit_builder.py-20060606110838-76e3ra5slucqus81-1
      bzrlib/tests/test_commit.py    test_commit.py-20050914060732-279f057f8c295434
      bzrlib/tests/test_osutils.py   test_osutils.py-20051201224856-e48ee24c12182989
      bzrlib/tests/test_sftp_transport.py testsftp.py-20051027032739-247570325fec7e7e
      bzrlib/tests/test_symbol_versioning.py test_symbol_versioning.py-20060105104851-51d7722c2018d42b
      bzrlib/tests/test_versionedfile.py test_versionedfile.py-20060222045249-db45c9ed14a1c2e5
      bzrlib/tests/test_weave.py     testknit.py-20050627023648-9833cc5562ffb785
      bzrlib/tests/transport_util.py transportutil.py-20070525113600-5v2igk89s8fensom-1
      bzrlib/tests/workingtree_implementations/test_commit.py test_commit.py-20060421013633-1610ec2331c8190f
      bzrlib/transport/ftp.py        ftp.py-20051116161804-58dc9506548c2a53
      bzrlib/tuned_gzip.py           tuned_gzip.py-20060407014720-5aadc518e928e8d2
      bzrlib/versionedfile.py        versionedfile.py-20060222045106-5039c71ee3b65490
      bzrlib/weave.py                knit.py-20050627021749-759c29984154256b
      bzrlib/workingtree_4.py        workingtree_4.py-20070208044105-5fgpc5j3ljlh5q6c-1
      doc/developers/HACKING.txt     HACKING-20050805200004-2a5dc975d870f78c
    ------------------------------------------------------------
    revno: 2592.1.25.2.7.1.28.1.6.1.3.1.9.2.1.3.74.1.31.3.18.1.9.1.2.1.12.1.8.1.19
    revision-id: pqm at pqm.ubuntu.com-20070921051316-85muv96iv0duh31j
    parent: pqm at pqm.ubuntu.com-20070921031326-72zmv08871klgb61
    parent: ian.clatworthy at internode.on.net-20070921042253-eguu8ycfjbnb96yj
    committer: Canonical.com Patch Queue Manager <pqm at pqm.ubuntu.com>
    branch nick: +trunk
    timestamp: Fri 2007-09-21 06:13:16 +0100
    message:
      Faster partial commits by walking less data (Robert Collins)
    modified:
      NEWS                           NEWS-20050323055033-4e00b5db738777ff
      bzrlib/commit.py               commit.py-20050511101309-79ec1a0168e0e825
      bzrlib/dirstate.py             dirstate.py-20060728012006-d6mvoihjb3je9peu-1
      bzrlib/inventory.py            inventory.py-20050309040759-6648b84ca2005b37
      bzrlib/osutils.py              osutils.py-20050309040759-eeaff12fbf77ac86
      bzrlib/tests/inventory_implementations/basics.py basics.py-20070903044446-kdjwbiu1p1zi9phs-1
      bzrlib/tests/test_osutils.py   test_osutils.py-20051201224856-e48ee24c12182989
      bzrlib/workingtree_4.py        workingtree_4.py-20070208044105-5fgpc5j3ljlh5q6c-1
        ------------------------------------------------------------
        revno: 2592.1.25.2.7.1.28.1.6.1.3.1.9.2.1.3.74.1.31.3.18.1.9.1.2.1.12.1.8.1.18.1.1
        revision-id: ian.clatworthy at internode.on.net-20070921042253-eguu8ycfjbnb96yj
        parent: pqm at pqm.ubuntu.com-20070921031326-72zmv08871klgb61
        parent: robertc at robertcollins.net-20070920070333-eedxrxidkignx4i1
        committer: Ian Clatworthy <ian.clatworthy at internode.on.net>
        branch nick: ianc-integration2
        timestamp: Fri 2007-09-21 14:22:53 +1000
        message:
          Faster partial commits by walking less data (Robert Collins)
        modified:
          NEWS                           NEWS-20050323055033-4e00b5db738777ff
          bzrlib/commit.py               commit.py-20050511101309-79ec1a0168e0e825
          bzrlib/dirstate.py             dirstate.py-20060728012006-d6mvoihjb3je9peu-1
          bzrlib/inventory.py            inventory.py-20050309040759-6648b84ca2005b37
          bzrlib/osutils.py              osutils.py-20050309040759-eeaff12fbf77ac86
          bzrlib/tests/inventory_implementations/basics.py basics.py-20070903044446-kdjwbiu1p1zi9phs-1
          bzrlib/tests/test_osutils.py   test_osutils.py-20051201224856-e48ee24c12182989
          bzrlib/workingtree_4.py        workingtree_4.py-20070208044105-5fgpc5j3ljlh5q6c-1
        ------------------------------------------------------------
        revno: 2592.1.25.2.7.1.28.1.6.1.3.1.9.2.1.3.74.1.31.3.18.1.9.1.2.1.12.1.8.7.1
        revision-id: robertc at robertcollins.net-20070920070333-eedxrxidkignx4i1
        parent: pqm at pqm.ubuntu.com-20070917005035-cshdkpzbj63id1uw
        committer: Robert Collins <robertc at robertcollins.net>
        branch nick: commit-specific-file-handling
        timestamp: Thu 2007-09-20 17:03:33 +1000
        message:
          * Partial commits are now approximately 40% faster by walking over the
            unselected current tree more efficiently. (Robert Collins)
          
          * New method ``bzrlib.osutils.minimum_path_selection`` useful for removing
            duplication from user input, when a user mentions both a path and an item
            contained within that path. (Robert Collins)
          
          * New parameter yield_parents on ``Inventory.iter_entries_by_dir`` which
            causes the parents of a selected id to be returned recursively, so all the
            paths from the root down to each element of selected_file_ids are
            returned. (Robert Collins)
        modified:
          NEWS                           NEWS-20050323055033-4e00b5db738777ff
          bzrlib/commit.py               commit.py-20050511101309-79ec1a0168e0e825
          bzrlib/dirstate.py             dirstate.py-20060728012006-d6mvoihjb3je9peu-1
          bzrlib/inventory.py            inventory.py-20050309040759-6648b84ca2005b37
          bzrlib/osutils.py              osutils.py-20050309040759-eeaff12fbf77ac86
          bzrlib/tests/blackbox/test_commit.py test_commit.py-20060212094538-ae88fc861d969db0
          bzrlib/tests/inventory_implementations/basics.py basics.py-20070903044446-kdjwbiu1p1zi9phs-1
          bzrlib/tests/test_commit.py    test_commit.py-20050914060732-279f057f8c295434
          bzrlib/tests/test_osutils.py   test_osutils.py-20051201224856-e48ee24c12182989
          bzrlib/workingtree_4.py        workingtree_4.py-20070208044105-5fgpc5j3ljlh5q6c-1
    ------------------------------------------------------------
    revno: 2592.1.25.2.7.1.28.1.6.1.3.1.9.2.1.3.74.1.31.3.18.1.9.1.2.1.12.1.8.1.18
    revision-id: pqm at pqm.ubuntu.com-20070921031326-72zmv08871klgb61
    parent: pqm at pqm.ubuntu.com-20070921022023-cgeid5vrxco9o4jo
    parent: ian.clatworthy at internode.on.net-20070921010021-mr4nx4o0vrvhwu4r
    committer: Canonical.com Patch Queue Manager <pqm at pqm.ubuntu.com>
    branch nick: +trunk
    timestamp: Fri 2007-09-21 04:13:26 +0100
    message:
      Make WorkingTree.rename_one honour our normalisation requirements (Robert Collins)
    modified:
      NEWS                           NEWS-20050323055033-4e00b5db738777ff
      bzrlib/dirstate.py             dirstate.py-20060728012006-d6mvoihjb3je9peu-1
      bzrlib/inventory.py            inventory.py-20050309040759-6648b84ca2005b37
      bzrlib/tests/test_workingtree_4.py test_workingtree_4.p-20070223025758-531n3tznl3zacv2o-1
      bzrlib/tests/workingtree_implementations/test_rename_one.py test_rename_one.py-20070226161242-2d8ibdedl700jgio-1
        ------------------------------------------------------------
        revno: 2592.1.25.2.7.1.28.1.6.1.3.1.9.2.1.3.74.1.31.3.18.1.9.1.2.1.12.1.8.1.16.1.1
        revision-id: ian.clatworthy at internode.on.net-20070921010021-mr4nx4o0vrvhwu4r
        parent: pqm at pqm.ubuntu.com-20070921005024-anlkzk5nrdtujta4
        parent: robertc at robertcollins.net-20070917053356-05fyvmd1b3xalx6h
        committer: Ian Clatworthy <ian.clatworthy at internode.on.net>
        branch nick: ianc-integration2
        timestamp: Fri 2007-09-21 11:00:21 +1000
        message:
          Make WorkingTree.rename_one honour our normalisation requirements (Robert Collins)
        modified:
          NEWS                           NEWS-20050323055033-4e00b5db738777ff
          bzrlib/dirstate.py             dirstate.py-20060728012006-d6mvoihjb3je9peu-1
          bzrlib/inventory.py            inventory.py-20050309040759-6648b84ca2005b37
          bzrlib/tests/test_workingtree_4.py test_workingtree_4.p-20070223025758-531n3tznl3zacv2o-1
          bzrlib/tests/workingtree_implementations/test_rename_one.py test_rename_one.py-20070226161242-2d8ibdedl700jgio-1
    ------------------------------------------------------------
    revno: 2592.1.25.2.7.1.28.1.6.1.3.1.9.2.1.3.74.1.31.3.18.1.9.1.2.1.12.1.8.1.17
    revision-id: pqm at pqm.ubuntu.com-20070921022023-cgeid5vrxco9o4jo
    parent: pqm at pqm.ubuntu.com-20070921005024-anlkzk5nrdtujta4
    parent: ian.clatworthy at internode.on.net-20070921002235-u5lbs3wog6na1qxg
    committer: Canonical.com Patch Queue Manager <pqm at pqm.ubuntu.com>
    branch nick: +trunk
    timestamp: Fri 2007-09-21 03:20:23 +0100
    message:
      faster pointless commit detection (Robert Collins)
    modified:
      NEWS                           NEWS-20050323055033-4e00b5db738777ff
      bzrlib/commit.py               commit.py-20050511101309-79ec1a0168e0e825
      bzrlib/inventory.py            inventory.py-20050309040759-6648b84ca2005b37
      bzrlib/repository.py           rev_storage.py-20051111201905-119e9401e46257e3
      bzrlib/tests/repository_implementations/test_commit_builder.py test_commit_builder.py-20060606110838-76e3ra5slucqus81-1
      bzrlib/tests/workingtree_implementations/test_commit.py test_commit.py-20060421013633-1610ec2331c8190f
    ------------------------------------------------------------
    revno: 2592.1.25.2.7.1.28.1.6.1.3.1.9.2.1.3.74.1.31.3.18.1.9.1.2.1.12.1.8.1.15.1.1
    revision-id: ian.clatworthy at internode.on.net-20070921002235-u5lbs3wog6na1qxg
    parent: pqm at pqm.ubuntu.com-20070920235505-6w61gqyajy9i0ioj
    parent: robertc at robertcollins.net-20070920075948-6f32d46hr3oyw4zb
    committer: Ian Clatworthy <ian.clatworthy at internode.on.net>
    branch nick: ianc-integration
    timestamp: Fri 2007-09-21 10:22:35 +1000
    message:
      faster pointless commit detection (Robert Collins)
    modified:
      NEWS                           NEWS-20050323055033-4e00b5db738777ff
      bzrlib/commit.py               commit.py-20050511101309-79ec1a0168e0e825
      bzrlib/inventory.py            inventory.py-20050309040759-6648b84ca2005b37
      bzrlib/repository.py           rev_storage.py-20051111201905-119e9401e46257e3
      bzrlib/tests/repository_implementations/test_commit_builder.py test_commit_builder.py-20060606110838-76e3ra5slucqus81-1
      bzrlib/tests/workingtree_implementations/test_commit.py test_commit.py-20060421013633-1610ec2331c8190f
    ------------------------------------------------------------
    revno: 2592.1.25.2.7.1.28.1.6.1.3.1.9.2.1.3.74.1.31.3.18.1.9.1.2.1.12.1.8.6.2
    revision-id: robertc at robertcollins.net-20070920075948-6f32d46hr3oyw4zb
    parent: robertc at robertcollins.net-20070920034311-lgjoomiumagdhksn
    committer: Robert Collins <robertc at robertcollins.net>
    branch nick: record-entry-returns-status
    timestamp: Thu 2007-09-20 17:59:48 +1000
    message:
      Review feedback, and fix pointless commits with nested trees to raise PointlessCommit appropriately.
    modified:
      NEWS                           NEWS-20050323055033-4e00b5db738777ff
      bzrlib/commit.py               commit.py-20050511101309-79ec1a0168e0e825
      bzrlib/inventory.py            inventory.py-20050309040759-6648b84ca2005b37
      bzrlib/repository.py           rev_storage.py-20051111201905-119e9401e46257e3
      bzrlib/tests/workingtree_implementations/test_commit.py test_commit.py-20060421013633-1610ec2331c8190f
    ------------------------------------------------------------
    revno: 2592.1.25.2.7.1.28.1.6.1.3.1.9.2.1.3.74.1.31.3.18.1.9.1.2.1.12.1.8.6.1
    revision-id: robertc at robertcollins.net-20070920034311-lgjoomiumagdhksn
    parent: pqm at pqm.ubuntu.com-20070917005035-cshdkpzbj63id1uw
    committer: Robert Collins <robertc at robertcollins.net>
    branch nick: record-entry-returns-status
    timestamp: Thu 2007-09-20 13:43:11 +1000
    message:
      * Committing a change which is not a merge and does not change the number of
        files in the tree is faster by utilising the data about whether files are
        changed to determine if a the tree is unchanged rather than recalculating
        it at the end of the commit process. (Robert Collins)
    modified:
      NEWS                           NEWS-20050323055033-4e00b5db738777ff
      bzrlib/commit.py               commit.py-20050511101309-79ec1a0168e0e825
      bzrlib/repository.py           rev_storage.py-20051111201905-119e9401e46257e3
      bzrlib/tests/repository_implementations/test_commit_builder.py test_commit_builder.py-20060606110838-76e3ra5slucqus81-1
=== modified file 'NEWS'
--- a/NEWS	2007-09-21 01:36:48 +0000
+++ b/NEWS	2007-09-21 06:24:46 +0000
@@ -32,9 +32,17 @@
    * Commit in quiet mode is now slightly faster as the information to
      output is no longer calculated. (Ian Clatworthy)
 
+   * Committing a change which is not a merge and does not change the number of
+     files in the tree is faster by utilising the data about whether files are
+     changed to determine if the tree is unchanged rather than recalculating
+     it at the end of the commit process. (Robert Collins)
+
    * Inventory serialisation no longer double-sha's the content.
      (Robert Collins)
 
+   * Partial commits are now approximately 40% faster by walking over the
+     unselected current tree more efficiently. (Robert Collins)
+
    * XML inventory serialisation takes 20% less time while being stricter about
      the contents. (Robert Collins)
 
@@ -91,6 +99,10 @@
 
   INTERNALS:
 
+   * New method ``bzrlib.osutils.minimum_path_selection`` useful for removing
+     duplication from user input, when a user mentions both a path and an item
+     contained within that path. (Robert Collins)
+
    * New method on ``bzrlib.tree.Tree`` ``path_content_summary`` provides a
      tuple containing the key information about a path for commit processing
      to complete. (Robert Collins)
@@ -102,6 +114,11 @@
      and returns a gzipped version of the same. This is used to avoid a bunch
      of api friction during adding of knit hunks. (Robert Collins)
 
+   * New parameter yield_parents on ``Inventory.iter_entries_by_dir`` which
+     causes the parents of a selected id to be returned recursively, so all the
+     paths from the root down to each element of selected_file_ids are
+     returned. (Robert Collins)
+
   TESTING:
 
 

=== modified file 'bzrlib/commit.py'
--- a/bzrlib/commit.py	2007-09-21 00:27:04 +0000
+++ b/bzrlib/commit.py	2007-09-21 06:24:46 +0000
@@ -68,8 +68,9 @@
                            ConflictsInTree,
                            StrictCommitFailed
                            )
-from bzrlib.osutils import (kind_marker, isdir,isfile, is_inside_any, 
+from bzrlib.osutils import (kind_marker, isdir,isfile, is_inside_any,
                             is_inside_or_parent_of_any,
+                            minimum_path_selection,
                             quotefn, sha_file, split_lines)
 from bzrlib.testament import Testament
 from bzrlib.trace import mutter, note, warning, is_quiet
@@ -241,11 +242,18 @@
                                " parameter is required for commit().")
 
         self.bound_branch = None
+        self.any_entries_changed = False
+        self.any_entries_deleted = False
         self.local = local
         self.master_branch = None
         self.master_locked = False
         self.rev_id = None
-        self.specific_files = specific_files
+        if specific_files is not None:
+            self.specific_files = sorted(
+                minimum_path_selection(specific_files))
+        else:
+            self.specific_files = None
+        self.specific_file_ids = None
         self.allow_pointless = allow_pointless
         self.revprops = revprops
         self.message_callback = message_callback
@@ -279,14 +287,16 @@
                 self.config = self.branch.get_config()
 
             # If provided, ensure the specified files are versioned
-            if specific_files is not None:
-                # Note: We don't actually need the IDs here. This routine
-                # is being called because it raises PathNotVerisonedError
-                # as a side effect of finding the IDs.
+            if self.specific_files is not None:
+                # Note: This routine is being called because it raises
+                # PathNotVerisonedError as a side effect of finding the IDs. We
+                # later use the ids we found as input to the working tree
+                # inventory iterator, so we only consider those ids rather than
+                # examining the whole tree again.
                 # XXX: Dont we have filter_unversioned to do this more
                 # cheaply?
-                tree.find_ids_across_trees(specific_files,
-                                           [self.basis_tree, self.work_tree])
+                self.specific_file_ids = tree.find_ids_across_trees(
+                    specific_files, [self.basis_tree, self.work_tree])
 
             # Setup the progress bar. As the number of files that need to be
             # committed in unknown, progress is reported as stages.
@@ -384,41 +394,6 @@
             return NullCommitReporter()
         return ReportCommitToLog()
 
-    def _any_real_changes(self):
-        """Are there real changes between new_inventory and basis?
-
-        For trees without rich roots, inv.root.revision changes every commit.
-        But if that is the only change, we want to treat it as though there
-        are *no* changes.
-        """
-        new_entries = self.builder.new_inventory.iter_entries()
-        basis_entries = self.basis_inv.iter_entries()
-        new_path, new_root_ie = new_entries.next()
-        basis_path, basis_root_ie = basis_entries.next()
-
-        # This is a copy of InventoryEntry.__eq__ only leaving out .revision
-        def ie_equal_no_revision(this, other):
-            return ((this.file_id == other.file_id)
-                    and (this.name == other.name)
-                    and (this.symlink_target == other.symlink_target)
-                    and (this.text_sha1 == other.text_sha1)
-                    and (this.text_size == other.text_size)
-                    and (this.text_id == other.text_id)
-                    and (this.parent_id == other.parent_id)
-                    and (this.kind == other.kind)
-                    and (this.executable == other.executable)
-                    and (this.reference_revision == other.reference_revision)
-                    )
-        if not ie_equal_no_revision(new_root_ie, basis_root_ie):
-            return True
-
-        for new_ie, basis_ie in zip(new_entries, basis_entries):
-            if new_ie != basis_ie:
-                return True
-
-        # No actual changes present
-        return False
-
     def _check_pointless(self):
         if self.allow_pointless:
             return
@@ -435,7 +410,8 @@
             return
         # If length == 1, then we only have the root entry. Which means
         # that there is no real difference (only the root could be different)
-        if (len(self.builder.new_inventory) != 1 and self._any_real_changes()):
+        if len(self.builder.new_inventory) != 1 and (self.any_entries_changed
+            or self.any_entries_deleted):
             return
         raise PointlessCommit()
 
@@ -672,22 +648,33 @@
         # recorded in their previous state. For more details, see
         # https://lists.ubuntu.com/archives/bazaar/2007q3/028476.html.
         if specific_files:
-            for path, new_ie in self.basis_inv.iter_entries():
-                if new_ie.file_id in self.builder.new_inventory:
+            for path, old_ie in self.basis_inv.iter_entries():
+                if old_ie.file_id in self.builder.new_inventory:
                     # already added - skip.
                     continue
                 if is_inside_any(specific_files, path):
                     # was inside the selected path, if not present it has been
                     # deleted so skip.
                     continue
+                if old_ie.kind == 'directory':
+                    self._next_progress_entry()
                 # not in final inv yet, was not in the selected files, so is an
                 # entry to be preserved unaltered.
-                ie = new_ie.copy()
-                self.builder.record_entry_contents(ie, self.parent_invs, path,
-                                                   self.basis_tree, None)
+                ie = old_ie.copy()
+                # Note: specific file commits after a merge are currently
+                # prohibited. This test is for sanity/safety in case it's
+                # required after that changes.
+                if len(self.parents) > 1:
+                    ie.revision = None
+                if self.builder.record_entry_contents(ie, self.parent_invs, path,
+                    self.basis_tree, None):
+                    self.any_entries_changed = True
 
+        # note that deletes have occurred
+        if set(self.basis_inv._byid.keys()) - set(self.builder.new_inventory._byid.keys()):
+            self.any_entries_deleted = True
         # Report what was deleted.
-        if self.reporter.is_verbose():
+        if self.any_entries_deleted and self.reporter.is_verbose():
             for path, ie in self.basis_inv.iter_entries():
                 if ie.file_id not in self.builder.new_inventory:
                     self.reporter.deleted(path)
@@ -705,7 +692,8 @@
         work_inv = self.work_tree.inventory
         assert work_inv.root is not None
         # XXX: Note that entries may have the wrong kind.
-        entries = work_inv.iter_entries_by_dir()
+        entries = work_inv.iter_entries_by_dir(
+            specific_file_ids=self.specific_file_ids, yield_parents=True)
         if not self.builder.record_root_entry:
             entries.next()
         for path, existing_ie in entries:
@@ -715,7 +703,6 @@
             kind = existing_ie.kind
             if kind == 'directory':
                 self._next_progress_entry()
-
             # Skip files that have been deleted from the working tree.
             # The deleted files/directories are also recorded so they
             # can be explicitly unversioned later. Note that when a
@@ -794,26 +781,17 @@
         content_summary):
         "Record the new inventory entry for a path if any."
         # mutter('check %s {%s}', path, file_id)
-        if (not specific_files or 
-            is_inside_or_parent_of_any(specific_files, path)):
-                # mutter('%s selected for commit', path)
-                if definitely_changed or existing_ie is None:
-                    ie = inventory.make_entry(kind, name, parent_id, file_id)
-                else:
-                    ie = existing_ie.copy()
-                    ie.revision = None
+        # mutter('%s selected for commit', path)
+        if definitely_changed or existing_ie is None:
+            ie = inventory.make_entry(kind, name, parent_id, file_id)
         else:
-            # mutter('%s not selected for commit', path)
-            if self.basis_inv.has_id(file_id):
-                ie = self.basis_inv[file_id].copy()
-            else:
-                # this entry is new and not being committed
-                ie = None
-        if ie is not None:
-            self.builder.record_entry_contents(ie, self.parent_invs,
-                path, self.work_tree, content_summary)
-            if report_changes:
-                self._report_change(ie, path)
+            ie = existing_ie.copy()
+            ie.revision = None
+        if self.builder.record_entry_contents(ie, self.parent_invs,
+            path, self.work_tree, content_summary):
+            self.any_entries_changed = True
+        if report_changes:
+            self._report_change(ie, path)
         return ie
 
     def _report_change(self, ie, path):

=== modified file 'bzrlib/dirstate.py'
--- a/bzrlib/dirstate.py	2007-09-17 05:33:56 +0000
+++ b/bzrlib/dirstate.py	2007-09-21 04:22:53 +0000
@@ -1470,7 +1470,8 @@
         kind = inv_entry.kind
         minikind = DirState._kind_to_minikind[kind]
         tree_data = inv_entry.revision
-        assert len(tree_data) > 0, 'empty revision for the inv_entry.'
+        assert tree_data, 'empty revision for the inv_entry %s.' % \
+            inv_entry.file_id
         if kind == 'directory':
             fingerprint = ''
             size = 0

=== modified file 'bzrlib/inventory.py'
--- a/bzrlib/inventory.py	2007-09-17 06:10:36 +0000
+++ b/bzrlib/inventory.py	2007-09-21 06:10:31 +0000
@@ -809,6 +809,13 @@
     def _forget_tree_state(self):
         self.reference_revision = None 
 
+    def _unchanged(self, previous_ie):
+        """See InventoryEntry._unchanged."""
+        compatible = super(TreeReference, self)._unchanged(previous_ie)
+        if self.reference_revision != previous_ie.reference_revision:
+            compatible = False
+        return compatible
+
 
 class Inventory(object):
     """Inventory of versioned files in a tree.
@@ -934,7 +941,8 @@
                 # if we finished all children, pop it off the stack
                 stack.pop()
 
-    def iter_entries_by_dir(self, from_dir=None, specific_file_ids=None):
+    def iter_entries_by_dir(self, from_dir=None, specific_file_ids=None,
+        yield_parents=False):
         """Iterate over the entries in a directory first order.
 
         This returns all entries for a directory before returning
@@ -942,6 +950,9 @@
         lexicographically sorted order, and is a hybrid between
         depth-first and breadth-first.
 
+        :param yield_parents: If True, yield the parents from the root leading
+            down to specific_file_ids that have been requested. This has no
+            impact if specific_file_ids is None.
         :return: This yields (path, entry) pairs
         """
         if specific_file_ids:
@@ -953,13 +964,14 @@
             if self.root is None:
                 return
             # Optimize a common case
-            if specific_file_ids is not None and len(specific_file_ids) == 1:
+            if (not yield_parents and specific_file_ids is not None and
+                len(specific_file_ids) == 1):
                 file_id = list(specific_file_ids)[0]
                 if file_id in self:
                     yield self.id2path(file_id), self[file_id]
                 return 
             from_dir = self.root
-            if (specific_file_ids is None or 
+            if (specific_file_ids is None or yield_parents or
                 self.root.file_id in specific_file_ids):
                 yield u'', self.root
         elif isinstance(from_dir, basestring):
@@ -994,7 +1006,8 @@
                 child_relpath = cur_relpath + child_name
 
                 if (specific_file_ids is None or 
-                    child_ie.file_id in specific_file_ids):
+                    child_ie.file_id in specific_file_ids or
+                    (yield_parents and child_ie.file_id in parents)):
                     yield child_relpath, child_ie
 
                 if child_ie.kind == 'directory':

=== modified file 'bzrlib/osutils.py'
--- a/bzrlib/osutils.py	2007-09-21 00:27:04 +0000
+++ b/bzrlib/osutils.py	2007-09-21 06:24:46 +0000
@@ -87,6 +87,23 @@
         os.chmod(filename, mod)
 
 
+def minimum_path_selection(paths):
+    """Return the smallset subset of paths which are outside paths.
+
+    :param paths: A container (and hence not None) of paths.
+    :return: A set of paths sufficient to include everything in paths via
+        is_inside_any, drawn from the paths parameter.
+    """
+    search_paths = set()
+    paths = set(paths)
+    for path in paths:
+        other_paths = paths.difference([path])
+        if not is_inside_any(other_paths, path):
+            # this is a top level path, we must check it.
+            search_paths.add(path)
+    return search_paths
+
+
 _QUOTE_RE = None
 
 

=== modified file 'bzrlib/repository.py'
--- a/bzrlib/repository.py	2007-09-20 22:58:47 +0000
+++ b/bzrlib/repository.py	2007-09-21 06:24:46 +0000
@@ -70,6 +70,8 @@
     
     # all clients should supply tree roots.
     record_root_entry = True
+    # the default CommitBuilder does not manage trees whose root is versioned.
+    _versioned_root = False
 
     def __init__(self, repository, parents, config, timestamp=None, 
                  timezone=None, committer=None, revprops=None, 
@@ -221,6 +223,9 @@
             content - stat, length, exec, sha/link target. This is only
             accessed when the entry has a revision of None - that is when it is
             a candidate to commit.
+        :return: True if a new version of the entry has been recorded.
+            (Committing a merge where a file was only changed on the other side
+            will not return True.)
         """
         if self.new_inventory.root is None:
             self._check_root(ie, parent_invs, tree)
@@ -241,10 +246,11 @@
         self.new_inventory.add(ie)
 
         # ie.revision is always None if the InventoryEntry is considered
-        # for committing. ie.snapshot will record the correct revision 
-        # which may be the sole parent if it is untouched.
+        # for committing. We may record the previous parents revision if the
+        # content is actually unchanged against a sole head.
         if ie.revision is not None:
-            return
+            return ie.revision == self._new_revision_id and (path != '' or
+                self._versioned_root)
 
         # XXX: Friction: parent_candidates should return a list not a dict
         #      so that we don't have to walk the inventories again.
@@ -361,6 +367,7 @@
         else:
             raise NotImplementedError('unknown kind')
         ie.revision = self._new_revision_id
+        return True
 
     def _add_text_to_weave(self, file_id, new_lines, parents, nostore_sha):
         versionedfile = self.repository.weave_store.get_weave_or_empty(
@@ -385,6 +392,9 @@
 class RootCommitBuilder(CommitBuilder):
     """This commitbuilder actually records the root id"""
     
+    # the root entry gets versioned properly by this builder.
+    _versioned_root = True
+
     def _check_root(self, ie, parent_invs, tree):
         """Helper for record_entry_contents.
 

=== modified file 'bzrlib/tests/inventory_implementations/basics.py'
--- a/bzrlib/tests/inventory_implementations/basics.py	2007-09-03 04:45:38 +0000
+++ b/bzrlib/tests/inventory_implementations/basics.py	2007-09-20 07:03:33 +0000
@@ -202,6 +202,13 @@
             ], [(path, ie.file_id) for path, ie in inv.iter_entries_by_dir(
                 specific_file_ids=('bye-id',))])
 
+        self.assertEqual([
+            ('', 'tree-root'),
+            ('src', 'src-id'),
+            ('src/bye.c', 'bye-id'),
+            ], [(path, ie.file_id) for path, ie in inv.iter_entries_by_dir(
+                specific_file_ids=('bye-id',), yield_parents=True)])
+
     def test_add_recursive(self):
         parent = InventoryDirectory('src-id', 'src', 'tree-root')
         child = InventoryFile('hello-id', 'hello.c', 'src-id')

=== modified file 'bzrlib/tests/repository_implementations/test_commit_builder.py'
--- a/bzrlib/tests/repository_implementations/test_commit_builder.py	2007-09-21 00:27:04 +0000
+++ b/bzrlib/tests/repository_implementations/test_commit_builder.py	2007-09-21 06:24:46 +0000
@@ -140,6 +140,28 @@
             rev_id = builder.commit('foo bar')
         finally:
             tree.unlock()
+    
+    def test_commit_unchanged_root(self):
+        tree = self.make_branch_and_tree(".")
+        tree.commit('')
+        tree.lock_write()
+        parent_tree = tree.basis_tree()
+        parent_tree.lock_read()
+        self.addCleanup(parent_tree.unlock)
+        builder = tree.branch.get_commit_builder([parent_tree.inventory])
+        try:
+            ie = inventory.make_entry('directory', '', None,
+                    tree.inventory.root.file_id)
+            self.assertFalse(builder.record_entry_contents(
+                ie, [parent_tree.inventory], '', tree,
+                tree.path_content_summary('')))
+            builder.abort()
+        except:
+            builder.abort()
+            tree.unlock()
+            raise
+        else:
+            tree.unlock()
 
     def test_commit(self):
         tree = self.make_branch_and_tree(".")
@@ -301,7 +323,44 @@
         tree.add([name], [name + 'id'])
         rev1 = tree.commit('')
         changer()
-        rev2 = tree.commit('')
+        tree.lock_write()
+        try:
+            # mini manual commit here so we can check the return of
+            # record_entry_contents.
+            builder = tree.branch.get_commit_builder([tree.last_revision()])
+            parent_tree = tree.basis_tree()
+            parent_tree.lock_read()
+            self.addCleanup(parent_tree.unlock)
+            parent_invs = [parent_tree.inventory]
+            # root
+            builder.record_entry_contents(
+                inventory.make_entry('directory', '', None,
+                    tree.inventory.root.file_id), parent_invs, '', tree,
+                    tree.path_content_summary(''))
+            def commit_id(file_id):
+                old_ie = tree.inventory[file_id]
+                path = tree.id2path(file_id)
+                ie = inventory.make_entry(tree.kind(file_id), old_ie.name,
+                    old_ie.parent_id, file_id)
+                return builder.record_entry_contents(ie, parent_invs, path,
+                    tree, tree.path_content_summary(path))
+
+            file_id = name + 'id'
+            parent_id = tree.inventory[file_id].parent_id
+            if parent_id != tree.inventory.root.file_id:
+                commit_id(parent_id)
+            # because a change of some sort is meant to have occurred,
+            # recording the entry must return True.
+            self.assertTrue(commit_id(file_id))
+            builder.finish_inventory()
+            rev2 = builder.commit('')
+            tree.set_parent_ids([rev2])
+        except:
+            builder.abort()
+            tree.unlock()
+            raise
+        else:
+            tree.unlock()
         tree1, tree2 = self._get_revtrees(tree, [rev1, rev2])
         self.assertEqual(rev1, tree1.inventory[name + 'id'].revision)
         self.assertEqual(rev2, tree2.inventory[name + 'id'].revision)

=== modified file 'bzrlib/tests/test_osutils.py'
--- a/bzrlib/tests/test_osutils.py	2007-09-04 11:00:30 +0000
+++ b/bzrlib/tests/test_osutils.py	2007-09-20 07:03:33 +0000
@@ -477,6 +477,16 @@
         #       osutils.getcwd() renormalize the path.
         self.assertEndsWith(osutils._win32_getcwd(), u'mu-\xb5')
 
+    def test_minimum_path_selection(self):
+        self.assertEqual(set(),
+            osutils.minimum_path_selection([]))
+        self.assertEqual(set(['a', 'b']),
+            osutils.minimum_path_selection(['a', 'b']))
+        self.assertEqual(set(['a/', 'b']),
+            osutils.minimum_path_selection(['a/', 'b']))
+        self.assertEqual(set(['a/', 'b']),
+            osutils.minimum_path_selection(['a/c', 'a/', 'b']))
+
     def test_mkdtemp(self):
         tmpdir = osutils._win32_mkdtemp(dir='.')
         self.assertFalse('\\' in tmpdir)

=== modified file 'bzrlib/tests/workingtree_implementations/test_commit.py'
--- a/bzrlib/tests/workingtree_implementations/test_commit.py	2007-08-27 08:38:37 +0000
+++ b/bzrlib/tests/workingtree_implementations/test_commit.py	2007-09-20 07:59:48 +0000
@@ -90,14 +90,14 @@
 
     def test_commit_sets_last_revision(self):
         tree = self.make_branch_and_tree('tree')
-        committed_id = tree.commit('foo', rev_id='foo', allow_pointless=True)
+        committed_id = tree.commit('foo', rev_id='foo')
         self.assertEqual(['foo'], tree.get_parent_ids())
         # the commit should have returned the same id we asked for.
         self.assertEqual('foo', committed_id)
 
     def test_commit_returns_revision_id(self):
         tree = self.make_branch_and_tree('.')
-        committed_id = tree.commit('message', allow_pointless=True)
+        committed_id = tree.commit('message')
         self.assertTrue(tree.branch.repository.has_revision(committed_id))
         self.assertNotEqual(None, committed_id)
 
@@ -323,6 +323,22 @@
             basis.get_reference_revision(basis.path2id('subtree')))
         self.assertNotEqual(rev_id, rev_id2)
 
+    def test_nested_pointless_commits_are_pointless(self):
+        tree = self.make_branch_and_tree('.')
+        if not tree.supports_tree_reference():
+            # inapplicable test.
+            return
+        subtree = self.make_branch_and_tree('subtree')
+        tree.add(['subtree'])
+        # record the reference.
+        rev_id = tree.commit('added reference')
+        child_revid = subtree.last_revision()
+        # now do a no-op commit with allow_pointless=False
+        self.assertRaises(errors.PointlessCommit, tree.commit, '',
+            allow_pointless=False)
+        self.assertEqual(child_revid, subtree.last_revision())
+        self.assertEqual(rev_id, tree.last_revision())
+
 
 class TestCommitProgress(TestCaseWithWorkingTree):
     

=== modified file 'bzrlib/workingtree_4.py'
--- a/bzrlib/workingtree_4.py	2007-09-20 22:58:47 +0000
+++ b/bzrlib/workingtree_4.py	2007-09-21 06:24:46 +0000
@@ -931,12 +931,7 @@
             if not all_versioned:
                 raise errors.PathsNotVersionedError(paths)
         # -- remove redundancy in supplied paths to prevent over-scanning --
-        search_paths = set()
-        for path in paths:
-            other_paths = paths.difference(set([path]))
-            if not osutils.is_inside_any(other_paths, path):
-                # this is a top level path, we must check it.
-                search_paths.add(path)
+        search_paths = osutils.minimum_path_selection(paths)
         # sketch: 
         # for all search_indexs in each path at or under each element of
         # search_paths, if the detail is relocated: add the id, and add the



More information about the bazaar-commits mailing list