~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/branch.py

Merge pt1 hooks branch.

Show diffs side-by-side

added added

removed removed

Lines of Context:
28
28
        controldir,
29
29
        debug,
30
30
        errors,
 
31
        fetch,
 
32
        graph as _mod_graph,
31
33
        lockdir,
32
34
        lockable_files,
33
35
        remote,
660
662
        raise errors.UnsupportedOperation(self.get_reference_info, self)
661
663
 
662
664
    @needs_write_lock
663
 
    def fetch(self, from_branch, last_revision=None, pb=None):
 
665
    def fetch(self, from_branch, last_revision=None, pb=None, fetch_spec=None):
664
666
        """Copy revisions from from_branch into this branch.
665
667
 
666
668
        :param from_branch: Where to copy from.
667
669
        :param last_revision: What revision to stop at (None for at the end
668
670
                              of the branch.
669
671
        :param pb: An optional progress bar to use.
 
672
        :param fetch_spec: If specified, a SearchResult or
 
673
            PendingAncestryResult that describes which revisions to copy.  This
 
674
            allows copying multiple heads at once.  Mutually exclusive with
 
675
            last_revision.
670
676
        :return: None
671
677
        """
 
678
        if fetch_spec is not None and last_revision is not None:
 
679
            raise AssertionError(
 
680
                "fetch_spec and last_revision are mutually exclusive.")
672
681
        if self.base == from_branch.base:
673
682
            return (0, [])
674
683
        if pb is not None:
677
686
                % "pb parameter to fetch()")
678
687
        from_branch.lock_read()
679
688
        try:
680
 
            if last_revision is None:
 
689
            if last_revision is None and fetch_spec is None:
681
690
                last_revision = from_branch.last_revision()
682
691
                last_revision = _mod_revision.ensure_null(last_revision)
683
692
            return self.repository.fetch(from_branch.repository,
684
693
                                         revision_id=last_revision,
685
 
                                         pb=pb)
 
694
                                         pb=pb, fetch_spec=fetch_spec)
686
695
        finally:
687
696
            from_branch.unlock()
688
697
 
871
880
                # XXX: If you unstack a branch while it has a working tree
872
881
                # with a pending merge, the pending-merged revisions will no
873
882
                # longer be present.  You can (probably) revert and remerge.
874
 
                #
875
 
                # XXX: This only fetches up to the tip of the repository; it
876
 
                # doesn't bring across any tags.  That's fairly consistent
877
 
                # with how branch works, but perhaps not ideal.
878
 
                self.repository.fetch(old_repository,
879
 
                    revision_id=self.last_revision(),
880
 
                    find_ghosts=True)
 
883
                try:
 
884
                    tags_to_fetch = set(self.tags.get_reverse_tag_dict())
 
885
                except errors.TagsNotSupported:
 
886
                    tags_to_fetch = set()
 
887
                fetch_spec = _mod_graph.NotInOtherForRevs(self.repository,
 
888
                    old_repository, required_ids=[self.last_revision()],
 
889
                    if_present_ids=tags_to_fetch, find_ghosts=True).execute()
 
890
                self.repository.fetch(old_repository, fetch_spec=fetch_spec)
881
891
            finally:
882
892
                old_repository.unlock()
883
893
        finally:
1020
1030
        return other_history[self_len:stop_revision]
1021
1031
 
1022
1032
    def update_revisions(self, other, stop_revision=None, overwrite=False,
1023
 
                         graph=None):
 
1033
                         graph=None, fetch_tags=True):
1024
1034
        """Pull in new perfect-fit revisions.
1025
1035
 
1026
1036
        :param other: Another Branch to pull from
1029
1039
            to see if it is a proper descendant.
1030
1040
        :param graph: A Graph object that can be used to query history
1031
1041
            information. This can be None.
 
1042
        :param fetch_tags: Flag that specifies if tags from other should be
 
1043
            fetched too.
1032
1044
        :return: None
1033
1045
        """
1034
1046
        return InterBranch.get(other, self).update_revisions(stop_revision,
1035
 
            overwrite, graph)
 
1047
            overwrite, graph, fetch_tags=fetch_tags)
1036
1048
 
 
1049
    @deprecated_method(deprecated_in((2, 4, 0)))
1037
1050
    def import_last_revision_info(self, source_repo, revno, revid):
1038
1051
        """Set the last revision info, importing from another repo if necessary.
1039
1052
 
1040
 
        This is used by the bound branch code to upload a revision to
1041
 
        the master branch first before updating the tip of the local branch.
1042
 
 
1043
1053
        :param source_repo: Source repository to optionally fetch from
1044
1054
        :param revno: Revision number of the new tip
1045
1055
        :param revid: Revision id of the new tip
1048
1058
            self.repository.fetch(source_repo, revision_id=revid)
1049
1059
        self.set_last_revision_info(revno, revid)
1050
1060
 
 
1061
    def import_last_revision_info_and_tags(self, source, revno, revid):
 
1062
        """Set the last revision info, importing from another repo if necessary.
 
1063
 
 
1064
        This is used by the bound branch code to upload a revision to
 
1065
        the master branch first before updating the tip of the local branch.
 
1066
        Revisions referenced by source's tags are also transferred.
 
1067
 
 
1068
        :param source: Source branch to optionally fetch from
 
1069
        :param revno: Revision number of the new tip
 
1070
        :param revid: Revision id of the new tip
 
