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
96
101
from bzrlib.filters import filtered_input_file
97
102
from bzrlib.trace import mutter, note
98
103
from bzrlib.transport.local import LocalTransport
104
from bzrlib.progress import DummyProgress, ProgressPhase
99
105
from bzrlib.revision import CURRENT_REVISION
100
106
from bzrlib.rio import RioReader, rio_file, Stanza
101
107
from bzrlib.symbol_versioning import (
107
113
MERGE_MODIFIED_HEADER_1 = "BZR merge-modified list format 1"
108
# TODO: Modifying the conflict objects or their type is currently nearly
109
# impossible as there is no clear relationship between the working tree format
110
# and the conflict list file format.
111
114
CONFLICT_HEADER_1 = "BZR conflict list format 1"
113
116
ERROR_PATH_NOT_FOUND = 3 # WindowsError errno code, equivalent to ENOENT
248
250
self._rules_searcher = None
249
251
self.views = self._make_views()
252
def user_transport(self):
253
return self.bzrdir.user_transport
256
def control_transport(self):
257
return self._transport
259
253
def _detect_case_handling(self):
260
254
wt_trans = self.bzrdir.get_workingtree_transport(None)
915
909
branch.last_revision().
917
911
from bzrlib.merge import Merger, Merge3Merger
918
merger = Merger(self.branch, this_tree=self)
919
# check that there are no local alterations
920
if not force and self.has_changes():
921
raise errors.UncommittedChanges(self)
922
if to_revision is None:
923
to_revision = _mod_revision.ensure_null(branch.last_revision())
924
merger.other_rev_id = to_revision
925
if _mod_revision.is_null(merger.other_rev_id):
926
raise errors.NoCommits(branch)
927
self.branch.fetch(branch, last_revision=merger.other_rev_id)
928
merger.other_basis = merger.other_rev_id
929
merger.other_tree = self.branch.repository.revision_tree(
931
merger.other_branch = branch
932
if from_revision is None:
935
merger.set_base_revision(from_revision, branch)
936
if merger.base_rev_id == merger.other_rev_id:
937
raise errors.PointlessMerge
938
merger.backup_files = False
939
if merge_type is None:
940
merger.merge_type = Merge3Merger
942
merger.merge_type = merge_type
943
merger.set_interesting_files(None)
944
merger.show_base = False
945
merger.reprocess = False
946
conflicts = merger.do_merge()
912
pb = ui.ui_factory.nested_progress_bar()
914
merger = Merger(self.branch, this_tree=self, pb=pb)
915
merger.pp = ProgressPhase("Merge phase", 5, pb)
916
merger.pp.next_phase()
917
# check that there are no local alterations
918
if not force and self.has_changes():
919
raise errors.UncommittedChanges(self)
920
if to_revision is None:
921
to_revision = _mod_revision.ensure_null(branch.last_revision())
922
merger.other_rev_id = to_revision
923
if _mod_revision.is_null(merger.other_rev_id):
924
raise errors.NoCommits(branch)
925
self.branch.fetch(branch, last_revision=merger.other_rev_id)
926
merger.other_basis = merger.other_rev_id
927
merger.other_tree = self.branch.repository.revision_tree(
929
merger.other_branch = branch
930
merger.pp.next_phase()
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()
1097
1098
tree_transport = self.bzrdir.root_transport.clone(sub_path)
1098
1099
if tree_transport.base != branch_transport.base:
1099
1100
tree_bzrdir = format.initialize_on_transport(tree_transport)
1100
branch.BranchReferenceFormat().initialize(tree_bzrdir,
1101
target_branch=new_branch)
1101
branch.BranchReferenceFormat().initialize(tree_bzrdir, new_branch)
1103
1103
tree_bzrdir = branch_bzrdir
1104
1104
wt = tree_bzrdir.create_workingtree(_mod_revision.NULL_REVISION)
1142
1142
This does not include files that have been deleted in this
1143
1143
tree. Skips the control directory.
1145
:param include_root: if True, return an entry for the root
1145
:param include_root: if True, do not return an entry for the root
1146
1146
:param from_dir: start from this directory or None for the root
1147
1147
:param recursive: whether to recurse into subdirectories or not
1602
1602
@needs_write_lock
1603
1603
def pull(self, source, overwrite=False, stop_revision=None,
1604
1604
change_reporter=None, possible_transports=None, local=False):
1605
top_pb = ui.ui_factory.nested_progress_bar()
1605
1606
source.lock_read()
1608
pp = ProgressPhase("Pull phase", 2, top_pb)
1607
1610
old_revision_info = self.branch.last_revision_info()
1608
1611
basis_tree = self.basis_tree()
1609
1612
count = self.branch.pull(source, overwrite, stop_revision,
1620
1625
new_basis_tree,
1622
1627
this_tree=self,
1624
1629
change_reporter=change_reporter)
1625
1630
basis_root_id = basis_tree.get_root_id()
1626
1631
new_root_id = new_basis_tree.get_root_id()
1627
1632
if basis_root_id != new_root_id:
1628
1633
self.set_root_id(new_root_id)
1630
1636
basis_tree.unlock()
1631
1637
# TODO - dedup parents list with things merged by pull ?
1632
1638
# reuse the revisiontree we merged against to set the new
1799
1806
raise errors.ObjectNotLocked(self)
1801
1808
def lock_read(self):
1802
"""Lock the tree for reading.
1804
This also locks the branch, and can be unlocked via self.unlock().
1806
:return: A bzrlib.lock.LogicalLockResult.
1809
"""See Branch.lock_read, and WorkingTree.unlock."""
1808
1810
if not self.is_locked():
1809
1811
self._reset_data()
1810
1812
self.branch.lock_read()
1812
self._control_files.lock_read()
1813
return LogicalLockResult(self.unlock)
1814
return self._control_files.lock_read()
1815
1816
self.branch.unlock()
1818
1819
def lock_tree_write(self):
1819
"""See MutableTree.lock_tree_write, and WorkingTree.unlock.
1821
:return: A bzrlib.lock.LogicalLockResult.
1820
"""See MutableTree.lock_tree_write, and WorkingTree.unlock."""
1823
1821
if not self.is_locked():
1824
1822
self._reset_data()
1825
1823
self.branch.lock_read()
1827
self._control_files.lock_write()
1828
return LogicalLockResult(self.unlock)
1825
return self._control_files.lock_write()
1830
1827
self.branch.unlock()
1833
1830
def lock_write(self):
1834
"""See MutableTree.lock_write, and WorkingTree.unlock.
1836
:return: A bzrlib.lock.LogicalLockResult.
1831
"""See MutableTree.lock_write, and WorkingTree.unlock."""
1838
1832
if not self.is_locked():
1839
1833
self._reset_data()
1840
1834
self.branch.lock_write()
1842
self._control_files.lock_write()
1843
return LogicalLockResult(self.unlock)
1836
return self._control_files.lock_write()
1845
1838
self.branch.unlock()
1911
1904
# revision_id is set. We must check for this full string, because a
1912
1905
# root node id can legitimately look like 'revision_id' but cannot
1913
1906
# contain a '"'.
1914
xml = self.branch.repository._get_inventory_xml(new_revision)
1907
xml = self.branch.repository.get_inventory_xml(new_revision)
1915
1908
firstline = xml.split('\n', 1)[0]
1916
1909
if (not 'revision_id="' in firstline or
1917
1910
'format="7"' not in firstline):
1971
1964
def recurse_directory_to_add_files(directory):
1972
1965
# Recurse directory and add all files
1973
1966
# so we can check if they have changed.
1974
for parent_info, file_infos in self.walkdirs(directory):
1967
for parent_info, file_infos in\
1968
self.walkdirs(directory):
1975
1969
for relpath, basename, kind, lstat, fileid, kind in file_infos:
1976
1970
# Is it versioned or ignored?
1977
1971
if self.path2id(relpath) or self.is_ignored(relpath):
2012
2006
# ... but not ignored
2013
2007
has_changed_files = True
2015
elif (content_change and (kind[1] is not None) and
2016
osutils.is_inside_any(files, path[1])):
2017
# Versioned and changed, but not deleted, and still
2018
# in one of the dirs to be deleted.
2009
elif content_change and (kind[1] is not None):
2010
# Versioned and changed, but not deleted
2019
2011
has_changed_files = True
2075
2067
@needs_tree_write_lock
2076
2068
def revert(self, filenames=None, old_tree=None, backups=True,
2077
pb=None, report_changes=False):
2069
pb=DummyProgress(), report_changes=False):
2078
2070
from bzrlib.conflicts import resolve
2079
2071
if filenames == []:
2080
2072
filenames = None
2269
2261
# We MUST save it even if an error occurs, because otherwise the users
2270
2262
# local work is unreferenced and will appear to have been lost.
2274
2266
last_rev = self.get_parent_ids()[0]
2275
2267
except IndexError:
2276
2268
last_rev = _mod_revision.NULL_REVISION
2277
2269
if revision is None:
2278
2270
revision = self.branch.last_revision()
2280
old_tip = old_tip or _mod_revision.NULL_REVISION
2282
if not _mod_revision.is_null(old_tip) and old_tip != last_rev:
2283
# the branch we are bound to was updated
2284
# merge those changes in first
2285
base_tree = self.basis_tree()
2286
other_tree = self.branch.repository.revision_tree(old_tip)
2287
nb_conflicts = merge.merge_inner(self.branch, other_tree,
2288
base_tree, this_tree=self,
2289
change_reporter=change_reporter)
2291
self.add_parent_tree((old_tip, other_tree))
2292
trace.note('Rerun update after fixing the conflicts.')
2272
if revision not in self.branch.revision_history():
2273
raise errors.NoSuchRevision(self.branch, revision)
2295
2274
if last_rev != _mod_revision.ensure_null(revision):
2296
# the working tree is up to date with the branch
2297
# we can merge the specified revision from master
2298
to_tree = self.branch.repository.revision_tree(revision)
2299
to_root_id = to_tree.get_root_id()
2275
# merge tree state up to specified revision.
2301
2276
basis = self.basis_tree()
2302
2277
basis.lock_read()
2279
to_tree = self.branch.repository.revision_tree(revision)
2280
to_root_id = to_tree.get_root_id()
2304
2281
if (basis.inventory.root is None
2305
2282
or basis.inventory.root.file_id != to_root_id):
2306
2283
self.set_root_id(to_root_id)
2285
result += merge.merge_inner(
2290
change_reporter=change_reporter)
2291
self.set_last_revision(revision)
2311
# determine the branch point
2312
graph = self.branch.repository.get_graph()
2313
base_rev_id = graph.find_unique_lca(self.branch.last_revision(),
2315
base_tree = self.branch.repository.revision_tree(base_rev_id)
2317
nb_conflicts = merge.merge_inner(self.branch, to_tree, base_tree,
2319
change_reporter=change_reporter)
2320
self.set_last_revision(revision)
2321
2294
# TODO - dedup parents list with things merged by pull ?
2322
2295
# reuse the tree we've updated to to set the basis:
2323
2296
parent_trees = [(revision, to_tree)]
2330
2303
for parent in merges:
2331
2304
parent_trees.append(
2332
2305
(parent, self.branch.repository.revision_tree(parent)))
2333
if not _mod_revision.is_null(old_tip):
2306
if (old_tip is not None and not _mod_revision.is_null(old_tip)):
2334
2307
parent_trees.append(
2335
2308
(old_tip, self.branch.repository.revision_tree(old_tip)))
2336
2309
self.set_parent_trees(parent_trees)
2337
2310
last_rev = parent_trees[0][0]
2312
# the working tree had the same last-revision as the master
2313
# branch did. We may still have pivot local work from the local
2314
# branch into old_tip:
2315
if (old_tip is not None and not _mod_revision.is_null(old_tip)):
2316
self.add_parent_tree_id(old_tip)
2317
if (old_tip is not None and not _mod_revision.is_null(old_tip)
2318
and old_tip != last_rev):
2319
# our last revision was not the prior branch last revision
2320
# and we have converted that last revision to a pending merge.
2321
# base is somewhere between the branch tip now
2322
# and the now pending merge
2324
# Since we just modified the working tree and inventory, flush out
2325
# the current state, before we modify it again.
2326
# TODO: jam 20070214 WorkingTree3 doesn't require this, dirstate
2327
# requires it only because TreeTransform directly munges the
2328
# inventory and calls tree._write_inventory(). Ultimately we
2329
# should be able to remove this extra flush.
2331
graph = self.branch.repository.get_graph()
2332
base_rev_id = graph.find_unique_lca(revision, old_tip)
2333
base_tree = self.branch.repository.revision_tree(base_rev_id)
2334
other_tree = self.branch.repository.revision_tree(old_tip)
2335
result += merge.merge_inner(
2340
change_reporter=change_reporter)
2340
2343
def _write_hashcache_if_dirty(self):
2341
2344
"""Write out the hashcache if it is dirty."""