408
393
return pathjoin(self.basedir, filename)
410
395
def basis_tree(self):
411
"""Return RevisionTree for the current last revision.
413
If the left most parent is a ghost then the returned tree will be an
414
empty tree - one obtained by calling repository.revision_tree(None).
417
revision_id = self.get_parent_ids()[0]
419
# no parents, return an empty revision tree.
420
# in the future this should return the tree for
421
# 'empty:' - the implicit root empty tree.
422
return self.branch.repository.revision_tree(None)
396
"""Return RevisionTree for the current last revision."""
397
revision_id = self.last_revision()
398
if revision_id is not None:
425
400
xml = self.read_basis_inventory()
426
inv = bzrlib.xml6.serializer_v6.read_inventory_from_string(xml)
427
if inv is not None and inv.revision_id == revision_id:
428
return bzrlib.tree.RevisionTree(self.branch.repository,
430
except (NoSuchFile, errors.BadInventoryFormat):
432
# No cached copy available, retrieve from the repository.
433
# FIXME? RBC 20060403 should we cache the inventory locally
436
return self.branch.repository.revision_tree(revision_id)
437
except errors.RevisionNotPresent:
438
# the basis tree *may* be a ghost or a low level error may have
439
# occured. If the revision is present, its a problem, if its not
441
if self.branch.repository.has_revision(revision_id):
443
# the basis tree is a ghost so return an empty tree.
444
return self.branch.repository.revision_tree(None)
401
inv = bzrlib.xml5.serializer_v5.read_inventory_from_string(xml)
404
if inv is not None and inv.revision_id == revision_id:
405
return bzrlib.tree.RevisionTree(self.branch.repository, inv,
407
# FIXME? RBC 20060403 should we cache the inventory here ?
408
return self.branch.repository.revision_tree(revision_id)
447
411
@deprecated_method(zero_eight)
684
642
self._write_inventory(inv)
686
@needs_tree_write_lock
687
def add_parent_tree_id(self, revision_id, allow_leftmost_as_ghost=False):
688
"""Add revision_id as a parent.
690
This is equivalent to retrieving the current list of parent ids
691
and setting the list to its value plus revision_id.
693
:param revision_id: The revision id to add to the parent list. It may
694
be a ghost revision as long as its not the first parent to be added,
695
or the allow_leftmost_as_ghost parameter is set True.
696
:param allow_leftmost_as_ghost: Allow the first parent to be a ghost.
698
parents = self.get_parent_ids() + [revision_id]
699
self.set_parent_ids(parents,
700
allow_leftmost_as_ghost=len(parents) > 1 or allow_leftmost_as_ghost)
702
@needs_tree_write_lock
703
def add_parent_tree(self, parent_tuple, allow_leftmost_as_ghost=False):
704
"""Add revision_id, tree tuple as a parent.
706
This is equivalent to retrieving the current list of parent trees
707
and setting the list to its value plus parent_tuple. See also
708
add_parent_tree_id - if you only have a parent id available it will be
709
simpler to use that api. If you have the parent already available, using
710
this api is preferred.
712
:param parent_tuple: The (revision id, tree) to add to the parent list.
713
If the revision_id is a ghost, pass None for the tree.
714
:param allow_leftmost_as_ghost: Allow the first parent to be a ghost.
716
parent_ids = self.get_parent_ids() + [parent_tuple[0]]
717
if len(parent_ids) > 1:
718
# the leftmost may have already been a ghost, preserve that if it
720
allow_leftmost_as_ghost = True
721
self.set_parent_ids(parent_ids,
722
allow_leftmost_as_ghost=allow_leftmost_as_ghost)
724
@needs_tree_write_lock
725
645
def add_pending_merge(self, *revision_ids):
726
646
# TODO: Perhaps should check at this point that the
727
647
# history of the revision is actually present?
728
parents = self.get_parent_ids()
648
p = self.pending_merges()
730
650
for rev_id in revision_ids:
731
if rev_id in parents:
733
parents.append(rev_id)
736
self.set_parent_ids(parents, allow_leftmost_as_ghost=True)
656
self.set_pending_merges(p)
738
@deprecated_method(zero_eleven)
740
659
def pending_merges(self):
741
660
"""Return a list of pending merges.
743
662
These are revisions that have been merged into the working
744
663
directory but not yet committed.
746
As of 0.11 this is deprecated. Please see WorkingTree.get_parent_ids()
747
instead - which is available on all tree objects.
749
return self.get_parent_ids()[1:]
751
@needs_tree_write_lock
752
def set_parent_ids(self, revision_ids, allow_leftmost_as_ghost=False):
753
"""Set the parent ids to revision_ids.
755
See also set_parent_trees. This api will try to retrieve the tree data
756
for each element of revision_ids from the trees repository. If you have
757
tree data already available, it is more efficient to use
758
set_parent_trees rather than set_parent_ids. set_parent_ids is however
759
an easier API to use.
761
:param revision_ids: The revision_ids to set as the parent ids of this
762
working tree. Any of these may be ghosts.
764
if len(revision_ids) > 0:
765
leftmost_id = revision_ids[0]
766
if (not allow_leftmost_as_ghost and not
767
self.branch.repository.has_revision(leftmost_id)):
768
raise errors.GhostRevisionUnusableHere(leftmost_id)
769
self.set_last_revision(leftmost_id)
771
self.set_last_revision(None)
772
merges = revision_ids[1:]
773
self._control_files.put_utf8('pending-merges', '\n'.join(merges))
775
@needs_tree_write_lock
776
def set_parent_trees(self, parents_list, allow_leftmost_as_ghost=False):
777
"""Set the parents of the working tree.
779
:param parents_list: A list of (revision_id, tree) tuples.
780
If tree is None, then that element is treated as an unreachable
781
parent tree - i.e. a ghost.
783
# parent trees are not used in current format trees, delegate to
785
self.set_parent_ids([rev for (rev, tree) in parents_list],
786
allow_leftmost_as_ghost=allow_leftmost_as_ghost)
788
@needs_tree_write_lock
666
merges_file = self._control_files.get_utf8('pending-merges')
670
for l in merges_file.readlines():
671
p.append(l.rstrip('\n'))
789
675
def set_pending_merges(self, rev_list):
790
parents = self.get_parent_ids()
791
leftmost = parents[:1]
792
new_parents = leftmost + rev_list
793
self.set_parent_ids(new_parents)
676
self._control_files.put_utf8('pending-merges', '\n'.join(rev_list))
795
@needs_tree_write_lock
796
679
def set_merge_modified(self, modified_hashes):
797
680
def iter_stanzas():
798
681
for file_id, hash in modified_hashes.iteritems():
799
682
yield Stanza(file_id=file_id, hash=hash)
800
683
self._put_rio('merge-hashes', iter_stanzas(), MERGE_MODIFIED_HEADER_1)
802
@needs_tree_write_lock
803
686
def _put_rio(self, filename, stanzas, header):
804
687
my_file = rio_file(stanzas, header)
805
688
self._control_files.put(filename, my_file)
807
@needs_write_lock # because merge pulls data into the branch.
808
def merge_from_branch(self, branch, to_revision=None):
809
"""Merge from a branch into this working tree.
811
:param branch: The branch to merge from.
812
:param to_revision: If non-None, the merge will merge to to_revision, but
813
not beyond it. to_revision does not need to be in the history of
814
the branch when it is supplied. If None, to_revision defaults to
815
branch.last_revision().
817
from bzrlib.merge import Merger, Merge3Merger
818
pb = bzrlib.ui.ui_factory.nested_progress_bar()
820
merger = Merger(self.branch, this_tree=self, pb=pb)
821
merger.pp = ProgressPhase("Merge phase", 5, pb)
822
merger.pp.next_phase()
823
# check that there are no
825
merger.check_basis(check_clean=True, require_commits=False)
826
if to_revision is None:
827
to_revision = branch.last_revision()
828
merger.other_rev_id = to_revision
829
if merger.other_rev_id is None:
830
raise error.NoCommits(branch)
831
self.branch.fetch(branch, last_revision=merger.other_rev_id)
832
merger.other_basis = merger.other_rev_id
833
merger.other_tree = self.branch.repository.revision_tree(
835
merger.pp.next_phase()
837
if merger.base_rev_id == merger.other_rev_id:
838
raise errors.PointlessMerge
839
merger.backup_files = False
840
merger.merge_type = Merge3Merger
841
merger.set_interesting_files(None)
842
merger.show_base = False
843
merger.reprocess = False
844
conflicts = merger.do_merge()
851
691
def merge_modified(self):
1115
956
for subp in self.extras():
1116
957
if not self.is_ignored(subp):
1119
@needs_tree_write_lock
1120
def unversion(self, file_ids):
1121
"""Remove the file ids in file_ids from the current versioned set.
1123
When a file_id is unversioned, all of its children are automatically
1126
:param file_ids: The file ids to stop versioning.
1127
:raises: NoSuchId if any fileid is not currently versioned.
1129
for file_id in file_ids:
1130
if self._inventory.has_id(file_id):
1131
self._inventory.remove_recursive_id(file_id)
1133
raise errors.NoSuchId(self, file_id)
1135
# in the future this should just set a dirty bit to wait for the
1136
# final unlock. However, until all methods of workingtree start
1137
# with the current in -memory inventory rather than triggering
1138
# a read, it is more complex - we need to teach read_inventory
1139
# to know when to read, and when to not read first... and possibly
1140
# to save first when the in memory one may be corrupted.
1141
# so for now, we just only write it if it is indeed dirty.
1143
self._write_inventory(self._inventory)
1145
960
@deprecated_method(zero_eight)
1146
961
def iter_conflicts(self):
1147
962
"""List all files in the tree that have text or content conflicts.
1623
1403
Do a 'normal' merge of the old branch basis if it is relevant.
1625
1405
old_tip = self.branch.update()
1626
# here if old_tip is not None, it is the old tip of the branch before
1627
# it was updated from the master branch. This should become a pending
1628
# merge in the working tree to preserve the user existing work. we
1629
# cant set that until we update the working trees last revision to be
1630
# one from the new branch, because it will just get absorbed by the
1631
# parent de-duplication logic.
1633
# We MUST save it even if an error occurs, because otherwise the users
1634
# local work is unreferenced and will appear to have been lost.
1406
if old_tip is not None:
1407
self.add_pending_merge(old_tip)
1408
self.branch.lock_read()
1638
last_rev = self.get_parent_ids()[0]
1641
if last_rev != self.branch.last_revision():
1642
# merge tree state up to new branch tip.
1643
basis = self.basis_tree()
1644
to_tree = self.branch.basis_tree()
1645
result += merge_inner(self.branch,
1649
# TODO - dedup parents list with things merged by pull ?
1650
# reuse the tree we've updated to to set the basis:
1651
parent_trees = [(self.branch.last_revision(), to_tree)]
1652
merges = self.get_parent_ids()[1:]
1653
# Ideally we ask the tree for the trees here, that way the working
1654
# tree can decide whether to give us teh entire tree or give us a
1655
# lazy initialised tree. dirstate for instance will have the trees
1656
# in ram already, whereas a last-revision + basis-inventory tree
1657
# will not, but also does not need them when setting parents.
1658
for parent in merges:
1659
parent_trees.append(
1660
(parent, self.branch.repository.revision_tree(parent)))
1661
if old_tip is not None:
1662
parent_trees.append(
1663
(old_tip, self.branch.repository.revision_tree(old_tip)))
1664
self.set_parent_trees(parent_trees)
1665
last_rev = parent_trees[0][0]
1667
# the working tree had the same last-revision as the master
1668
# branch did. We may still have pivot local work from the local
1669
# branch into old_tip:
1670
if old_tip is not None:
1671
self.add_parent_tree_id(old_tip)
1672
if old_tip and old_tip != last_rev:
1673
# our last revision was not the prior branch last revision
1674
# and we have converted that last revision to a pending merge.
1675
# base is somewhere between the branch tip now
1676
# and the now pending merge
1677
from bzrlib.revision import common_ancestor
1679
base_rev_id = common_ancestor(self.branch.last_revision(),
1681
self.branch.repository)
1682
except errors.NoCommonAncestor:
1684
base_tree = self.branch.repository.revision_tree(base_rev_id)
1685
other_tree = self.branch.repository.revision_tree(old_tip)
1686
result += merge_inner(self.branch,
1411
if self.last_revision() != self.branch.last_revision():
1412
# merge tree state up to new branch tip.
1413
basis = self.basis_tree()
1414
to_tree = self.branch.basis_tree()
1415
result += merge_inner(self.branch,
1419
self.set_last_revision(self.branch.last_revision())
1420
if old_tip and old_tip != self.last_revision():
1421
# our last revision was not the prior branch last revision
1422
# and we have converted that last revision to a pending merge.
1423
# base is somewhere between the branch tip now
1424
# and the now pending merge
1425
from bzrlib.revision import common_ancestor
1427
base_rev_id = common_ancestor(self.branch.last_revision(),
1429
self.branch.repository)
1430
except errors.NoCommonAncestor:
1432
base_tree = self.branch.repository.revision_tree(base_rev_id)
1433
other_tree = self.branch.repository.revision_tree(old_tip)
1434
result += merge_inner(self.branch,
1440
self.branch.unlock()
1692
@needs_tree_write_lock
1693
1443
def _write_inventory(self, inv):
1694
1444
"""Write inventory as the current inventory."""
1695
1445
sio = StringIO()