1071
        """
 
1072
        if not self.repository.has_same_location(source.repository):
 
1073
            try:
 
1074
                tags_to_fetch = set(source.tags.get_reverse_tag_dict())
 
1075
            except errors.TagsNotSupported:
 
1076
                tags_to_fetch = set()
 
1077
            fetch_spec = _mod_graph.NotInOtherForRevs(self.repository,
 
1078
                source.repository, [revid],
 
1079
                if_present_ids=tags_to_fetch).execute()
 
1080
            self.repository.fetch(source.repository, fetch_spec=fetch_spec)
 
1081
        self.set_last_revision_info(revno, revid)
 
1082
 
1051
1083
    def revision_id_to_revno(self, revision_id):
1052
1084
        """Given a revision id, return its revno"""
1053
1085
        if _mod_revision.is_null(revision_id):
1552
1584
    _formats = {}
1553
1585
    """The known formats."""
1554
1586
 
 
1587
    _extra_formats = []
 
1588
    """Extra formats that can not be part of a metadir."""
 
1589
 
1555
1590
    can_set_append_revisions_only = True
1556
1591
 
1557
1592
    def __eq__(self, other):
1592
1627
            if isinstance(fmt, MetaDirBranchFormatFactory):
1593
1628
                fmt = fmt()
1594
1629
            result.append(fmt)
1595
 
        return result
 
1630
        return result + klass._extra_formats
1596
1631
 
1597
1632
    def get_reference(self, a_bzrdir, name=None):
1598
1633
        """Get the target reference of the branch in a_bzrdir.
1738
1773
        raise NotImplementedError(self.open)
1739
1774
 
1740
1775
    @classmethod
 
1776
    def register_extra_format(klass, format):
 
1777
        """Register a branch format that can not be part of a metadir.
 
1778
 
 
1779
        This is mainly useful to allow custom branch formats, such as
 
1780
        older Bazaar formats and foreign formats, to be tested
 
1781
        """
 
1782
        klass._extra_formats.append(format)
 
1783
        network_format_registry.register(
 
1784
            format.network_name(), format.__class__)
 
1785
 
 
1786
    @classmethod
1741
1787
    def register_format(klass, format):
1742
1788
        """Register a metadir format.
1743
1789
        
1769
1815
    def unregister_format(klass, format):
1770
1816
        del klass._formats[format.get_format_string()]
1771
1817
 
 
1818
    @classmethod
 
1819
    def unregister_extra_format(klass, format):
 
1820
        klass._extra_formats.remove(format)
 
1821
 
1772
1822
    def __str__(self):
1773
1823
        return self.get_format_description().rstrip()
1774
1824
 
2379
2429
BranchFormat.register_format(__format7)
2380
2430
BranchFormat.register_format(__format8)
2381
2431
BranchFormat.set_default_format(__format7)
2382
 
_legacy_formats = [BzrBranchFormat4(),
2383
 
    ]
2384
 
network_format_registry.register(
2385
 
    _legacy_formats[0].network_name(), _legacy_formats[0].__class__)
 
2432
BranchFormat.register_extra_format(BzrBranchFormat4())
2386
2433
 
2387
2434
 
2388
2435
class BranchWriteLockResult(LogicalLockResult):
3338
3385
 
3339
3386
    @needs_write_lock
3340
3387
    def update_revisions(self, stop_revision=None, overwrite=False,
3341
 
                         graph=None):
 
3388
                         graph=None, fetch_tags=True):
3342
3389
        """Pull in new perfect-fit revisions.
3343
3390
 
3344
3391
        :param stop_revision: Updated until the given revision
3346
3393
            to see if it is a proper descendant.
3347
3394
        :param graph: A Graph object that can be used to query history
3348
3395
            information. This can be None.
 
3396
        :param fetch_tags: Flag that specifies if tags from source should be
 
3397
            fetched too.
3349
3398
        :return: None
3350
3399
        """
3351
3400
        raise NotImplementedError(self.update_revisions)
3409
3458
 
3410
3459
    @needs_write_lock
3411
3460
    def update_revisions(self, stop_revision=None, overwrite=False,
3412
 
        graph=None):
 
3461
        graph=None, fetch_tags=True):
3413
3462
        """See InterBranch.update_revisions()."""
3414
3463
        other_revno, other_last_revision = self.source.last_revision_info()
3415
3464
        stop_revno = None # unknown
3427
3476
        # case of having something to pull, and so that the check for
3428
3477
        # already merged can operate on the just fetched graph, which will
3429
3478
        # be cached in memory.
3430
 
        self.target.fetch(self.source, stop_revision)
 
3479
        if fetch_tags:
 
3480
            fetch_spec_factory = fetch.FetchSpecFactory()
 
3481
            fetch_spec_factory.source_branch = self.source
 
3482
            fetch_spec_factory.source_branch_stop_revision_id = stop_revision
 
3483
            fetch_spec_factory.source_repo = self.source.repository
 
3484
            fetch_spec_factory.target_repo = self.target.repository
 
3485
            fetch_spec_factory.target_repo_kind = fetch.TargetRepoKinds.PREEXISTING
 
3486
            fetch_spec = fetch_spec_factory.make_fetch_spec()
 
3487
        else:
 
3488
            fetch_spec = _mod_graph.NotInOtherForRevs(self.target.repository,
 
3489
                self.source.repository, revision_ids=[stop_revision]).execute()
 
3490
        self.target.fetch(self.source, fetch_spec=fetch_spec)
3431
3491
        # Check to see if one is an ancestor of the other
3432
3492
        if not overwrite:
3433
3493
            if graph is None: