~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/branch.py

  • Committer: Andrew Bennetts
  • Date: 2009-07-27 05:24:02 UTC
  • mfrom: (4570 +trunk)
  • mto: This revision was merged to the branch mainline in revision 4573.
  • Revision ID: andrew.bennetts@canonical.com-20090727052402-e3vakc2pnq0y66gm
Merge bzr.dev.

Show diffs side-by-side

added added

removed removed

Lines of Context:
35
35
        symbol_versioning,
36
36
        transport,
37
37
        tsort,
 
38
        ui,
38
39
        urlutils,
39
40
        )
40
41
from bzrlib.config import BranchConfig, TransportConfig
662
663
        """
663
664
        if not self._format.supports_stacking():
664
665
            raise errors.UnstackableBranchFormat(self._format, self.base)
 
666
        # XXX: Changing from one fallback repository to another does not check
 
667
        # that all the data you need is present in the new fallback.
 
668
        # Possibly it should.
665
669
        self._check_stackable_repo()
666
670
        if not url:
667
671
            try:
669
673
            except (errors.NotStacked, errors.UnstackableBranchFormat,
670
674
                errors.UnstackableRepositoryFormat):
671
675
                return
672
 
            url = ''
673
 
            # XXX: Lock correctness - should unlock our old repo if we were
674
 
            # locked.
675
 
            # repositories don't offer an interface to remove fallback
676
 
            # repositories today; take the conceptually simpler option and just
677
 
            # reopen it.
678
 
            self.repository = self.bzrdir.find_repository()
679
 
            self.repository.lock_write()
680
 
            # for every revision reference the branch has, ensure it is pulled
681
 
            # in.
682
 
            source_repository = self._get_fallback_repository(old_url)
683
 
            for revision_id in chain([self.last_revision()],
684
 
                self.tags.get_reverse_tag_dict()):
685
 
                self.repository.fetch(source_repository, revision_id,
686
 
                    find_ghosts=True)
 
676
            self._unstack()
687
677
        else:
688
678
            self._activate_fallback_location(url)
689
679
        # write this out after the repository is stacked to avoid setting a
690
680
        # stacked config that doesn't work.
691
681
        self._set_config_location('stacked_on_location', url)
692
682
 
 
683
    def _unstack(self):
 
684
        """Change a branch to be unstacked, copying data as needed.
 
685
        
 
686
        Don't call this directly, use set_stacked_on_url(None).
 
687
        """
 
688
        pb = ui.ui_factory.nested_progress_bar()
 
689
        try:
 
690
            pb.update("Unstacking")
 
691
            # The basic approach here is to fetch the tip of the branch,
 
692
            # including all available ghosts, from the existing stacked
 
693
            # repository into a new repository object without the fallbacks. 
 
694
            #
 
695
            # XXX: See <https://launchpad.net/bugs/397286> - this may not be
 
696
            # correct for CHKMap repostiories
 
697
            old_repository = self.repository
 
698
            if len(old_repository._fallback_repositories) != 1:
 
699
                raise AssertionError("can't cope with fallback repositories "
 
700
                    "of %r" % (self.repository,))
 
701
            # unlock it, including unlocking the fallback
 
702
            old_repository.unlock()
 
703
            old_repository.lock_read()
 
704
            try:
 
705
                # Repositories don't offer an interface to remove fallback
 
706
                # repositories today; take the conceptually simpler option and just
 
707
                # reopen it.  We reopen it starting from the URL so that we
 
708
                # get a separate connection for RemoteRepositories and can
 
709
                # stream from one of them to the other.  This does mean doing
 
710
                # separate SSH connection setup, but unstacking is not a
 
711
                # common operation so it's tolerable.
 
712
                new_bzrdir = bzrdir.BzrDir.open(self.bzrdir.root_transport.base)
 
713
                new_repository = new_bzrdir.find_repository()
 
714
                self.repository = new_repository
 
715
                if self.repository._fallback_repositories:
 
716
                    raise AssertionError("didn't expect %r to have "
 
717
                        "fallback_repositories"
 
718
                        % (self.repository,))
 
719
                # this is not paired with an unlock because it's just restoring
 
720
                # the previous state; the lock's released when set_stacked_on_url
 
721
                # returns
 
722
                self.repository.lock_write()
 
723
                # XXX: If you unstack a branch while it has a working tree
 
724
                # with a pending merge, the pending-merged revisions will no
 
725
                # longer be present.  You can (probably) revert and remerge.
 
726
                #
 
727
                # XXX: This only fetches up to the tip of the repository; it
 
728
                # doesn't bring across any tags.  That's fairly consistent
 
729
                # with how branch works, but perhaps not ideal.
 
730
                self.repository.fetch(old_repository,
 
731
                    revision_id=self.last_revision(),
 
732
                    find_ghosts=True)
 
733
            finally:
 
734
                old_repository.unlock()
 
735
        finally:
 
736
            pb.finished()
693
737
 
694
738
    def _set_tags_bytes(self, bytes):
695
739
        """Mirror method for _get_tags_bytes.