494
494
old.append(list(tree.annotate_iter(file_id)))
495
495
return annotate.reannotate(old, self.get_file(file_id).readlines(),
500
def _get_ancestors(self, default_revision):
501
ancestors = set([default_revision])
502
for parent_id in self.get_parent_ids():
503
ancestors.update(self.branch.repository.get_ancestry(
504
parent_id, topo_sorted=False))
507
500
def get_parent_ids(self):
508
501
"""See Tree.get_parent_ids.
510
503
This implementation reads the pending merges list and last_revision
511
504
value and uses that to decide what the parents list should be.
513
last_rev = _mod_revision.ensure_null(self._last_revision())
514
if _mod_revision.NULL_REVISION == last_rev:
506
last_rev = self._last_revision()
517
510
parents = [last_rev]
742
735
revision_ids = [osutils.safe_revision_id(r) for r in revision_ids]
743
736
self._check_parents_for_ghosts(revision_ids,
744
737
allow_leftmost_as_ghost=allow_leftmost_as_ghost)
745
for revision_id in revision_ids:
746
_mod_revision.check_not_reserved_id(revision_id)
748
739
if len(revision_ids) > 0:
749
740
self.set_last_revision(revision_ids[0])
751
self.set_last_revision(_mod_revision.NULL_REVISION)
742
self.set_last_revision(None)
753
744
self._set_merges_from_parent_ids(revision_ids)
756
747
def set_parent_trees(self, parents_list, allow_leftmost_as_ghost=False):
757
748
"""See MutableTree.set_parent_trees."""
758
749
parent_ids = [osutils.safe_revision_id(rev) for (rev, tree) in parents_list]
759
for revision_id in parent_ids:
760
_mod_revision.check_not_reserved_id(revision_id)
762
751
self._check_parents_for_ghosts(parent_ids,
763
752
allow_leftmost_as_ghost=allow_leftmost_as_ghost)
765
754
if len(parent_ids) == 0:
766
leftmost_parent_id = _mod_revision.NULL_REVISION
755
leftmost_parent_id = None
767
756
leftmost_parent_tree = None
769
758
leftmost_parent_id, leftmost_parent_tree = parents_list[0]
819
808
# local alterations
820
809
merger.check_basis(check_clean=True, require_commits=False)
821
810
if to_revision is None:
822
to_revision = _mod_revision.ensure_null(branch.last_revision())
811
to_revision = branch.last_revision()
824
813
to_revision = osutils.safe_revision_id(to_revision)
825
814
merger.other_rev_id = to_revision
826
if _mod_revision.is_null(merger.other_rev_id):
827
raise errors.NoCommits(branch)
815
if merger.other_rev_id is None:
816
raise error.NoCommits(branch)
828
817
self.branch.fetch(branch, last_revision=merger.other_rev_id)
829
818
merger.other_basis = merger.other_rev_id
830
819
merger.other_tree = self.branch.repository.revision_tree(
1794
1783
def recurse_directory_to_add_files(directory):
1795
1784
# recurse directory and add all files
1796
1785
# so we can check if they have changed.
1797
for parent_info, file_infos in\
1798
osutils.walkdirs(self.abspath(directory),
1800
for relpath, basename, kind, lstat, abspath in file_infos:
1802
if self.path2id(relpath): #is it versioned?
1786
for contained_dir_info in self.walkdirs(directory):
1787
for file_info in contained_dir_info[1]:
1788
if file_info[2] == 'file':
1789
relpath = self.relpath(file_info[0])
1790
if file_info[4]: #is it versioned?
1803
1791
new_files.add(relpath)
1805
1793
unknown_files_in_directory.add(
1806
(relpath, None, kind))
1794
(relpath, None, file_info[2]))
1808
1796
for filename in files:
1809
1797
# Get file name into canonical form.
1810
abspath = self.abspath(filename)
1811
filename = self.relpath(abspath)
1798
filename = self.relpath(self.abspath(filename))
1812
1799
if len(filename) > 0:
1813
1800
new_files.add(filename)
1814
if osutils.isdir(abspath):
1801
if osutils.isdir(filename) and len(os.listdir(filename)) > 0:
1815
1802
recurse_directory_to_add_files(filename)
1816
1803
files = [f for f in new_files]
1819
return # nothing to do
1821
1805
# Sort needed to first handle directory content before the directory
1822
1806
files.sort(reverse=True)
1823
1807
if not keep_files and not force:
1824
has_changed_files = len(unknown_files_in_directory) > 0
1825
if not has_changed_files:
1826
for (file_id, path, content_change, versioned, parent_id, name,
1827
kind, executable) in self._iter_changes(self.basis_tree(),
1828
include_unchanged=True, require_versioned=False,
1829
want_unversioned=True, specific_files=files):
1830
# check if it's unknown OR changed but not deleted:
1831
if (versioned == (False, False)
1832
or (content_change and kind[1] != None)):
1833
has_changed_files = True
1836
if has_changed_files:
1837
# make delta to show ALL applicable changes in error message.
1838
tree_delta = self.changes_from(self.basis_tree(),
1839
specific_files=files)
1840
for unknown_file in unknown_files_in_directory:
1841
tree_delta.unversioned.extend((unknown_file,))
1808
tree_delta = self.changes_from(self.basis_tree(),
1809
specific_files=files)
1810
for unknown_file in unknown_files_in_directory:
1811
tree_delta.unversioned.extend((unknown_file,))
1812
if bool(tree_delta.modified
1814
or tree_delta.renamed
1815
or tree_delta.kind_changed
1816
or tree_delta.unversioned):
1842
1817
raise errors.BzrRemoveChangedFilesError(tree_delta)
1844
1819
# do this before any modifications
1845
1820
for f in files:
1846
fid = self.path2id(f)
1821
fid = inv.path2id(f)
1849
1824
message="%s is not versioned." % (f,)
1854
1829
new_status = 'I'
1856
1831
new_status = '?'
1857
textui.show_status(new_status, self.kind(fid), f,
1832
textui.show_status(new_status, inv[fid].kind, f,
1858
1833
to_file=to_file)
1859
1834
# unversion file
1860
inv_delta.append((f, None, fid, None))
1861
1836
message="removed %s" % (f,)
1863
1838
if not keep_files:
2030
2005
old_tip = self.branch.update()
2033
return self._update_tree(old_tip, change_reporter)
2008
return self._update_tree(old_tip)
2037
2012
@needs_tree_write_lock
2038
def _update_tree(self, old_tip=None, change_reporter=None):
2013
def _update_tree(self, old_tip=None):
2039
2014
"""Update a tree to the master branch.
2041
2016
:param old_tip: if supplied, the previous tip revision the branch,
2094
2068
# the working tree had the same last-revision as the master
2095
2069
# branch did. We may still have pivot local work from the local
2096
2070
# branch into old_tip:
2097
if (old_tip is not None and not _mod_revision.is_null(old_tip)):
2071
if old_tip is not None:
2098
2072
self.add_parent_tree_id(old_tip)
2099
if (old_tip is not None and not _mod_revision.is_null(old_tip)
2100
and old_tip != last_rev):
2073
if old_tip and old_tip != last_rev:
2101
2074
# our last revision was not the prior branch last revision
2102
2075
# and we have converted that last revision to a pending merge.
2103
2076
# base is somewhere between the branch tip now
2110
2083
# inventory and calls tree._write_inventory(). Ultimately we
2111
2084
# should be able to remove this extra flush.
2113
graph = self.branch.repository.get_graph()
2114
base_rev_id = graph.find_unique_lca(self.branch.last_revision(),
2086
from bzrlib.revision import common_ancestor
2088
base_rev_id = common_ancestor(self.branch.last_revision(),
2090
self.branch.repository)
2091
except errors.NoCommonAncestor:
2116
2093
base_tree = self.branch.repository.revision_tree(base_rev_id)
2117
2094
other_tree = self.branch.repository.revision_tree(old_tip)
2118
2095
result += merge.merge_inner(
2123
change_reporter=change_reporter)
2126
2102
def _write_hashcache_if_dirty(self):
2619
2595
if not isinstance(a_bzrdir.transport, LocalTransport):
2620
2596
raise errors.NotLocalUrl(a_bzrdir.transport.base)
2621
2597
branch = a_bzrdir.open_branch()
2622
if revision_id is None:
2623
revision_id = _mod_revision.ensure_null(branch.last_revision())
2598
if revision_id is not None:
2625
2599
revision_id = osutils.safe_revision_id(revision_id)
2628
branch.generate_revision_history(revision_id)
2602
revision_history = branch.revision_history()
2604
position = revision_history.index(revision_id)
2606
raise errors.NoSuchRevision(branch, revision_id)
2607
branch.set_revision_history(revision_history[:position + 1])
2610
revision = branch.last_revision()
2631
2611
inv = Inventory()
2632
2612
wt = WorkingTree2(a_bzrdir.root_transport.local_abspath('.'),
2635
2615
_internal=True,
2637
2617
_bzrdir=a_bzrdir)
2638
basis_tree = branch.repository.revision_tree(revision_id)
2618
basis_tree = branch.repository.revision_tree(revision)
2639
2619
if basis_tree.inventory.root is not None:
2640
2620
wt.set_root_id(basis_tree.inventory.root.file_id)
2641
2621
# set the parent list and cache the basis tree.
2642
if _mod_revision.is_null(revision_id):
2645
parent_trees = [(revision_id, basis_tree)]
2646
wt.set_parent_trees(parent_trees)
2622
wt.set_parent_trees([(revision, basis_tree)])
2647
2623
transform.build_tree(basis_tree, wt)
2798
2774
# and not independently creatable, so are not registered.
2799
2775
_legacy_formats = [WorkingTreeFormat2(),
2779
class WorkingTreeTestProviderAdapter(object):
2780
"""A tool to generate a suite testing multiple workingtree formats at once.
2782
This is done by copying the test once for each transport and injecting
2783
the transport_server, transport_readonly_server, and workingtree_format
2784
classes into each copy. Each copy is also given a new id() to make it
2788
def __init__(self, transport_server, transport_readonly_server, formats):
2789
self._transport_server = transport_server
2790
self._transport_readonly_server = transport_readonly_server
2791
self._formats = formats
2793
def _clone_test(self, test, bzrdir_format, workingtree_format, variation):
2794
"""Clone test for adaption."""
2795
new_test = deepcopy(test)
2796
new_test.transport_server = self._transport_server
2797
new_test.transport_readonly_server = self._transport_readonly_server
2798
new_test.bzrdir_format = bzrdir_format
2799
new_test.workingtree_format = workingtree_format
2800
def make_new_test_id():
2801
new_id = "%s(%s)" % (test.id(), variation)
2802
return lambda: new_id
2803
new_test.id = make_new_test_id()
2806
def adapt(self, test):
2807
from bzrlib.tests import TestSuite
2808
result = TestSuite()
2809
for workingtree_format, bzrdir_format in self._formats:
2810
new_test = self._clone_test(
2813
workingtree_format, workingtree_format.__class__.__name__)
2814
result.addTest(new_test)