~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/branch.py

  • Committer: Martin Pool
  • Date: 2009-03-03 03:01:49 UTC
  • mfrom: (4070 +trunk)
  • mto: This revision was merged to the branch mainline in revision 4073.
  • Revision ID: mbp@sourcefrog.net-20090303030149-8p8o8hszdtqa7w8f
merge trunk

Show diffs side-by-side

added added

removed removed

Lines of Context:
45
45
 
46
46
from bzrlib.decorators import needs_read_lock, needs_write_lock
47
47
from bzrlib.hooks import Hooks
 
48
from bzrlib.inter import InterObject
 
49
from bzrlib import registry
48
50
from bzrlib.symbol_versioning import (
49
51
    deprecated_in,
50
52
    deprecated_method,
134
136
    @staticmethod
135
137
    def open_containing(url, possible_transports=None):
136
138
        """Open an existing branch which contains url.
137
 
        
 
139
 
138
140
        This probes for a branch at url, and searches upwards from there.
139
141
 
140
142
        Basically we keep looking up until we find the control directory or
141
143
        run into the root.  If there isn't one, raises NotBranchError.
142
 
        If there is one and it is either an unrecognised format or an unsupported 
 
144
        If there is one and it is either an unrecognised format or an unsupported
143
145
        format, UnknownFormatError or UnsupportedFormatError are raised.
144
146
        If there is one, it is returned, along with the unused portion of url.
145
147
        """
147
149
                                                         possible_transports)
148
150
        return control.open_branch(), relpath
149
151
 
 
152
    def _push_should_merge_tags(self):
 
153
        """Should _basic_push merge this branch's tags into the target?
 
154
 
 
155
        The default implementation returns False if this branch has no tags,
 
156
        and True the rest of the time.  Subclasses may override this.
 
157
        """
 
158
        return self.tags.supports_tags() and self.tags.get_tag_dict()
 
159
 
150
160
    def get_config(self):
151
161
        return BranchConfig(self)
152
162
 
255
265
    @needs_read_lock
256
266
    def revision_id_to_dotted_revno(self, revision_id):
257
267
        """Given a revision id, return its dotted revno.
258
 
        
 
268
 
259
269
        :return: a tuple like (1,) or (400,1,3).
260
270
        """
261
271
        return self._do_revision_id_to_dotted_revno(revision_id)
425
435
    def leave_lock_in_place(self):
426
436
        """Tell this branch object not to release the physical lock when this
427
437
        object is unlocked.
428
 
        
 
438
 
429
439
        If lock_write doesn't return a token, then this method is not supported.
430
440
        """
431
441
        self.control_files.leave_in_place()
