~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/workingtree.py

Merge updated set_parents api.

Show diffs side-by-side

added added

removed removed

Lines of Context:
394
394
        return pathjoin(self.basedir, filename)
395
395
    
396
396
    def basis_tree(self):
397
 
        """Return RevisionTree for the current last revision."""
 
397
        """Return RevisionTree for the current last revision.
 
398
        
 
399
        If the left most parent is a ghost then the returned tree will be an
 
400
        empty tree - one obtained by calling repository.revision_tree(None).
 
401
        """
398
402
        revision_id = self.last_revision()
399
403
        if revision_id is not None:
400
404
            try:
415
419
            # its a ghost.
416
420
            if self.branch.repository.has_revision(revision_id):
417
421
                raise
418
 
            # the basis tree is a ghost
 
422
            # the basis tree is a ghost so return an empty tree.
419
423
            return self.branch.repository.revision_tree(None)
420
424
 
421
425
    @staticmethod
661
665
        and setting the list to its value plus revision_id.
662
666
 
663
667
        :param revision_id: The revision id to add to the parent list. It may
664
 
        be a ghost revision.
 
668
        be a ghost revision as long as its not the first parent to be added,
 
669
        or the allow_leftmost_as_ghost parameter is set True.
 
670
        :param allow_leftmost_as_ghost: Allow the first parent to be a ghost.
665
671
        """
666
672
        self.set_parent_ids(self.get_parent_ids() + [revision_id],
667
673
            allow_leftmost_as_ghost=allow_leftmost_as_ghost)
676
682
        simpler to use that api. If you have the parent already available, using
677
683
        this api is preferred.
678
684
 
679
 
        :param parent_tuple: The (revision id, tree) to add to the parent list.             If the revision_id is a ghost, pass None for the tree.
 
685
        :param parent_tuple: The (revision id, tree) to add to the parent list.
 
686
            If the revision_id is a ghost, pass None for the tree.
 
687
        :param allow_leftmost_as_ghost: Allow the first parent to be a ghost.
680
688
        """
681
689
        self.set_parent_ids(self.get_parent_ids() + [parent_tuple[0]],
682
690
            allow_leftmost_as_ghost=allow_leftmost_as_ghost)
734
742
                    (rev_id, self.branch.repository.revision_tree(rev_id)))
735
743
            except errors.RevisionNotPresent:
736
744
                trees.append((rev_id, None))
737
 
                pass
738
745
        self.set_parent_trees(trees,
739
746
            allow_leftmost_as_ghost=allow_leftmost_as_ghost)
740
747
 
746
753
            If tree is None, then that element is treated as an unreachable
747
754
            parent tree - i.e. a ghost.
748
755
        """
749
 
        parent = parents_list[:1]
750
 
        if len(parent):
 
756
        if len(parents_list) > 0:
 
757
            leftmost_id = parents_list[0][0]
751
758
            if (not allow_leftmost_as_ghost and not
752
 
                self.branch.repository.has_revision(parent[0][0])):
753
 
                raise errors.GhostRevision(parent[0][0])
754
 
            self.set_last_revision(parent[0][0])
 
759
                self.branch.repository.has_revision(leftmost_id)):
 
760
                raise errors.GhostRevisionUnusableHere(leftmost_id)
 
761
            self.set_last_revision(leftmost_id)
755
762
        else:
756
763
            self.set_last_revision(None)
757
764
        merges = parents_list[1:]
1504
1511
        Do a 'normal' merge of the old branch basis if it is relevant.
1505
1512
        """
1506
1513
        old_tip = self.branch.update()
1507
 
        try:
1508
 
            result = 0
1509
 
            if self.last_revision() != self.branch.last_revision():
1510
 
                # merge tree state up to new branch tip.
1511
 
                basis = self.basis_tree()
1512
 
                to_tree = self.branch.basis_tree()
1513
 
                result += merge_inner(self.branch,
1514
 
                                      to_tree,
1515
 
                                      basis,
1516
 
                                      this_tree=self)
1517
 
                self.set_last_revision(self.branch.last_revision())
1518
 
                # TODO - dedup parents list with things merged by pull ?
1519
 
                # reuse the tree we've updated to to set the basis:
1520
 
                parent_trees = [(self.branch.last_revision(), to_tree)]
1521
 
                merges = self.get_parent_ids()[1:]
1522
 
                # pull the other trees out of the repository. This could be
1523
 
                # better expressed - for instance by inserting a parent, and
1524
 
                # that would remove duplication.
1525
 
                parent_trees.extend([
1526
 
                    (parent, self.branch.repository.revision_tree(parent)) for
1527
 
                     parent in merges])
1528
 
                self.set_parent_trees(parent_trees)
1529
 
            if old_tip and old_tip != self.last_revision():
1530
 
                # our last revision was not the prior branch last revision
1531
 
                # and we have converted that last revision to a pending merge.
1532
 
                # base is somewhere between the branch tip now
1533
 
                # and the now pending merge
1534
 
                from bzrlib.revision import common_ancestor
1535
 
                try:
1536
 
                    base_rev_id = common_ancestor(self.branch.last_revision(),
1537
 
                                                  old_tip,
1538
 
                                                  self.branch.repository)
1539
 
                except errors.NoCommonAncestor:
1540
 
                    base_rev_id = None
1541
 
                base_tree = self.branch.repository.revision_tree(base_rev_id)
1542
 
                other_tree = self.branch.repository.revision_tree(old_tip)
1543
 
                result += merge_inner(self.branch,
1544
 
                                      other_tree,
1545
 
                                      base_tree,
1546
 
                                      this_tree=self)
1547
 
            return result
1548
 
        finally:
 
1514
        # here if old_tip is not None, it is the old tip of the branch before
 
1515
        # it was updated from the master branch. This should become a pending
 
1516
        # merge in the working tree to preserve the user existing work.  we
 
1517
        # cant set that until we update the working trees last revision to be
 
1518
        # one from the new branch, because it will just get absorbed by the
 
1519
        # parent de-duplication logic.
 
1520
        # 
 
1521
        # We MUST save it even if an error occurs, because otherwise the users
 
1522
        # local work is unreferenced and will appear to have been lost.
 
1523
        # 
 
1524
        result = 0
 
1525
        if self.last_revision() != self.branch.last_revision():
 
1526
            # merge tree state up to new branch tip.
 
1527
            basis = self.basis_tree()
 
1528
            to_tree = self.branch.basis_tree()
 
1529
            result += merge_inner(self.branch,
 
1530
                                  to_tree,
 
1531
                                  basis,
 
1532
                                  this_tree=self)
 
1533
            # TODO - dedup parents list with things merged by pull ?
 
1534
            # reuse the tree we've updated to to set the basis:
 
1535
            parent_trees = [(self.branch.last_revision(), to_tree)]
 
1536
            merges = self.get_parent_ids()[1:]
 
1537
            # Ideally we ask the tree for the trees here, that way the working
 
1538
            # tree can decide whether to give us teh entire tree or give us a
 
1539
            # lazy initialised tree. dirstate for instance will have the trees
 
1540
            # in ram already, whereas a last-revision + basis-inventory tree
 
1541
            # will not, but also does not need them when setting parents.
 
1542
            for parent in merges:
 
1543
                parent_trees.append(
 
1544
                    (parent, self.branch.repository.revision_tree(parent)))
 
1545
            if old_tip is not None:
 
1546
                parent_trees.append(
 
1547
                    (old_tip, self.branch.repository.revision_tree(old_tip)))
 
1548
            self.set_parent_trees(parent_trees)
 
1549
        else:
 
1550
            # the working tree had the same last-revision as the master
 
1551
            # branch did. We may still have pivot local work from the local
 
1552
            # branch into old_tip:
1549
1553
            if old_tip is not None:
1550
1554
                self.add_pending_merge(old_tip)
 
1555
        if old_tip and old_tip != self.last_revision():
 
1556
            # our last revision was not the prior branch last revision
 
1557
            # and we have converted that last revision to a pending merge.
 
1558
            # base is somewhere between the branch tip now
 
1559
            # and the now pending merge
 
1560
            from bzrlib.revision import common_ancestor
 
1561
            try:
 
1562
                base_rev_id = common_ancestor(self.branch.last_revision(),
 
1563
                                              old_tip,
 
1564
                                              self.branch.repository)
 
1565
            except errors.NoCommonAncestor:
 
1566
                base_rev_id = None
 
1567
            base_tree = self.branch.repository.revision_tree(base_rev_id)
 
1568
            other_tree = self.branch.repository.revision_tree(old_tip)
 
1569
            result += merge_inner(self.branch,
 
1570
                                  other_tree,
 
1571
                                  base_tree,
 
1572
                                  this_tree=self)
 
1573
        return result
1551
1574
 
1552
1575
    @needs_write_lock
1553
1576
    def _write_inventory(self, inv):