29
29
WorkingTree.open(dir).
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)
33
39
from cStringIO import StringIO
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 (
247
253
self._rules_searcher = None
248
254
self.views = self._make_views()
251
def user_transport(self):
252
return self.bzrdir.user_transport
255
def control_transport(self):
256
return self._transport
258
256
def _detect_case_handling(self):
259
257
wt_trans = self.bzrdir.get_workingtree_transport(None)
914
912
branch.last_revision().
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(
930
merger.other_branch = branch
931
if from_revision is None:
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
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()
915
pb = ui.ui_factory.nested_progress_bar()
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(
932
merger.other_branch = branch
933
merger.pp.next_phase()
934
if from_revision is None:
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
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()
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)
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.
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
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()
1611
pp = ProgressPhase("Pull phase", 2, top_pb)
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,
1619
1628
new_basis_tree,
1621
1630
this_tree=self,
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)
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
1798
1809
raise errors.ObjectNotLocked(self)
1800
1811
def lock_read(self):
1801
"""Lock the tree for reading.
1803
This also locks the branch, and can be unlocked via self.unlock().
1805
:return: An object with an unlock method which will release the lock
1812
"""See Branch.lock_read, and WorkingTree.unlock."""
1808
1813
if not self.is_locked():
1809
1814
self._reset_data()
1810
1815
self.branch.lock_read()
1812
self._control_files.lock_read()
1817
return self._control_files.lock_read()
1815
1819
self.branch.unlock()
1818
1822
def lock_tree_write(self):
1819
"""See MutableTree.lock_tree_write, and WorkingTree.unlock.
1821
:return: An object with an unlock method which will release the lock
1823
"""See MutableTree.lock_tree_write, and WorkingTree.unlock."""
1824
1824
if not self.is_locked():
1825
1825
self._reset_data()
1826
1826
self.branch.lock_read()
1828
self._control_files.lock_write()
1828
return self._control_files.lock_write()
1831
1830
self.branch.unlock()
1834
1833
def lock_write(self):
1835
"""See MutableTree.lock_write, and WorkingTree.unlock.
1837
:return: An object with an unlock method which will release the lock
1834
"""See MutableTree.lock_write, and WorkingTree.unlock."""
1840
1835
if not self.is_locked():
1841
1836
self._reset_data()
1842
1837
self.branch.lock_write()
1844
self._control_files.lock_write()
1839
return self._control_files.lock_write()
1847
1841
self.branch.unlock()
2076
2070
@needs_tree_write_lock
2077
2071
def revert(self, filenames=None, old_tree=None, backups=True,
2078
pb=None, report_changes=False):
2072
pb=DummyProgress(), report_changes=False):
2079
2073
from bzrlib.conflicts import resolve
2080
2074
if filenames == []:
2081
2075
filenames = None
2270
2264
# We MUST save it even if an error occurs, because otherwise the users
2271
2265
# local work is unreferenced and will appear to have been lost.
2275
2269
last_rev = self.get_parent_ids()[0]
2276
2270
except IndexError:
2277
2271
last_rev = _mod_revision.NULL_REVISION
2278
2272
if revision is None:
2279
2273
revision = self.branch.last_revision()
2281
old_tip = old_tip or _mod_revision.NULL_REVISION
2283
if not _mod_revision.is_null(old_tip) and old_tip != last_rev:
2284
# the branch we are bound to was updated
2285
# merge those changes in first
2286
base_tree = self.basis_tree()
2287
other_tree = self.branch.repository.revision_tree(old_tip)
2288
nb_conflicts = merge.merge_inner(self.branch, other_tree,
2289
base_tree, this_tree=self,
2290
change_reporter=change_reporter)
2292
self.add_parent_tree((old_tip, other_tree))
2293
trace.note('Rerun update after fixing the conflicts.')
2275
if revision not in self.branch.revision_history():
2276
raise errors.NoSuchRevision(self.branch, revision)
2296
2277
if last_rev != _mod_revision.ensure_null(revision):
2297
# the working tree is up to date with the branch
2298
# we can merge the specified revision from master
2299
to_tree = self.branch.repository.revision_tree(revision)
2300
to_root_id = to_tree.get_root_id()
2278
# merge tree state up to specified revision.
2302
2279
basis = self.basis_tree()
2303
2280
basis.lock_read()
2282
to_tree = self.branch.repository.revision_tree(revision)
2283
to_root_id = to_tree.get_root_id()
2305
2284
if (basis.inventory.root is None
2306
2285
or basis.inventory.root.file_id != to_root_id):
2307
2286
self.set_root_id(to_root_id)
2288
result += merge.merge_inner(
2293
change_reporter=change_reporter)
2294
self.set_last_revision(revision)
2312
# determine the branch point
2313
graph = self.branch.repository.get_graph()
2314
base_rev_id = graph.find_unique_lca(self.branch.last_revision(),
2316
base_tree = self.branch.repository.revision_tree(base_rev_id)
2318
nb_conflicts = merge.merge_inner(self.branch, to_tree, base_tree,
2320
change_reporter=change_reporter)
2321
self.set_last_revision(revision)
2322
2297
# TODO - dedup parents list with things merged by pull ?
2323
2298
# reuse the tree we've updated to to set the basis:
2324
2299
parent_trees = [(revision, to_tree)]
2331
2306
for parent in merges:
2332
2307
parent_trees.append(
2333
2308
(parent, self.branch.repository.revision_tree(parent)))
2334
if not _mod_revision.is_null(old_tip):
2309
if (old_tip is not None and not _mod_revision.is_null(old_tip)):
2335
2310
parent_trees.append(
2336
2311
(old_tip, self.branch.repository.revision_tree(old_tip)))
2337
2312
self.set_parent_trees(parent_trees)
2338
2313
last_rev = parent_trees[0][0]
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
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.
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(
2343
change_reporter=change_reporter)
2341
2346
def _write_hashcache_if_dirty(self):
2342
2347
"""Write out the hashcache if it is dirty."""