~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/workingtree.py

  • Committer: Vincent Ladeuil
  • Date: 2010-02-08 16:36:13 UTC
  • mto: (5029.2.1 integration2)
  • mto: This revision was merged to the branch mainline in revision 5031.
  • Revision ID: v.ladeuil+lp@free.fr-20100208163613-9sgl3ugvdxapwgw8
``bzr add`` won't blindly add conflict related files.

* bzrlib/tests/per_workingtree/test_smart_add.py:
(TestSmartAddConflictRelatedFiles): Make sure we don't add blindly
but that we can add on demand.

* bzrlib/mutabletree.py:
(MutableTree.smart_add): Check that we don't, implicitly, add a
file generated to help resolve a conflict.

* bzrlib/conflicts.py:
(Conflict.associated_filenames): New helper.
(Conflict.cleanup): Use the helper to reduce duplication.
(PathConflict, ContentsConflict, TextConflict, HandledConflict):
Define associated_filenames instead of cleanup.

Show diffs side-by-side

added added

removed removed

Lines of Context:
29
29
WorkingTree.open(dir).
30
30
"""
31
31
 
 
32
# TODO: Give the workingtree sole responsibility for the working inventory;
 
33
# remove the variable and references to it from the branch.  This may require
 
34
# updating the commit code so as to update the inventory within the working
 
35
# copy, and making sure there's only one WorkingTree for any directory on disk.
 
36
# At the moment they may alias the inventory and have old copies of it in
 
37
# memory.  (Now done? -- mbp 20060309)
32
38
 
33
39
from cStringIO import StringIO
34
40
import os
95
101
from bzrlib.filters import filtered_input_file
96
102
from bzrlib.trace import mutter, note
97
103
from bzrlib.transport.local import LocalTransport
 
104
from bzrlib.progress import DummyProgress, ProgressPhase
98
105
from bzrlib.revision import CURRENT_REVISION
99
106
from bzrlib.rio import RioReader, rio_file, Stanza
100
107
from bzrlib.symbol_versioning import (
167
174
        return ''
168
175
 
169
176
 
170
 
class WorkingTree(bzrlib.mutabletree.MutableTree,
171
 
    bzrdir.ControlComponent):
 
177
class WorkingTree(bzrlib.mutabletree.MutableTree):
172
178
    """Working copy tree.
173
179
 
174
180
    The inventory is held in the `Branch` working-inventory, and the
247
253
        self._rules_searcher = None
248
254
        self.views = self._make_views()
249
255
 
250
 
    @property
251
 
    def user_transport(self):
252
 
        return self.bzrdir.user_transport
253
 
 
254
 
    @property
255
 
    def control_transport(self):
256
 
        return self._transport
257
 
 
258
256
    def _detect_case_handling(self):
259
257
        wt_trans = self.bzrdir.get_workingtree_transport(None)
260
258
        try:
914
912
            branch.last_revision().
915
913
        """
916
914
        from bzrlib.merge import Merger, Merge3Merger
917
 
        merger = Merger(self.branch, this_tree=self)
918
 
        # check that there are no local alterations
919
 
        if not force and self.has_changes():
920
 
            raise errors.UncommittedChanges(self)
921
 
        if to_revision is None:
922
 
            to_revision = _mod_revision.ensure_null(branch.last_revision())
923
 
        merger.other_rev_id = to_revision
924
 
        if _mod_revision.is_null(merger.other_rev_id):
925
 
            raise errors.NoCommits(branch)
926
 
        self.branch.fetch(branch, last_revision=merger.other_rev_id)
927
 
        merger.other_basis = merger.other_rev_id
928
 
        merger.other_tree = self.branch.repository.revision_tree(
929
 
            merger.other_rev_id)
930
 
        merger.other_branch = branch
931
 
        if from_revision is None:
932
 
            merger.find_base()
933
 
        else:
934
 
            merger.set_base_revision(from_revision, branch)
935
 
        if merger.base_rev_id == merger.other_rev_id:
936
 
            raise errors.PointlessMerge
937
 
        merger.backup_files = False
938
 
        if merge_type is None:
939
 
            merger.merge_type = Merge3Merger
940
 
        else:
941
 
            merger.merge_type = merge_type
942
 
        merger.set_interesting_files(None)
943
 
        merger.show_base = False
944
 
        merger.reprocess = False
945
 
        conflicts = merger.do_merge()
946
 
        merger.set_pending()
 
915
        pb = ui.ui_factory.nested_progress_bar()
 
916
        try:
 
917
            merger = Merger(self.branch, this_tree=self, pb=pb)
 
918
            merger.pp = ProgressPhase("Merge phase", 5, pb)
 
919
            merger.pp.next_phase()
 
920
            # check that there are no local alterations
 
921
            if not force and self.has_changes():
 
922
                raise errors.UncommittedChanges(self)
 
923
            if to_revision is None:
 
924
                to_revision = _mod_revision.ensure_null(branch.last_revision())
 
925
            merger.other_rev_id = to_revision
 
926
            if _mod_revision.is_null(merger.other_rev_id):
 
927
                raise errors.NoCommits(branch)
 
928
            self.branch.fetch(branch, last_revision=merger.other_rev_id)
 
929
            merger.other_basis = merger.other_rev_id
 
930
            merger.other_tree = self.branch.repository.revision_tree(
 
931
                merger.other_rev_id)
 
932
            merger.other_branch = branch
 
933
            merger.pp.next_phase()
 
934
            if from_revision is None:
 
935
                merger.find_base()
 
936
            else:
 
937
                merger.set_base_revision(from_revision, branch)
 
938
            if merger.base_rev_id == merger.other_rev_id:
 
939
                raise errors.PointlessMerge
 
940
            merger.backup_files = False
 
941
            if merge_type is None:
 
942
                merger.merge_type = Merge3Merger
 
943
            else:
 
944
                merger.merge_type = merge_type
 
945
            merger.set_interesting_files(None)
 
946
            merger.show_base = False
 
947
            merger.reprocess = False
 
948
            conflicts = merger.do_merge()
 
949
            merger.set_pending()
 
950
        finally:
 
951
            pb.finished()
947
952
        return conflicts
948
953
 
949
954
    @needs_read_lock
1096
1101
        tree_transport = self.bzrdir.root_transport.clone(sub_path)
1097
1102
        if tree_transport.base != branch_transport.base:
1098
1103
            tree_bzrdir = format.initialize_on_transport(tree_transport)
1099
 
            branch.BranchReferenceFormat().initialize(tree_bzrdir,
1100
 
                target_branch=new_branch)
 
1104
            branch.BranchReferenceFormat().initialize(tree_bzrdir, new_branch)
1101
1105
        else:
1102
1106
            tree_bzrdir = branch_bzrdir
1103
1107
        wt = tree_bzrdir.create_workingtree(_mod_revision.NULL_REVISION)
1141
1145
        This does not include files that have been deleted in this
1142
1146
        tree. Skips the control directory.
1143
1147
 
1144
 
        :param include_root: if True, return an entry for the root
 
1148
        :param include_root: if True, do not return an entry for the root
1145
1149
        :param from_dir: start from this directory or None for the root
1146
1150
        :param recursive: whether to recurse into subdirectories or not
1147
1151
        """
1601
1605
    @needs_write_lock
1602
1606
    def pull(self, source, overwrite=False, stop_revision=None,
1603
1607
             change_reporter=None, possible_transports=None, local=False):
 
1608
        top_pb = ui.ui_factory.nested_progress_bar()
1604
1609
        source.lock_read()
1605
1610
        try:
 
1611
            pp = ProgressPhase("Pull phase", 2, top_pb)
 
1612
            pp.next_phase()
1606
1613
            old_revision_info = self.branch.last_revision_info()
1607
1614
            basis_tree = self.basis_tree()