454
464
        :param last_revision: What revision to stop at (None for at the end
455
465
                              of the branch.
456
466
        :param pb: An optional progress bar to use.
457
 
 
458
 
        Returns the copied revision count and the failed revisions in a tuple:
459
 
        (copied, failures).
 
467
        :return: None
460
468
        """
461
469
        if self.base == from_branch.base:
462
470
            return (0, [])
487
495
        branch.
488
496
        """
489
497
        return None
490
 
    
 
498
 
491
499
    def get_old_bound_location(self):
492
500
        """Return the URL of the branch we used to be bound to
493
501
        """
494
502
        raise errors.UpgradeRequired(self.base)
495
503
 
496
 
    def get_commit_builder(self, parents, config=None, timestamp=None, 
497
 
                           timezone=None, committer=None, revprops=None, 
 
504
    def get_commit_builder(self, parents, config=None, timestamp=None,
 
505
                           timezone=None, committer=None, revprops=None,
498
506
                           revision_id=None):
499
507
        """Obtain a CommitBuilder for this branch.
500
 
        
 
508
 
501
509
        :param parents: Revision ids of the parents of the new revision.
502
510
        :param config: Optional configuration to use.
503
511
        :param timestamp: Optional timestamp recorded for commit.
509
517
 
510
518
        if config is None:
511
519
            config = self.get_config()
512
 
        
 
520
 
513
521
        return self.repository.get_commit_builder(self, parents, config,
514
522
            timestamp, timezone, committer, revprops, revision_id)
515
523
 
516
524
    def get_master_branch(self, possible_transports=None):
517
525
        """Return the branch we are bound to.
518
 
        
 
526
 
519
527
        :return: Either a Branch, or None
520
528
        """
521
529
        return None
592
600
 
593
601
    def _gen_revision_history(self):
594
602
        """Return sequence of revision hashes on to this branch.
595
 
        
 
603
 
596
604
        Unlike revision_history, this method always regenerates or rereads the
597
605
        revision history, i.e. it does not cache the result, so repeated calls
598
606
        may be expensive.
599
607
 
600
608
        Concrete subclasses should override this instead of revision_history so
601
609
        that subclasses do not need to deal with caching logic.
602
 
        
 
610
 
603
611
        This API is semi-public; it only for use by subclasses, all other code
604
612
        should consider it to be private.
605
613
        """
608
616
    @needs_read_lock
609
617
    def revision_history(self):
610
618
        """Return sequence of revision ids on this branch.
611
 
        
 
619
 
612
620
        This method will cache the revision history for as long as it is safe to
613
621
        do so.
614
622
        """
662
670
    @deprecated_method(deprecated_in((1, 6, 0)))
663
671
    def missing_revisions(self, other, stop_revision=None):
664
672
        """Return a list of new revisions that would perfectly fit.
665
 
        
 
673
 
666
674
        If self and other have not diverged, return a list of the revisions
667
675
        present in other, but missing from self.
668
676
        """
695
703
            information. This can be None.
696
704
        :return: None
697
705
        """
698
 
        other.lock_read()
699
 
        try:
700
 
            other_revno, other_last_revision = other.last_revision_info()
701
 
            stop_revno = None # unknown
702
 
            if stop_revision is None:
703
 
                stop_revision = other_last_revision
704
 
                if _mod_revision.is_null(stop_revision):
705
 
                    # if there are no commits, we're done.
706
 
                    return
707
 
                stop_revno = other_revno
708
 
 
709
 
            # what's the current last revision, before we fetch [and change it
710
 
            # possibly]
711
 
            last_rev = _mod_revision.ensure_null(self.last_revision())
712
 
            # we fetch here so that we don't process data twice in the common
713
 
            # case of having something to pull, and so that the check for 
714
 
            # already merged can operate on the just fetched graph, which will
715
 
            # be cached in memory.
716
 
            self.fetch(other, stop_revision)
717
 
            # Check to see if one is an ancestor of the other
718
 
            if not overwrite:
719
 
                if graph is None:
720
 
                    graph = self.repository.get_graph()
721
 
                if self._check_if_descendant_or_diverged(
722
 
                        stop_revision, last_rev, graph, other):
723
 
                    # stop_revision is a descendant of last_rev, but we aren't
724
 
                    # overwriting, so we're done.
725
 
                    return
726
 
            if stop_revno is None:
727
 
                if graph is None:
728
 
                    graph = self.repository.get_graph()
729
 
                this_revno, this_last_revision = self.last_revision_info()
730
 
                stop_revno = graph.find_distance_to_null(stop_revision,
731
 
                                [(other_last_revision, other_revno),
732
 
                                 (this_last_revision, this_revno)])
733
 
            self.set_last_revision_info(stop_revno, stop_revision)
734
 
        finally:
735
 
            other.unlock()
 
706
        return InterBranch.get(other, self).update_revisions(stop_revision,
 
707
            overwrite, graph)
736
708
 
737
709
    def revision_id_to_revno(self, revision_id):
738
710
        """Given a revision id, return its revno"""
778
750
    def get_parent(self):
779
751
        """Return the parent location of the branch.
780
752
 
781
 
        This is the default location for push/pull/missing.  The usual
 
753
        This is the default location for pull/missing.  The usual
782
754
        pattern is that the user can override it by specifying a
783
755
        location.
784
756
        """
881
853
 
882
854
    @needs_write_lock
883
855
    def update(self):
884
 
        """Synchronise this branch with the master branch if any. 
 
856
        """Synchronise this branch with the master branch if any.
885
857
 
886
858
        :return: None or the last_revision pivoted out during the update.
887
859
        """
894
866
        """
895
867
        if revno != 0:
896
868
            self.check_real_revno(revno)
897
 
            
 
869
 
898
870
    def check_real_revno(self, revno):
899
871
        """\
900
872
        Check whether a revno corresponds to a real revision.
904
876
            raise errors.InvalidRevisionNumber(revno)
905
877
 
906
878
    @needs_read_lock
907
 
    def clone(self, to_bzrdir, revision_id=None):
 
879
    def clone(self, to_bzrdir, revision_id=None, repository_policy=None):
908
880
        """Clone this branch into to_bzrdir preserving all semantic values.
909
 
        
 
881
 
 
882
        Most API users will want 'create_clone_on_transport', which creates a
 
883
        new bzrdir and branch on the fly.
 
884
 
910
885
        revision_id: if not None, the revision history in the new branch will
911
886
                     be truncated to end with revision_id.
912
887
        """
913
888
        result = to_bzrdir.create_branch()
 
889
        if repository_policy is not None:
 
890
            repository_policy.configure_branch(result)
914
891
        self.copy_content_into(result, revision_id=revision_id)
915
892
        return  result
916
893
 
956
933
            revno = len(list(self.repository.iter_reverse_revision_history(
957
934
                                                                revision_id)))
958
935
        destination.set_last_revision_info(revno, revision_id)
959
 
    
 
936
 
960
937
    @needs_read_lock
961
938
    def copy_content_into(self, destination, revision_id=None):
962
939
        """Copy the content of self into destination.
972
949
        else:
973
950
            if parent:
974
951
                destination.set_parent(parent)
975
 
        self.tags.merge_to(destination.tags)
 
952
        if self._push_should_merge_tags():
 
953
            self.tags.merge_to(destination.tags)
976
954
 
977
955
    @needs_read_lock
978
956
    def check(self):
979
957
        """Check consistency of the branch.
980
958
 
981
959
        In particular this checks that revisions given in the revision-history
982
 
        do actually match up in the revision graph, and that they're all 
 
960
        do actually match up in the revision graph, and that they're all
983
961
        present in the repository.
984
 
        
 
962
 
985
963
        Callers will typically also want to check the repository.
986
964
 
987
965
        :return: A BranchCheckResult.
1026
1004
            format.set_branch_format(self._format)
1027
1005
        return format
1028
1006
 
 
1007
    def create_clone_on_transport(self, to_transport, revision_id=None,
 
1008
        stacked_on=None):
 
1009
        """Create a clone of this branch and its bzrdir.
 
1010
 
 
1011
        :param to_transport: The transport to clone onto.
 
1012
        :param revision_id: The revision id to use as tip in the new branch.
 
1013
            If None the tip is obtained from this branch.
 
1014
        :param stacked_on: An optional URL to stack the clone on.
 
1015
        """
 
1016
        # XXX: Fix the bzrdir API to allow getting the branch back from the
 
1017
        # clone call. Or something. 20090224 RBC/spiv.
 
1018
        dir_to = self.bzrdir.clone_on_transport(to_transport,
 
1019
            revision_id=revision_id, stacked_on=stacked_on)
 
1020
        return dir_to.open_branch()
 
1021
 
1029
1022
    def create_checkout(self, to_location, revision_id=None,
1030
1023
                        lightweight=False, accelerator_tree=None,
1031
1024
                        hardlink=False):
1032
1025
        """Create a checkout of a branch.
1033
 
        
 
1026
 
1034
1027
        :param to_location: The url to produce the checkout at
1035
1028
        :param revision_id: The revision to check out
1036
1029
        :param lightweight: If True, produce a lightweight checkout, otherwise,
1055
1048
                to_location, force_new_tree=False, format=format)
1056
1049
            checkout = checkout_branch.bzrdir
1057
1050
            checkout_branch.bind(self)
1058
 
            # pull up to the specified revision_id to set the initial 
 
1051
            # pull up to the specified revision_id to set the initial
1059
1052
            # branch tip correctly, and seed it with history.
1060
1053
            checkout_branch.pull(self, stop_revision=revision_id)
1061
1054
            from_branch=None
1100
1093
        """Ensure that revision_b is a descendant of revision_a.
1101
1094
 
1102
1095
        This is a helper function for update_revisions.
1103
 
        
 
1096
 
1104
1097
        :raises: DivergedBranches if revision_b has diverged from revision_a.
1105
1098
        :returns: True if revision_b is a descendant of revision_a.
1106
1099
        """
1116
1109
 
1117
1110
    def _revision_relations(self, revision_a, revision_b, graph):
1118
1111
        """Determine the relationship between two revisions.
1119
 
        
 
1112
 
1120
1113
        :returns: One of: 'a_descends_from_b', 'b_descends_from_a', 'diverged'
1121
1114
        """
1122
1115
        heads = graph.heads([revision_a, revision_b])
1139
1132
     * a format string,
1140
1133
     * an open routine.
1141
1134
 
1142
 
    Formats are placed in an dict by their format string for reference 
 
1135
    Formats are placed in an dict by their format string for reference
1143
1136
    during branch opening. Its not required that these be instances, they
1144
 
    can be classes themselves with class methods - it simply depends on 
 
1137
    can be classes themselves with class methods - it simply depends on
1145
1138
    whether state is needed for a given format or not.
1146
1139
 
1147
1140
    Once a format is deprecated, just deprecate the initialize and open
1148
 
    methods on the format class. Do not deprecate the object, as the 
 
1141
    methods on the format class. Do not deprecate the object, as the
1149
1142
    object will be created every time regardless.
1150
1143
    """
1151
1144
 
1253
1246
        """Is this format supported?
1254
1247
 
1255
1248
        Supported formats can be initialized and opened.
1256
 
        Unsupported formats may not support initialization or committing or 
 
1249
        Unsupported formats may not support initialization or committing or
1257
1250
        some other features depending on the reason for not being supported.
1258
1251
        """
1259
1252
        return True
1260
1253
 
 
1254
    def network_name(self):
 
1255
        """A simple byte string uniquely identifying this format for RPC calls.
 
1256
 
 
1257
        MetaDir branch formats use their disk format string to identify the
 
1258
        repository over the wire. All in one formats such as bzr < 0.8, and
 
1259
        foreign formats like svn/git and hg should use some marker which is
 
1260
        unique and immutable.
 
1261
        """
 
1262
        raise NotImplementedError(self.network_name)
 
1263
 
1261
1264
    def open(self, a_bzrdir, _found=False):
1262
1265
        """Return the branch object for a_bzrdir
1263
1266
 
1268
1271
 
1269
1272
    @classmethod
1270
1273
    def register_format(klass, format):
 
1274
        """Register a metadir format."""
1271
1275
        klass._formats[format.get_format_string()] = format
 
1276
        # Metadir formats have a network name of their format string.
 
1277
        network_format_registry.register(format.get_format_string(), format)
1272
1278
 
1273
1279
    @classmethod
1274
1280
    def set_default_format(klass, format):
1283
1289
        del klass._formats[format.get_format_string()]
1284
1290
 
1285
1291
    def __str__(self):
1286
 
        return self.get_format_string().rstrip()
 
1292
        return self.get_format_description().rstrip()
1287
1293
 
1288
1294
    def supports_tags(self):
1289
1295
        """True if this format supports tags stored in the branch"""
1292
1298
 
1293
1299
class BranchHooks(Hooks):
1294
1300
    """A dictionary mapping hook name to a list of callables for branch hooks.
1295
 
    
 
1301
 
1296
1302
    e.g. ['set_rh'] Is the list of items to be called when the
1297
1303
    set_revision_history function is invoked.
1298
1304
    """
1317
1323
        # (push_result)
1318
1324
        # containing the members
1319
1325
        # (source, local, master, old_revno, old_revid, new_revno, new_revid)
1320
 
        # where local is the local target branch or None, master is the target 
 
1326
        # where local is the local target branch or None, master is the target
1321
1327
        # master branch, and the rest should be self explanatory. The source
1322
1328
        # is read locked and the target branches write locked. Source will
1323
1329
        # be the local low-latency branch.
1327
1333
        # (pull_result)
1328
1334
        # containing the members
1329
1335
        # (source, local, master, old_revno, old_revid, new_revno, new_revid)
1330
 
        # where local is the local branch or None, master is the target 
 
1336
        # where local is the local branch or None, master is the target
1331
1337
        # master branch, and the rest should be self explanatory. The source
1332
1338
        # is read locked and the target branches write locked. The local
1333
1339
        # branch is the low-latency branch.
1343
1349
        # CommitBuilder.revision_tree() and hooks MUST NOT modify this tree
1344
1350
        self['pre_commit'] = []
1345
1351
        # invoked after a commit operation completes.
1346
 
        # the api signature is 
 
1352
        # the api signature is
1347
1353
        # (local, master, old_revno, old_revid, new_revno, new_revid)
1348
1354
        # old_revid is NULL_REVISION for the first commit to a branch.
1349
1355
        self['post_commit'] = []
1410
1416
 
1411
1417
    def __eq__(self, other):
1412
1418
        return self.__dict__ == other.__dict__
1413
 
    
 
1419
 
1414
1420
    def __repr__(self):
1415
1421
        return "<%s of %s from (%s, %s) to (%s, %s)>" % (
1416
 
            self.__class__.__name__, self.branch, 
 
1422
            self.__class__.__name__, self.branch,
1417
1423
            self.old_revno, self.old_revid, self.new_revno, self.new_revid)
1418
1424
 
1419
1425
 
1441
1447
        super(BzrBranchFormat4, self).__init__()
1442
1448
        self._matchingbzrdir = bzrdir.BzrDirFormat6()
1443
1449
 
 
1450
    def network_name(self):
 
1451
        """The network name for this format is the control dirs disk label."""
 
1452
        return self._matchingbzrdir.get_format_string()
 
1453
 
1444
1454
    def open(self, a_bzrdir, _found=False):
1445
1455
        """Return the branch object for a_bzrdir
1446
1456
 
1466
1476
        """What class to instantiate on open calls."""
1467
1477
        raise NotImplementedError(self._branch_class)
1468
1478
 
 
1479
    def network_name(self):
 
1480
        """A simple byte string uniquely identifying this format for RPC calls.
 
1481
 
 
1482
        Metadir branch formats use their format string.
 
1483
        """
 
1484
        return self.get_format_string()
 
1485
 
1469
1486
    def open(self, a_bzrdir, _found=False):
1470
1487
        """Return the branch object for a_bzrdir.
1471
1488
 
1520
1537
    def get_format_description(self):
1521
1538
        """See BranchFormat.get_format_description()."""
1522
1539
        return "Branch format 5"
1523
 
        
 
1540
 
1524
1541
    def initialize(self, a_bzrdir):
1525
1542
        """Create a branch of this format in a_bzrdir."""
1526
1543
        utf8_files = [('revision-history', ''),
1651
1668
 
1652
1669
    def _make_reference_clone_function(format, a_branch):
1653
1670
        """Create a clone() routine for a branch dynamically."""
1654
 
        def clone(to_bzrdir, revision_id=None):
 
1671
        def clone(to_bzrdir, revision_id=None,
 
1672
            repository_policy=None):
1655
1673
            """See Branch.clone()."""
1656
1674
            return format.initialize(to_bzrdir, a_branch)
1657
1675
            # cannot obey revision_id limits when cloning a reference ...
1688
1706
        return result
1689
1707
 
1690
1708
 
 
1709
network_format_registry = registry.FormatRegistry()
 
1710
"""Registry of formats indexed by their network name.
 
1711
 
 
1712
The network name for a repository format is an identifier that can be used when
 
1713
referring to formats with smart server operations. See
 
1714
BranchFormat.network_name() for more detail.
 
1715
"""
 
1716
 
 
1717
 
1691
1718
# formats which have no format string are not discoverable
1692
1719
# and not independently creatable, so are not registered.
1693
1720
__format5 = BzrBranchFormat5()
1699
1726
BranchFormat.register_format(__format7)
1700
1727
BranchFormat.set_default_format(__format6)
1701
1728
_legacy_formats = [BzrBranchFormat4(),
1702
 
                   ]
 
1729
    ]
 
1730
network_format_registry.register(
 
1731
    _legacy_formats[0].network_name(), _legacy_formats[0])
 
1732
 
1703
1733
 
1704
1734
class BzrBranch(Branch):
1705
1735
    """A branch stored in the actual filesystem.
1708
1738
    really matter if it's on an nfs/smb/afs/coda/... share, as long as
1709
1739
    it's writable, and can be accessed via the normal filesystem API.
1710
1740
 
1711
 
    :ivar _transport: Transport for file operations on this branch's 
 
1741
    :ivar _transport: Transport for file operations on this branch's
1712
1742
        control files, typically pointing to the .bzr/branch directory.
1713
1743
    :ivar repository: Repository for this branch.
1714
 
    :ivar base: The url of the base directory for this branch; the one 
 
1744
    :ivar base: The url of the base directory for this branch; the one
1715
1745
        containing the .bzr directory.
1716
1746
    """
1717
 
    
 
1747
 
1718
1748
    def __init__(self, _format=None,
1719
1749
                 _control_files=None, a_bzrdir=None, _repository=None):
1720
1750
        """Create new branch object at a particular location."""
1774
1804
        if not self.control_files.is_locked():
1775
1805
            # we just released the lock
1776
1806
            self._clear_cached_state()
1777
 
        
 
1807
 
1778
1808
    def peek_lock_mode(self):
1779
1809
        if self.control_files._lock_count == 0:
1780
1810
            return None
1860
1890
        for this revision id.
1861
1891
 
1862
1892
        It may be possible to set the branch last revision to an id not
1863
 
        present in the repository.  However, branches can also be 
 
1893
        present in the repository.  However, branches can also be
1864
1894
        configured to check constraints on history, in which case this may not
1865
1895
        be permitted.
1866
1896
        """
1904
1934
             _override_hook_target=None):
1905
1935
        """See Branch.pull.
1906
1936
 
1907
 
        :param _hook_master: Private parameter - set the branch to 
 
1937
        :param _hook_master: Private parameter - set the branch to
1908
1938
            be supplied as the master to pull hooks.
1909
1939
        :param run_hooks: Private parameter - if false, this branch
1910
1940
            is being called because it's the master of the primary branch,
1958
1988
        This is the basic concrete implementation of push()
1959
1989
 
1960
1990
        :param _override_hook_source_branch: If specified, run
1961
 
        the hooks passing this Branch as the source, rather than self.  
 
1991
        the hooks passing this Branch as the source, rather than self.
1962
1992
        This is for use of RemoteBranch, where push is delegated to the
1963
 
        underlying vfs-based Branch. 
 
1993
        underlying vfs-based Branch.
1964
1994
        """
1965
1995
        # TODO: Public option to disable running hooks - should be trivial but
1966
1996
        # needs tests.
1973
2003
            stop_revision,
1974
2004
            _override_hook_source_branch=None):
1975
2005
        """Push from self into target, and into target's master if any.
1976
 
        
1977
 
        This is on the base BzrBranch class even though it doesn't support 
 
2006
 
 
2007
        This is on the base BzrBranch class even though it doesn't support
1978
2008
        bound branches because the *target* might be bound.
1979
2009
        """
1980
2010
        def _run_hooks():
2035
2065
        result.new_revno, result.new_revid = target.last_revision_info()
2036
2066
        return result
2037
2067
 
2038
 
    def _push_should_merge_tags(self):
2039
 
        """Should _basic_push merge this branch's tags into the target?
2040
 
        
2041
 
        The default implementation returns False if this branch has no tags,
2042
 
        and True the rest of the time.  Subclasses may override this.
2043
 
        """
2044
 
        return self.tags.supports_tags() and self.tags.get_tag_dict()
2045
 
 
2046
2068
    def get_parent(self):
2047
2069
        """See Branch.get_parent."""
2048
2070
        parent = self._get_parent_location()
2106
2128
             run_hooks=True, possible_transports=None,
2107
2129
             _override_hook_target=None):
2108
2130
        """Pull from source into self, updating my master if any.
2109
 
        
 
2131
 
2110
2132
        :param run_hooks: Private parameter - if false, this branch
2111
2133
            is being called because it's the master of the primary branch,
2112
2134
            so it should not run its hooks.
2139
2161
    @needs_read_lock
2140
2162
    def get_master_branch(self, possible_transports=None):
2141
2163
        """Return the branch we are bound to.
2142
 
        
 
2164
 
2143
2165
        :return: Either a Branch, or None
2144
2166
 
2145
2167
        This could memoise the branch, but if thats done
2181
2203
        check for divergence to raise an error when the branches are not
2182
2204
        either the same, or one a prefix of the other. That behaviour may not
2183
2205
        be useful, so that check may be removed in future.
2184
 
        
 
2206
 
2185
2207
        :param other: The branch to bind to
2186
2208
        :type other: Branch
2187
2209
        """
2206
2228
 
2207
2229
    @needs_write_lock
2208
2230
    def update(self, possible_transports=None):
2209
 
        """Synchronise this branch with the master branch if any. 
 
2231
        """Synchronise this branch with the master branch if any.
2210
2232
 
2211
2233
        :return: None or the last_revision that was pivoted out during the
2212
2234
                 update.
2303
2325
 
2304
2326
    def _synchronize_history(self, destination, revision_id):
2305
2327
        """Synchronize last revision and revision history between branches.
2306
 
        
 
2328
 
2307
2329
        :see: Branch._synchronize_history
2308
2330
        """
2309
2331
        # XXX: The base Branch has a fast implementation of this method based
2589
2611
    def report(self, to_file):
2590
2612
        """Write a human-readable description of the result."""
2591
2613
        if self.old_revid == self.new_revid:
2592
 
            to_file.write('No new revisions to push.\n')
 
2614
            note('No new revisions to push.')
2593
2615
        else:
2594
 
            to_file.write('Pushed up to revision %d.\n' % self.new_revno)
 
2616
            note('Pushed up to revision %d.' % self.new_revno)
2595
2617
        self._show_tag_conficts(to_file)
2596
2618
 
2597
2619
 
2606
2628
 
2607
2629
    def report_results(self, verbose):
2608
2630
        """Report the check results via trace.note.
2609
 
        
 
2631
 
2610
2632
        :param verbose: Requests more detailed display of what was checked,
2611
2633
            if any.
2612
2634
        """
2672
2694
            return callable(*args, **kwargs)
2673
2695
        finally:
2674
2696
            target.unlock()
2675
 
    
 
2697
 
2676
2698
    """
2677
2699
    # This is very similar to bzrlib.decorators.needs_write_lock.  Perhaps they
2678
2700
    # should share code?
2688
2710
    else:
2689
2711
        target.unlock()
2690
2712
        return result
 
2713
 
 
2714
 
 
2715
class InterBranch(InterObject):
 
2716
    """This class represents operations taking place between two branches.
 
2717
 
 
2718
    Its instances have methods like pull() and push() and contain
 
2719
    references to the source and target repositories these operations
 
2720
    can be carried out on.
 
2721
    """
 
2722
 
 
2723
    _optimisers = []
 
2724
    """The available optimised InterBranch types."""
 
2725
 
 
2726
    @staticmethod
 
2727
    def _get_branch_formats_to_test():
 
2728
        """Return a tuple with the Branch formats to use when testing."""
 
2729
        raise NotImplementedError(self._get_branch_formats_to_test)
 
2730
 
 
2731
    def update_revisions(self, stop_revision=None, overwrite=False,
 
2732
                         graph=None):
 
2733
        """Pull in new perfect-fit revisions.
 
2734
 
 
2735
        :param stop_revision: Updated until the given revision
 
2736
        :param overwrite: Always set the branch pointer, rather than checking
 
2737
            to see if it is a proper descendant.
 
2738
        :param graph: A Graph object that can be used to query history
 
2739
            information. This can be None.
 
2740
        :return: None
 
2741
        """
 
2742
        raise NotImplementedError(self.update_revisions)
 
2743
 
 
2744
 
 
2745
class GenericInterBranch(InterBranch):
 
2746
    """InterBranch implementation that uses public Branch functions.
 
2747
    """
 
2748
 
 
2749
    @staticmethod
 
2750
    def _get_branch_formats_to_test():
 
2751
        return BranchFormat._default_format, BranchFormat._default_format
 
2752
 
 
2753
    def update_revisions(self, stop_revision=None, overwrite=False,
 
2754
        graph=None):
 
2755
        """See InterBranch.update_revisions()."""
 
2756
        self.source.lock_read()
 
2757
        try:
 
2758
            other_revno, other_last_revision = self.source.last_revision_info()
 
2759
            stop_revno = None # unknown
 
2760
            if stop_revision is None:
 
2761
                stop_revision = other_last_revision
 
2762
                if _mod_revision.is_null(stop_revision):
 
2763
                    # if there are no commits, we're done.
 
2764
                    return
 
2765
                stop_revno = other_revno
 
2766
 
 
2767
            # what's the current last revision, before we fetch [and change it
 
2768
            # possibly]
 
2769
            last_rev = _mod_revision.ensure_null(self.target.last_revision())
 
2770
            # we fetch here so that we don't process data twice in the common
 
2771
            # case of having something to pull, and so that the check for
 
2772
            # already merged can operate on the just fetched graph, which will
 
2773
            # be cached in memory.
 
2774
            self.target.fetch(self.source, stop_revision)
 
2775
            # Check to see if one is an ancestor of the other
 
2776
            if not overwrite:
 
2777
                if graph is None:
 
2778
                    graph = self.target.repository.get_graph()
 
2779
                if self.target._check_if_descendant_or_diverged(
 
2780
                        stop_revision, last_rev, graph, self.source):
 
2781
                    # stop_revision is a descendant of last_rev, but we aren't
 
2782
                    # overwriting, so we're done.
 
2783
                    return
 
2784
            if stop_revno is None:
 
2785
                if graph is None:
 
2786
                    graph = self.target.repository.get_graph()
 
2787
                this_revno, this_last_revision = \
 
2788
                        self.target.last_revision_info()
 
2789
                stop_revno = graph.find_distance_to_null(stop_revision,
 
2790
                                [(other_last_revision, other_revno),
 
2791
                                 (this_last_revision, this_revno)])
 
2792
            self.target.set_last_revision_info(stop_revno, stop_revision)
 
2793
        finally:
 
2794
            self.source.unlock()
 
2795
 
 
2796
    @classmethod
 
2797
    def is_compatible(self, source, target):
 
2798
        # GenericBranch uses the public API, so always compatible
 
2799
        return True
 
2800
 
 
2801
 
 
2802
InterBranch.register_optimiser(GenericInterBranch)