1608
1615
            count = self.branch.pull(source, overwrite, stop_revision,
1610
1617
                                     local=local)
1611
1618
            new_revision_info = self.branch.last_revision_info()
1612
1619
            if new_revision_info != old_revision_info:
 
1620
                pp.next_phase()
1613
1621
                repository = self.branch.repository
 
1622
                pb = ui.ui_factory.nested_progress_bar()
1614
1623
                basis_tree.lock_read()
1615
1624
                try:
1616
1625
                    new_basis_tree = self.branch.basis_tree()
1619
1628
                                new_basis_tree,
1620
1629
                                basis_tree,
1621
1630
                                this_tree=self,
1622
 
                                pb=None,
 
1631
                                pb=pb,
1623
1632
                                change_reporter=change_reporter)
1624
1633
                    basis_root_id = basis_tree.get_root_id()
1625
1634
                    new_root_id = new_basis_tree.get_root_id()
1626
1635
                    if basis_root_id != new_root_id:
1627
1636
                        self.set_root_id(new_root_id)
1628
1637
                finally:
 
1638
                    pb.finished()
1629
1639
                    basis_tree.unlock()
1630
1640
                # TODO - dedup parents list with things merged by pull ?
1631
1641
                # reuse the revisiontree we merged against to set the new
1644
1654
            return count
1645
1655
        finally:
1646
1656
            source.unlock()
 
1657
            top_pb.finished()
1647
1658
 
1648
1659
    @needs_write_lock
1649
1660
    def put_file_bytes_non_atomic(self, file_id, bytes):
2058
2069
 
2059
2070
    @needs_tree_write_lock
2060
2071
    def revert(self, filenames=None, old_tree=None, backups=True,
2061
 
               pb=None, report_changes=False):
 
2072
               pb=DummyProgress(), report_changes=False):
2062
2073
        from bzrlib.conflicts import resolve
2063
2074
        if filenames == []:
2064
2075
            filenames = None
2253
2264
        # We MUST save it even if an error occurs, because otherwise the users
2254
2265
        # local work is unreferenced and will appear to have been lost.
2255
2266
        #
2256
 
        nb_conflicts = 0
 
2267
        result = 0
2257
2268
        try:
2258
2269
            last_rev = self.get_parent_ids()[0]
2259
2270
        except IndexError:
2260
2271
            last_rev = _mod_revision.NULL_REVISION
2261
2272
        if revision is None:
2262
2273
            revision = self.branch.last_revision()
2263
 
 
2264
 
        old_tip = old_tip or _mod_revision.NULL_REVISION
2265
 
 
2266
 
        if not _mod_revision.is_null(old_tip) and old_tip != last_rev:
2267
 
            # the branch we are bound to was updated
2268
 
            # merge those changes in first
2269
 
            base_tree  = self.basis_tree()
2270
 
            other_tree = self.branch.repository.revision_tree(old_tip)
2271
 
            nb_conflicts = merge.merge_inner(self.branch, other_tree,
2272
 
                                             base_tree, this_tree=self,
2273
 
                                             change_reporter=change_reporter)
2274
 
            if nb_conflicts:
2275
 
                self.add_parent_tree((old_tip, other_tree))
2276
 
                trace.note('Rerun update after fixing the conflicts.')
2277
 
                return nb_conflicts
2278
 
 
 
2274
        else:
 
2275
            if revision not in self.branch.revision_history():
 
2276
                raise errors.NoSuchRevision(self.branch, revision)
2279
2277
        if last_rev != _mod_revision.ensure_null(revision):
2280
 
            # the working tree is up to date with the branch
2281
 
            # we can merge the specified revision from master
2282
 
            to_tree = self.branch.repository.revision_tree(revision)
2283
 
            to_root_id = to_tree.get_root_id()
2284
 
 
 
2278
            # merge tree state up to specified revision.
2285
2279
            basis = self.basis_tree()
2286
2280
            basis.lock_read()
2287
2281
            try:
 
2282
                to_tree = self.branch.repository.revision_tree(revision)
 
2283
                to_root_id = to_tree.get_root_id()
2288
2284
                if (basis.inventory.root is None
2289
2285
                    or basis.inventory.root.file_id != to_root_id):
2290
2286
                    self.set_root_id(to_root_id)
2291
2287
                    self.flush()
 
2288
                result += merge.merge_inner(
 
2289
                                      self.branch,
 
2290
                                      to_tree,
 
2291
                                      basis,
 
2292
                                      this_tree=self,
 
2293
                                      change_reporter=change_reporter)
 
2294
                self.set_last_revision(revision)
2292
2295
            finally:
2293
2296
                basis.unlock()
2294
 
 
2295
 
            # determine the branch point
2296
 
            graph = self.branch.repository.get_graph()
2297
 
            base_rev_id = graph.find_unique_lca(self.branch.last_revision(),
2298
 
                                                last_rev)
2299
 
            base_tree = self.branch.repository.revision_tree(base_rev_id)
2300
 
 
2301
 
            nb_conflicts = merge.merge_inner(self.branch, to_tree, base_tree,
2302
 
                                             this_tree=self,
2303
 
                                             change_reporter=change_reporter)
2304
 
            self.set_last_revision(revision)
2305
2297
            # TODO - dedup parents list with things merged by pull ?
2306
2298
            # reuse the tree we've updated to to set the basis:
2307
2299
            parent_trees = [(revision, to_tree)]
2314
2306
            for parent in merges:
2315
2307
                parent_trees.append(
2316
2308
                    (parent, self.branch.repository.revision_tree(parent)))
2317
 
            if not _mod_revision.is_null(old_tip):
 
2309
            if (old_tip is not None and not _mod_revision.is_null(old_tip)):
2318
2310
                parent_trees.append(
2319
2311
                    (old_tip, self.branch.repository.revision_tree(old_tip)))
2320
2312
            self.set_parent_trees(parent_trees)
2321
2313
            last_rev = parent_trees[0][0]
2322
 
        return nb_conflicts
 
2314
        else:
 
2315
            # the working tree had the same last-revision as the master
 
2316
            # branch did. We may still have pivot local work from the local
 
2317
            # branch into old_tip:
 
2318
            if (old_tip is not None and not _mod_revision.is_null(old_tip)):
 
2319
                self.add_parent_tree_id(old_tip)
 
2320
        if (old_tip is not None and not _mod_revision.is_null(old_tip)
 
2321
            and old_tip != last_rev):
 
2322
            # our last revision was not the prior branch last revision
 
2323
            # and we have converted that last revision to a pending merge.
 
2324
            # base is somewhere between the branch tip now
 
2325
            # and the now pending merge
 
2326
 
 
2327
            # Since we just modified the working tree and inventory, flush out
 
2328
            # the current state, before we modify it again.
 
2329
            # TODO: jam 20070214 WorkingTree3 doesn't require this, dirstate
 
2330
            #       requires it only because TreeTransform directly munges the
 
2331
            #       inventory and calls tree._write_inventory(). Ultimately we
 
2332
            #       should be able to remove this extra flush.
 
2333
            self.flush()
 
2334
            graph = self.branch.repository.get_graph()
 
2335
            base_rev_id = graph.find_unique_lca(revision, old_tip)
 
2336
            base_tree = self.branch.repository.revision_tree(base_rev_id)
 
2337
            other_tree = self.branch.repository.revision_tree(old_tip)
 
2338
            result += merge.merge_inner(
 
2339
                                  self.branch,
 
2340
                                  other_tree,
 
2341
                                  base_tree,
 
2342
                                  this_tree=self,
 
2343
                                  change_reporter=change_reporter)
 
2344
        return result
2323
2345
 
2324
2346
    def _write_hashcache_if_dirty(self):
2325
2347
        """Write out the hashcache if it is dirty."""