/brz/remove-bazaar

To get this branch, use:
bzr branch http://gegoxaren.bato24.eu/bzr/brz/remove-bazaar

« back to all changes in this revision

Viewing changes to bzrlib/branch.py

  • Committer: Vincent Ladeuil
  • Date: 2011-05-17 15:14:38 UTC
  • mfrom: (5050.73.3 2.2)
  • mto: (5609.39.5 2.3)
  • mto: This revision was merged to the branch mainline in revision 5885.
  • Revision ID: v.ladeuil+lp@free.fr-20110517151438-j75xuw2zm9alk9a5
Merge 2.2 into 2.3 resolving conflicts

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# Copyright (C) 2005-2010 Canonical Ltd
 
1
# Copyright (C) 2005-2011 Canonical Ltd
2
2
#
3
3
# This program is free software; you can redistribute it and/or modify
4
4
# it under the terms of the GNU General Public License as published by
25
25
        bzrdir,
26
26
        cache_utf8,
27
27
        config as _mod_config,
 
28
        controldir,
28
29
        debug,
29
30
        errors,
30
31
        lockdir,
31
32
        lockable_files,
 
33
        remote,
32
34
        repository,
33
35
        revision as _mod_revision,
34
36
        rio,
49
51
from bzrlib.decorators import needs_read_lock, needs_write_lock, only_raises
50
52
from bzrlib.hooks import HookPoint, Hooks
51
53
from bzrlib.inter import InterObject
52
 
from bzrlib.lock import _RelockDebugMixin
 
54
from bzrlib.lock import _RelockDebugMixin, LogicalLockResult
53
55
from bzrlib import registry
54
56
from bzrlib.symbol_versioning import (
55
57
    deprecated_in,
63
65
BZR_BRANCH_FORMAT_6 = "Bazaar Branch Format 6 (bzr 0.15)\n"
64
66
 
65
67
 
66
 
class Branch(bzrdir.ControlComponent):
 
68
class Branch(controldir.ControlComponent):
67
69
    """Branch holding a history of revisions.
68
70
 
69
71
    :ivar base:
70
72
        Base directory/url of the branch; using control_url and
71
73
        control_transport is more standardized.
72
 
 
73
 
    hooks: An instance of BranchHooks.
 
74
    :ivar hooks: An instance of BranchHooks.
 
75
    :ivar _master_branch_cache: cached result of get_master_branch, see
 
76
        _clear_cached_state.
74
77
    """
75
78
    # this is really an instance variable - FIXME move it there
76
79
    # - RBC 20060112
90
93
        self._revision_id_to_revno_cache = None
91
94
        self._partial_revision_id_to_revno_cache = {}
92
95
        self._partial_revision_history_cache = []
 
96
        self._tags_bytes = None
93
97
        self._last_revision_info_cache = None
 
98
        self._master_branch_cache = None
94
99
        self._merge_sorted_revisions_cache = None
95
100
        self._open_hook()
96
101
        hooks = Branch.hooks['open']
102
107
 
103
108
    def _activate_fallback_location(self, url):
104
109
        """Activate the branch/repository from url as a fallback repository."""
 
110
        for existing_fallback_repo in self.repository._fallback_repositories:
 
111
            if existing_fallback_repo.user_url == url:
 
112
                # This fallback is already configured.  This probably only
 
113
                # happens because BzrDir.sprout is a horrible mess.  To avoid
 
114
                # confusing _unstack we don't add this a second time.
 
115
                mutter('duplicate activation of fallback %r on %r', url, self)
 
116
                return
105
117
        repo = self._get_fallback_repository(url)
106
118
        if repo.has_same_location(self.repository):
107
119
            raise errors.UnstackableLocationError(self.user_url, url)
197
209
        return self.supports_tags() and self.tags.get_tag_dict()
198
210
 
199
211
    def get_config(self):
 
212
        """Get a bzrlib.config.BranchConfig for this Branch.
 
213
 
 
214
        This can then be used to get and set configuration options for the
 
215
        branch.
 
216
 
 
217
        :return: A bzrlib.config.BranchConfig.
 
218
        """
200
219
        return BranchConfig(self)
201
220
 
202
221
    def _get_config(self):
218
237
            possible_transports=[self.bzrdir.root_transport])
219
238
        return a_branch.repository
220
239
 
 
240
    @needs_read_lock
221
241
    def _get_tags_bytes(self):
222
242
        """Get the bytes of a serialised tags dict.
223
243
 
230
250
        :return: The bytes of the tags file.
231
251
        :seealso: Branch._set_tags_bytes.
232
252
        """
233
 
        return self._transport.get_bytes('tags')
 
253
        if self._tags_bytes is None:
 
254
            self._tags_bytes = self._transport.get_bytes('tags')
 
255
        return self._tags_bytes
234
256
 
235
257
    def _get_nick(self, local=False, possible_transports=None):
236
258
        config = self.get_config()
238
260
        if not local and not config.has_explicit_nickname():
239
261
            try:
240
262
                master = self.get_master_branch(possible_transports)
 
263
                if master and self.user_url == master.user_url:
 
264
                    raise errors.RecursiveBind(self.user_url)
241
265
                if master is not None:
242
266
                    # return the master branch value
243
267
                    return master.nick
 
268
            except errors.RecursiveBind, e:
 
269
                raise e
244
270
            except errors.BzrError, e:
245
271
                # Silently fall back to local implicit nick if the master is
246
272
                # unavailable
283
309
        new_history.reverse()
284
310
        return new_history
285
311
 
286
 
    def lock_write(self):
 
312
    def lock_write(self, token=None):
 
313
        """Lock the branch for write operations.
 
314
 
 
315
        :param token: A token to permit reacquiring a previously held and
 
316
            preserved lock.
 
317
        :return: A BranchWriteLockResult.
 
318
        """
287
319
        raise NotImplementedError(self.lock_write)
288
320
 
289
321
    def lock_read(self):
 
322
        """Lock the branch for read operations.
 
323
 
 
324
        :return: A bzrlib.lock.LogicalLockResult.
 
325
        """
290
326
        raise NotImplementedError(self.lock_read)
291
327
 
292
328
    def unlock(self):
782
818
            old_repository = self.repository
783
819
            if len(old_repository._fallback_repositories) != 1:
784
820
                raise AssertionError("can't cope with fallback repositories "
785
 
                    "of %r" % (self.repository,))
786
 
            # unlock it, including unlocking the fallback
 
821
                    "of %r (fallbacks: %r)" % (old_repository,
 
822
                        old_repository._fallback_repositories))
 
823
            # Open the new repository object.
 
824
            # Repositories don't offer an interface to remove fallback
 
825
            # repositories today; take the conceptually simpler option and just
 
826
            # reopen it.  We reopen it starting from the URL so that we
 
827
            # get a separate connection for RemoteRepositories and can
 
828
            # stream from one of them to the other.  This does mean doing
 
829
            # separate SSH connection setup, but unstacking is not a
 
830
            # common operation so it's tolerable.
 
831
            new_bzrdir = bzrdir.BzrDir.open(self.bzrdir.root_transport.base)
 
832
            new_repository = new_bzrdir.find_repository()
 
833
            if new_repository._fallback_repositories:
 
834
                raise AssertionError("didn't expect %r to have "
 
835
                    "fallback_repositories"
 
836
                    % (self.repository,))
 
837
            # Replace self.repository with the new repository.
 
838
            # Do our best to transfer the lock state (i.e. lock-tokens and
 
839
            # lock count) of self.repository to the new repository.
 
840
            lock_token = old_repository.lock_write().repository_token
 
841
            self.repository = new_repository
 
842
            if isinstance(self, remote.RemoteBranch):
 
843
                # Remote branches can have a second reference to the old
 
844
                # repository that need to be replaced.
 
845
                if self._real_branch is not None:
 
846
                    self._real_branch.repository = new_repository
 
847
            self.repository.lock_write(token=lock_token)
 
848
            if lock_token is not None:
 
849
                old_repository.leave_lock_in_place()
787
850
            old_repository.unlock()
 
851
            if lock_token is not None:
 
852
                # XXX: self.repository.leave_lock_in_place() before this
 
853
                # function will not be preserved.  Fortunately that doesn't
 
854
                # affect the current default format (2a), and would be a
 
855
                # corner-case anyway.
 
856
                #  - Andrew Bennetts, 2010/06/30
 
857
                self.repository.dont_leave_lock_in_place()
 
858
            old_lock_count = 0
 
859
            while True:
 
860
                try:
 
861
                    old_repository.unlock()
 
862
                except errors.LockNotHeld:
 
863
                    break
 
864
                old_lock_count += 1
 
865
            if old_lock_count == 0:
 
866
                raise AssertionError(
 
867
                    'old_repository should have been locked at least once.')
 
868
            for i in range(old_lock_count-1):
 
869
                self.repository.lock_write()
 
870
            # Fetch from the old repository into the new.
788
871
            old_repository.lock_read()
789
872
            try:
790
 
                # Repositories don't offer an interface to remove fallback
791
 
                # repositories today; take the conceptually simpler option and just
792
 
                # reopen it.  We reopen it starting from the URL so that we
793
 
                # get a separate connection for RemoteRepositories and can
794
 
                # stream from one of them to the other.  This does mean doing
795
 
                # separate SSH connection setup, but unstacking is not a
796
 
                # common operation so it's tolerable.
797
 
                new_bzrdir = bzrdir.BzrDir.open(self.bzrdir.root_transport.base)
798
 
                new_repository = new_bzrdir.find_repository()
799
 
                self.repository = new_repository
800
 
                if self.repository._fallback_repositories:
801
 
                    raise AssertionError("didn't expect %r to have "
802
 
                        "fallback_repositories"
803
 
                        % (self.repository,))
804
 
                # this is not paired with an unlock because it's just restoring
805
 
                # the previous state; the lock's released when set_stacked_on_url
806
 
                # returns
807
 
                self.repository.lock_write()
808
873
                # XXX: If you unstack a branch while it has a working tree
809
874
                # with a pending merge, the pending-merged revisions will no
810
875
                # longer be present.  You can (probably) revert and remerge.
825
890
 
826
891
        :seealso: Branch._get_tags_bytes.
827
892
        """
828
 
        return _run_with_write_locked_target(self, self._transport.put_bytes,
829
 
            'tags', bytes)
 
893
        return _run_with_write_locked_target(self, self._set_tags_bytes_locked,
 
894
                bytes)
 
895
 
 
896
    def _set_tags_bytes_locked(self, bytes):
 
897
        self._tags_bytes = bytes
 
898
        return self._transport.put_bytes('tags', bytes)
830
899
 
831
900
    def _cache_revision_history(self, rev_history):
832
901
        """Set the cached revision history to rev_history.
859
928
        self._revision_history_cache = None
860
929
        self._revision_id_to_revno_cache = None
861
930
        self._last_revision_info_cache = None
 
931
        self._master_branch_cache = None
862
932
        self._merge_sorted_revisions_cache = None
863
933
        self._partial_revision_history_cache = []
864
934
        self._partial_revision_id_to_revno_cache = {}
 
935
        self._tags_bytes = None
865
936
 
866
937
    def _gen_revision_history(self):
867
938
        """Return sequence of revision hashes on to this branch.
951
1022
                raise errors.NoSuchRevision(self, stop_revision)
952
1023
        return other_history[self_len:stop_revision]
953
1024
 
954
 
    @needs_write_lock
955
1025
    def update_revisions(self, other, stop_revision=None, overwrite=False,
956
1026
                         graph=None):
957
1027
        """Pull in new perfect-fit revisions.
1006
1076
            self._extend_partial_history(distance_from_last)
1007
1077
        return self._partial_revision_history_cache[distance_from_last]
1008
1078
 
1009
 
    @needs_write_lock
1010
1079
    def pull(self, source, overwrite=False, stop_revision=None,
1011
1080
             possible_transports=None, *args, **kwargs):
1012
1081
        """Mirror source into this branch.
1208
1277
        return result
1209
1278
 
1210
1279
    @needs_read_lock
1211
 
    def sprout(self, to_bzrdir, revision_id=None, repository_policy=None):
 
1280
    def sprout(self, to_bzrdir, revision_id=None, repository_policy=None,
 
1281
            repository=None):
1212
1282
        """Create a new line of development from the branch, into to_bzrdir.
1213
1283
 
1214
1284
        to_bzrdir controls the branch format.
1219
1289
        if (repository_policy is not None and
1220
1290
            repository_policy.requires_stacking()):
1221
1291
            to_bzrdir._format.require_stacking(_skip_repo=True)
1222
 
        result = to_bzrdir.create_branch()
 
1292
        result = to_bzrdir.create_branch(repository=repository)
1223
1293
        result.lock_write()
1224
1294
        try:
1225
1295
            if repository_policy is not None:
1255
1325
                revno = 1
1256
1326
        destination.set_last_revision_info(revno, revision_id)
1257
1327
 
1258
 
    @needs_read_lock
1259
1328
    def copy_content_into(self, destination, revision_id=None):
1260
1329
        """Copy the content of self into destination.
1261
1330
 
1262
1331
        revision_id: if not None, the revision history in the new branch will
1263
1332
                     be truncated to end with revision_id.
1264
1333
        """
1265
 
        self.update_references(destination)
1266
 
        self._synchronize_history(destination, revision_id)
1267
 
        try:
1268
 
            parent = self.get_parent()
1269
 
        except errors.InaccessibleParent, e:
1270
 
            mutter('parent was not accessible to copy: %s', e)
1271
 
        else:
1272
 
            if parent:
1273
 
                destination.set_parent(parent)
1274
 
        if self._push_should_merge_tags():
1275
 
            self.tags.merge_to(destination.tags)
 
1334
        return InterBranch.get(self, destination).copy_content_into(
 
1335
            revision_id=revision_id)
1276
1336
 
1277
1337
    def update_references(self, target):
1278
1338
        if not getattr(self._format, 'supports_reference_locations', False):
1323
1383
        """Return the most suitable metadir for a checkout of this branch.
1324
1384
        Weaves are used if this branch's repository uses weaves.
1325
1385
        """
1326
 
        if isinstance(self.bzrdir, bzrdir.BzrDirPreSplitOut):
1327
 
            from bzrlib.repofmt import weaverepo
1328
 
            format = bzrdir.BzrDirMetaFormat1()
1329
 
            format.repository_format = weaverepo.RepositoryFormat7()
1330
 
        else:
1331
 
            format = self.repository.bzrdir.checkout_metadir()
1332
 
            format.set_branch_format(self._format)
 
1386
        format = self.repository.bzrdir.checkout_metadir()
 
1387
        format.set_branch_format(self._format)
1333
1388
        return format
1334
1389
 
1335
1390
    def create_clone_on_transport(self, to_transport, revision_id=None,
1336
 
        stacked_on=None, create_prefix=False, use_existing_dir=False):
 
1391
        stacked_on=None, create_prefix=False, use_existing_dir=False,
 
1392
        no_tree=None):
1337
1393
        """Create a clone of this branch and its bzrdir.
1338
1394
 
1339
1395
        :param to_transport: The transport to clone onto.
1346
1402
        """
1347
1403
        # XXX: Fix the bzrdir API to allow getting the branch back from the
1348
1404
        # clone call. Or something. 20090224 RBC/spiv.
 
1405
        # XXX: Should this perhaps clone colocated branches as well, 
 
1406
        # rather than just the default branch? 20100319 JRV
1349
1407
        if revision_id is None:
1350
1408
            revision_id = self.last_revision()
1351
1409
        dir_to = self.bzrdir.clone_on_transport(to_transport,
1352
1410
            revision_id=revision_id, stacked_on=stacked_on,
1353
 
            create_prefix=create_prefix, use_existing_dir=use_existing_dir)
 
1411
            create_prefix=create_prefix, use_existing_dir=use_existing_dir,
 
1412
            no_tree=no_tree)
1354
1413
        return dir_to.open_branch()
1355
1414
 
1356
1415
    def create_checkout(self, to_location, revision_id=None,
1481
1540
     * an open routine.
1482
1541
 
1483
1542
    Formats are placed in an dict by their format string for reference
1484
 
    during branch opening. Its not required that these be instances, they
 
1543
    during branch opening. It's not required that these be instances, they
1485
1544
    can be classes themselves with class methods - it simply depends on
1486
1545
    whether state is needed for a given format or not.
1487
1546
 
1510
1569
        try:
1511
1570
            transport = a_bzrdir.get_branch_transport(None, name=name)
1512
1571
            format_string = transport.get_bytes("format")
1513
 
            return klass._formats[format_string]
 
1572
            format = klass._formats[format_string]
 
1573
            if isinstance(format, MetaDirBranchFormatFactory):
 
1574
                return format()
 
1575
            return format
1514
1576
        except errors.NoSuchFile:
1515
1577
            raise errors.NotBranchError(path=transport.base, bzrdir=a_bzrdir)
1516
1578
        except KeyError:
1521
1583
        """Return the current default format."""
1522
1584
        return klass._default_format
1523
1585
 
1524
 
    def get_reference(self, a_bzrdir):
 
1586
    @classmethod
 
1587
    def get_formats(klass):
 
1588
        """Get all the known formats.
 
1589
 
 
1590
        Warning: This triggers a load of all lazy registered formats: do not
 
1591
        use except when that is desireed.
 
1592
        """
 
1593
        result = []
 
1594
        for fmt in klass._formats.values():
 
1595
            if isinstance(fmt, MetaDirBranchFormatFactory):
 
1596
                fmt = fmt()
 
1597
            result.append(fmt)
 
1598
        return result
 
1599
 
 
1600
    def get_reference(self, a_bzrdir, name=None):
1525
1601
        """Get the target reference of the branch in a_bzrdir.
1526
1602
 
1527
1603
        format probing must have been completed before calling
1529
1605
        in a_bzrdir is correct.
1530
1606
 
1531
1607
        :param a_bzrdir: The bzrdir to get the branch data from.
 
1608
        :param name: Name of the colocated branch to fetch
1532
1609
        :return: None if the branch is not a reference branch.
1533
1610
        """
1534
1611
        return None
1535
1612
 
1536
1613
    @classmethod
1537
 
    def set_reference(self, a_bzrdir, to_branch):
 
1614
    def set_reference(self, a_bzrdir, name, to_branch):
1538
1615
        """Set the target reference of the branch in a_bzrdir.
1539
1616
 
1540
1617
        format probing must have been completed before calling
1542
1619
        in a_bzrdir is correct.
1543
1620
 
1544
1621
        :param a_bzrdir: The bzrdir to set the branch reference for.
 
1622
        :param name: Name of colocated branch to set, None for default
1545
1623
        :param to_branch: branch that the checkout is to reference
1546
1624
        """
1547
1625
        raise NotImplementedError(self.set_reference)
1563
1641
            hook(params)
1564
1642
 
1565
1643
    def _initialize_helper(self, a_bzrdir, utf8_files, name=None,
1566
 
                           lock_type='metadir', set_format=True):
 
1644
                           repository=None, lock_type='metadir',
 
1645
                           set_format=True):
1567
1646
        """Initialize a branch in a bzrdir, with specified files
1568
1647
 
1569
1648
        :param a_bzrdir: The bzrdir to initialize the branch in
1603
1682
        finally:
1604
1683
            if lock_taken:
1605
1684
                control_files.unlock()
1606
 
        branch = self.open(a_bzrdir, name, _found=True)
 
1685
        branch = self.open(a_bzrdir, name, _found=True,
 
1686
                found_repository=repository)
1607
1687
        self._run_post_branch_init_hooks(a_bzrdir, name, branch)
1608
1688
        return branch
1609
1689
 
1610
 
    def initialize(self, a_bzrdir, name=None):
 
1690
    def initialize(self, a_bzrdir, name=None, repository=None):
1611
1691
        """Create a branch of this format in a_bzrdir.
1612
1692
        
1613
1693
        :param name: Name of the colocated branch to create.
1647
1727
        """
1648
1728
        raise NotImplementedError(self.network_name)
1649
1729
 
1650
 
    def open(self, a_bzrdir, name=None, _found=False, ignore_fallbacks=False):
 
1730
    def open(self, a_bzrdir, name=None, _found=False, ignore_fallbacks=False,
 
1731
            found_repository=None):
1651
1732
        """Return the branch object for a_bzrdir
1652
1733
 
1653
1734
        :param a_bzrdir: A BzrDir that contains a branch.
1661
1742
 
1662
1743
    @classmethod
1663
1744
    def register_format(klass, format):
1664
 
        """Register a metadir format."""
 
1745
        """Register a metadir format.
 
1746
        
 
1747
        See MetaDirBranchFormatFactory for the ability to register a format
 
1748
        without loading the code the format needs until it is actually used.
 
1749
        """
1665
1750
        klass._formats[format.get_format_string()] = format
1666
1751
        # Metadir formats have a network name of their format string, and get
1667
 
        # registered as class factories.
1668
 
        network_format_registry.register(format.get_format_string(), format.__class__)
 
1752
        # registered as factories.
 
1753
        if isinstance(format, MetaDirBranchFormatFactory):
 
1754
            network_format_registry.register(format.get_format_string(), format)
 
1755
        else:
 
1756
            network_format_registry.register(format.get_format_string(),
 
1757
                format.__class__)
1669
1758
 
1670
1759
    @classmethod
1671
1760
    def set_default_format(klass, format):
1691
1780
        return False  # by default
1692
1781
 
1693
1782
 
 
1783
class MetaDirBranchFormatFactory(registry._LazyObjectGetter):
 
1784
    """A factory for a BranchFormat object, permitting simple lazy registration.
 
1785
    
 
1786
    While none of the built in BranchFormats are lazy registered yet,
 
1787
    bzrlib.tests.test_branch.TestMetaDirBranchFormatFactory demonstrates how to
 
1788
    use it, and the bzr-loom plugin uses it as well (see
 
1789
    bzrlib.plugins.loom.formats).
 
1790
    """
 
1791
 
 
1792
    def __init__(self, format_string, module_name, member_name):
 
1793
        """Create a MetaDirBranchFormatFactory.
 
1794
 
 
1795
        :param format_string: The format string the format has.
 
1796
        :param module_name: Module to load the format class from.
 
1797
        :param member_name: Attribute name within the module for the format class.
 
1798
        """
 
1799
        registry._LazyObjectGetter.__init__(self, module_name, member_name)
 
1800
        self._format_string = format_string
 
1801
        
 
1802
    def get_format_string(self):
 
1803
        """See BranchFormat.get_format_string."""
 
1804
        return self._format_string
 
1805
 
 
1806
    def __call__(self):
 
1807
        """Used for network_format_registry support."""
 
1808
        return self.get_obj()()
 
1809
 
 
1810
 
1694
1811
class BranchHooks(Hooks):
1695
1812
    """A dictionary mapping hook name to a list of callables for branch hooks.
1696
1813
 
1723
1840
            "with a bzrlib.branch.PullResult object and only runs in the "
1724
1841
            "bzr client.", (0, 15), None))
1725
1842
        self.create_hook(HookPoint('pre_commit',
1726
 
            "Called after a commit is calculated but before it is is "
 
1843
            "Called after a commit is calculated but before it is "
1727
1844
            "completed. pre_commit is called with (local, master, old_revno, "
1728
1845
            "old_revid, future_revno, future_revid, tree_delta, future_tree"
1729
1846
            "). old_revid is NULL_REVISION for the first commit to a branch, "
1766
1883
            "all are called with the url returned from the previous hook."
1767
1884
            "The order is however undefined.", (1, 9), None))
1768
1885
        self.create_hook(HookPoint('automatic_tag_name',
1769
 
            "Called to determine an automatic tag name for a revision."
 
1886
            "Called to determine an automatic tag name for a revision. "
1770
1887
            "automatic_tag_name is called with (branch, revision_id) and "
1771
1888
            "should return a tag name or None if no tag name could be "
1772
1889
            "determined. The first non-None tag name returned will be used.",
1863
1980
        return self.__dict__ == other.__dict__
1864
1981
 
1865
1982
    def __repr__(self):
1866
 
        if self.branch:
1867
 
            return "<%s of %s>" % (self.__class__.__name__, self.branch)
1868
 
        else:
1869
 
            return "<%s of format:%s bzrdir:%s>" % (
1870
 
                self.__class__.__name__, self.branch,
1871
 
                self.format, self.bzrdir)
 
1983
        return "<%s of %s>" % (self.__class__.__name__, self.branch)
1872
1984
 
1873
1985
 
1874
1986
class SwitchHookParams(object):
1916
2028
        """See BranchFormat.get_format_description()."""
1917
2029
        return "Branch format 4"
1918
2030
 
1919
 
    def initialize(self, a_bzrdir, name=None):
 
2031
    def initialize(self, a_bzrdir, name=None, repository=None):
1920
2032
        """Create a branch of this format in a_bzrdir."""
 
2033
        if repository is not None:
 
2034
            raise NotImplementedError(
 
2035
                "initialize(repository=<not None>) on %r" % (self,))
1921
2036
        utf8_files = [('revision-history', ''),
1922
2037
                      ('branch-name', ''),
1923
2038
                      ]
1932
2047
        """The network name for this format is the control dirs disk label."""
1933
2048
        return self._matchingbzrdir.get_format_string()
1934
2049
 
1935
 
    def open(self, a_bzrdir, name=None, _found=False, ignore_fallbacks=False):
 
2050
    def open(self, a_bzrdir, name=None, _found=False, ignore_fallbacks=False,
 
2051
            found_repository=None):
1936
2052
        """See BranchFormat.open()."""
1937
2053
        if not _found:
1938
2054
            # we are being called directly and must probe.
1939
2055
            raise NotImplementedError
1940
 
        return BzrBranch(_format=self,
 
2056
        if found_repository is None:
 
2057
            found_repository = a_bzrdir.open_repository()
 
2058
        return BzrBranchPreSplitOut(_format=self,
1941
2059
                         _control_files=a_bzrdir._control_files,
1942
2060
                         a_bzrdir=a_bzrdir,
1943
2061
                         name=name,
1944
 
                         _repository=a_bzrdir.open_repository())
 
2062
                         _repository=found_repository)
1945
2063
 
1946
2064
    def __str__(self):
1947
2065
        return "Bazaar-NG branch format 4"
1961
2079
        """
1962
2080
        return self.get_format_string()
1963
2081
 
1964
 
    def open(self, a_bzrdir, name=None, _found=False, ignore_fallbacks=False):
 
2082
    def open(self, a_bzrdir, name=None, _found=False, ignore_fallbacks=False,
 
2083
            found_repository=None):
1965
2084
        """See BranchFormat.open()."""
1966
2085
        if not _found:
1967
2086
            format = BranchFormat.find_format(a_bzrdir, name=name)
1972
2091
        try:
1973
2092
            control_files = lockable_files.LockableFiles(transport, 'lock',
1974
2093
                                                         lockdir.LockDir)
 
2094
            if found_repository is None:
 
2095
                found_repository = a_bzrdir.find_repository()
1975
2096
            return self._branch_class()(_format=self,
1976
2097
                              _control_files=control_files,
1977
2098
                              name=name,
1978
2099
                              a_bzrdir=a_bzrdir,
1979
 
                              _repository=a_bzrdir.find_repository(),
 
2100
                              _repository=found_repository,
1980
2101
                              ignore_fallbacks=ignore_fallbacks)
1981
2102
        except errors.NoSuchFile:
1982
2103
            raise errors.NotBranchError(path=transport.base, bzrdir=a_bzrdir)
2014
2135
        """See BranchFormat.get_format_description()."""
2015
2136
        return "Branch format 5"
2016
2137
 
2017
 
    def initialize(self, a_bzrdir, name=None):
 
2138
    def initialize(self, a_bzrdir, name=None, repository=None):
2018
2139
        """Create a branch of this format in a_bzrdir."""
2019
2140
        utf8_files = [('revision-history', ''),
2020
2141
                      ('branch-name', ''),
2021
2142
                      ]
2022
 
        return self._initialize_helper(a_bzrdir, utf8_files, name)
 
2143
        return self._initialize_helper(a_bzrdir, utf8_files, name, repository)
2023
2144
 
2024
2145
    def supports_tags(self):
2025
2146
        return False
2047
2168
        """See BranchFormat.get_format_description()."""
2048
2169
        return "Branch format 6"
2049
2170
 
2050
 
    def initialize(self, a_bzrdir, name=None):
 
2171
    def initialize(self, a_bzrdir, name=None, repository=None):
2051
2172
        """Create a branch of this format in a_bzrdir."""
2052
2173
        utf8_files = [('last-revision', '0 null:\n'),
2053
2174
                      ('branch.conf', ''),
2054
2175
                      ('tags', ''),
2055
2176
                      ]
2056
 
        return self._initialize_helper(a_bzrdir, utf8_files, name)
 
2177
        return self._initialize_helper(a_bzrdir, utf8_files, name, repository)
2057
2178
 
2058
2179
    def make_tags(self, branch):
2059
2180
        """See bzrlib.branch.BranchFormat.make_tags()."""
2077
2198
        """See BranchFormat.get_format_description()."""
2078
2199
        return "Branch format 8"
2079
2200
 
2080
 
    def initialize(self, a_bzrdir, name=None):
 
2201
    def initialize(self, a_bzrdir, name=None, repository=None):
2081
2202
        """Create a branch of this format in a_bzrdir."""
2082
2203
        utf8_files = [('last-revision', '0 null:\n'),
2083
2204
                      ('branch.conf', ''),
2084
2205
                      ('tags', ''),
2085
2206
                      ('references', '')
2086
2207
                      ]
2087
 
        return self._initialize_helper(a_bzrdir, utf8_files, name)
 
2208
        return self._initialize_helper(a_bzrdir, utf8_files, name, repository)
2088
2209
 
2089
2210
    def __init__(self):
2090
2211
        super(BzrBranchFormat8, self).__init__()
2113
2234
    This format was introduced in bzr 1.6.
2114
2235
    """
2115
2236
 
2116
 
    def initialize(self, a_bzrdir, name=None):
 
2237
    def initialize(self, a_bzrdir, name=None, repository=None):
2117
2238
        """Create a branch of this format in a_bzrdir."""
2118
2239
        utf8_files = [('last-revision', '0 null:\n'),
2119
2240
                      ('branch.conf', ''),
2120
2241
                      ('tags', ''),
2121
2242
                      ]
2122
 
        return self._initialize_helper(a_bzrdir, utf8_files, name)
 
2243
        return self._initialize_helper(a_bzrdir, utf8_files, name, repository)
2123
2244
 
2124
2245
    def _branch_class(self):
2125
2246
        return BzrBranch7
2157
2278
        """See BranchFormat.get_format_description()."""
2158
2279
        return "Checkout reference format 1"
2159
2280
 
2160
 
    def get_reference(self, a_bzrdir):
 
2281
    def get_reference(self, a_bzrdir, name=None):
2161
2282
        """See BranchFormat.get_reference()."""
2162
 
        transport = a_bzrdir.get_branch_transport(None)
 
2283
        transport = a_bzrdir.get_branch_transport(None, name=name)
2163
2284
        return transport.get_bytes('location')
2164
2285
 
2165
 
    def set_reference(self, a_bzrdir, to_branch):
 
2286
    def set_reference(self, a_bzrdir, name, to_branch):
2166
2287
        """See BranchFormat.set_reference()."""
2167
 
        transport = a_bzrdir.get_branch_transport(None)
 
2288
        transport = a_bzrdir.get_branch_transport(None, name=name)
2168
2289
        location = transport.put_bytes('location', to_branch.base)
2169
2290
 
2170
 
    def initialize(self, a_bzrdir, name=None, target_branch=None):
 
2291
    def initialize(self, a_bzrdir, name=None, target_branch=None,
 
2292
            repository=None):
2171
2293
        """Create a branch of this format in a_bzrdir."""
2172
2294
        if target_branch is None:
2173
2295
            # this format does not implement branch itself, thus the implicit
2201
2323
        return clone
2202
2324
 
2203
2325
    def open(self, a_bzrdir, name=None, _found=False, location=None,
2204
 
             possible_transports=None, ignore_fallbacks=False):
 
2326
             possible_transports=None, ignore_fallbacks=False,
 
2327
             found_repository=None):
2205
2328
        """Return the branch that the branch reference in a_bzrdir points at.
2206
2329
 
2207
2330
        :param a_bzrdir: A BzrDir that contains a branch.
2221
2344
                raise AssertionError("wrong format %r found for %r" %
2222
2345
                    (format, self))
2223
2346
        if location is None:
2224
 
            location = self.get_reference(a_bzrdir)
 
2347
            location = self.get_reference(a_bzrdir, name)
2225
2348
        real_bzrdir = bzrdir.BzrDir.open(
2226
2349
            location, possible_transports=possible_transports)
2227
2350
        result = real_bzrdir.open_branch(name=name, 
2265
2388
    _legacy_formats[0].network_name(), _legacy_formats[0].__class__)
2266
2389
 
2267
2390
 
 
2391
class BranchWriteLockResult(LogicalLockResult):
 
2392
    """The result of write locking a branch.
 
2393
 
 
2394
    :ivar branch_token: The token obtained from the underlying branch lock, or
 
2395
        None.
 
2396
    :ivar unlock: A callable which will unlock the lock.
 
2397
    """
 
2398
 
 
2399
    def __init__(self, unlock, branch_token):
 
2400
        LogicalLockResult.__init__(self, unlock)
 
2401
        self.branch_token = branch_token
 
2402
 
 
2403
    def __repr__(self):
 
2404
        return "BranchWriteLockResult(%s, %s)" % (self.branch_token,
 
2405
            self.unlock)
 
2406
 
 
2407
 
2268
2408
class BzrBranch(Branch, _RelockDebugMixin):
2269
2409
    """A branch stored in the actual filesystem.
2270
2410
 
2324
2464
        return self.control_files.is_locked()
2325
2465
 
2326
2466
    def lock_write(self, token=None):
 
2467
        """Lock the branch for write operations.
 
2468
 
 
2469
        :param token: A token to permit reacquiring a previously held and
 
2470
            preserved lock.
 
2471
        :return: A BranchWriteLockResult.
 
2472
        """
2327
2473
        if not self.is_locked():
2328
2474
            self._note_lock('w')
2329
2475
        # All-in-one needs to always unlock/lock.
2335
2481
        else:
2336
2482
            took_lock = False
2337
2483
        try:
2338
 
            return self.control_files.lock_write(token=token)
 
2484
            return BranchWriteLockResult(self.unlock,
 
2485
                self.control_files.lock_write(token=token))
2339
2486
        except:
2340
2487
            if took_lock:
2341
2488
                self.repository.unlock()
2342
2489
            raise
2343
2490
 
2344
2491
    def lock_read(self):
 
2492
        """Lock the branch for read operations.
 
2493
 
 
2494
        :return: A bzrlib.lock.LogicalLockResult.
 
2495
        """
2345
2496
        if not self.is_locked():
2346
2497
            self._note_lock('r')
2347
2498
        # All-in-one needs to always unlock/lock.
2354
2505
            took_lock = False
2355
2506
        try:
2356
2507
            self.control_files.lock_read()
 
2508
            return LogicalLockResult(self.unlock)
2357
2509
        except:
2358
2510
            if took_lock:
2359
2511
                self.repository.unlock()
2522
2674
            target.update_revisions(self, stop_revision,
2523
2675
                overwrite=overwrite, graph=graph)
2524
2676
        if self._push_should_merge_tags():
2525
 
            result.tag_conflicts = self.tags.merge_to(target.tags,
2526
 
                overwrite)
 
2677
            result.tag_conflicts = self.tags.merge_to(target.tags, overwrite)
2527
2678
        result.new_revno, result.new_revid = target.last_revision_info()
2528
2679
        return result
2529
2680
 
2544
2695
                mode=self.bzrdir._get_file_mode())
2545
2696
 
2546
2697
 
 
2698
class BzrBranchPreSplitOut(BzrBranch):
 
2699
 
 
2700
    def _get_checkout_format(self):
 
2701
        """Return the most suitable metadir for a checkout of this branch.
 
2702
        Weaves are used if this branch's repository uses weaves.
 
2703
        """
 
2704
        from bzrlib.repofmt.weaverepo import RepositoryFormat7
 
2705
        from bzrlib.bzrdir import BzrDirMetaFormat1
 
2706
        format = BzrDirMetaFormat1()
 
2707
        format.repository_format = RepositoryFormat7()
 
2708
        return format
 
2709
 
 
2710
 
2547
2711
class BzrBranch5(BzrBranch):
2548
2712
    """A format 5 branch. This supports new features over plain branches.
2549
2713
 
2561
2725
        """Return the branch we are bound to.
2562
2726
 
2563
2727
        :return: Either a Branch, or None
2564
 
 
2565
 
        This could memoise the branch, but if thats done
2566
 
        it must be revalidated on each new lock.
2567
 
        So for now we just don't memoise it.
2568
 
        # RBC 20060304 review this decision.
2569
2728
        """
 
2729
        if self._master_branch_cache is None:
 
2730
            self._master_branch_cache = self._get_master_branch(
 
2731
                possible_transports)
 
2732
        return self._master_branch_cache
 
2733
 
 
2734
    def _get_master_branch(self, possible_transports):
2570
2735
        bound_loc = self.get_bound_location()
2571
2736
        if not bound_loc:
2572
2737
            return None
2583
2748
 
2584
2749
        :param location: URL to the target branch
2585
2750
        """
 
2751
        self._master_branch_cache = None
2586
2752
        if location:
2587
2753
            self._transport.put_bytes('bound', location+'\n',
2588
2754
                mode=self.bzrdir._get_file_mode())
2840
3006
 
2841
3007
    def set_bound_location(self, location):
2842
3008
        """See Branch.set_push_location."""
 
3009
        self._master_branch_cache = None
2843
3010
        result = None
2844
3011
        config = self.get_config()
2845
3012
        if location is None:
2983
3150
    :ivar tag_conflicts: A list of tag conflicts, see BasicTags.merge_to
2984
3151
    """
2985
3152
 
 
3153
    @deprecated_method(deprecated_in((2, 3, 0)))
2986
3154
    def __int__(self):
2987
 
        # DEPRECATED: pull used to return the change in revno
 
3155
        """Return the relative change in revno.
 
3156
 
 
3157
        :deprecated: Use `new_revno` and `old_revno` instead.
 
3158
        """
2988
3159
        return self.new_revno - self.old_revno
2989
3160
 
2990
3161
    def report(self, to_file):
3015
3186
        target, otherwise it will be None.
3016
3187
    """
3017
3188
 
 
3189
    @deprecated_method(deprecated_in((2, 3, 0)))
3018
3190
    def __int__(self):
3019
 
        # DEPRECATED: push used to return the change in revno
 
3191
        """Return the relative change in revno.
 
3192
 
 
3193
        :deprecated: Use `new_revno` and `old_revno` instead.
 
3194
        """
3020
3195
        return self.new_revno - self.old_revno
3021
3196
 
3022
3197
    def report(self, to_file):
3145
3320
    _optimisers = []
3146
3321
    """The available optimised InterBranch types."""
3147
3322
 
3148
 
    @staticmethod
3149
 
    def _get_branch_formats_to_test():
3150
 
        """Return a tuple with the Branch formats to use when testing."""
3151
 
        raise NotImplementedError(InterBranch._get_branch_formats_to_test)
 
3323
    @classmethod
 
3324
    def _get_branch_formats_to_test(klass):
 
3325
        """Return an iterable of format tuples for testing.
 
3326
        
 
3327
        :return: An iterable of (from_format, to_format) to use when testing
 
3328
            this InterBranch class. Each InterBranch class should define this
 
3329
            method itself.
 
3330
        """
 
3331
        raise NotImplementedError(klass._get_branch_formats_to_test)
3152
3332
 
 
3333
    @needs_write_lock
3153
3334
    def pull(self, overwrite=False, stop_revision=None,
3154
3335
             possible_transports=None, local=False):
3155
3336
        """Mirror source into target branch.
3160
3341
        """
3161
3342
        raise NotImplementedError(self.pull)
3162
3343
 
 
3344
    @needs_write_lock
3163
3345
    def update_revisions(self, stop_revision=None, overwrite=False,
3164
3346
                         graph=None):
3165
3347
        """Pull in new perfect-fit revisions.
3173
3355
        """
3174
3356
        raise NotImplementedError(self.update_revisions)
3175
3357
 
 
3358
    @needs_write_lock
3176
3359
    def push(self, overwrite=False, stop_revision=None,
3177
3360
             _override_hook_source_branch=None):
3178
3361
        """Mirror the source branch into the target branch.
3181
3364
        """
3182
3365
        raise NotImplementedError(self.push)
3183
3366
 
 
3367
    @needs_write_lock
 
3368
    def copy_content_into(self, revision_id=None):
 
3369
        """Copy the content of source into target
 
3370
 
 
3371
        revision_id: if not None, the revision history in the new branch will
 
3372
                     be truncated to end with revision_id.
 
3373
        """
 
3374
        raise NotImplementedError(self.copy_content_into)
 
3375
 
3184
3376
 
3185
3377
class GenericInterBranch(InterBranch):
3186
 
    """InterBranch implementation that uses public Branch functions.
3187
 
    """
3188
 
 
3189
 
    @staticmethod
3190
 
    def _get_branch_formats_to_test():
3191
 
        return BranchFormat._default_format, BranchFormat._default_format
3192
 
 
 
3378
    """InterBranch implementation that uses public Branch functions."""
 
3379
 
 
3380
    @classmethod
 
3381
    def is_compatible(klass, source, target):
 
3382
        # GenericBranch uses the public API, so always compatible
 
3383
        return True
 
3384
 
 
3385
    @classmethod
 
3386
    def _get_branch_formats_to_test(klass):
 
3387
        return [(BranchFormat._default_format, BranchFormat._default_format)]
 
3388
 
 
3389
    @classmethod
 
3390
    def unwrap_format(klass, format):
 
3391
        if isinstance(format, remote.RemoteBranchFormat):
 
3392
            format._ensure_real()
 
3393
            return format._custom_format
 
3394
        return format
 
3395
 
 
3396
    @needs_write_lock
 
3397
    def copy_content_into(self, revision_id=None):
 
3398
        """Copy the content of source into target
 
3399
 
 
3400
        revision_id: if not None, the revision history in the new branch will
 
3401
                     be truncated to end with revision_id.
 
3402
        """
 
3403
        self.source.update_references(self.target)
 
3404
        self.source._synchronize_history(self.target, revision_id)
 
3405
        try:
 
3406
            parent = self.source.get_parent()
 
3407
        except errors.InaccessibleParent, e:
 
3408
            mutter('parent was not accessible to copy: %s', e)
 
3409
        else:
 
3410
            if parent:
 
3411
                self.target.set_parent(parent)
 
3412
        if self.source._push_should_merge_tags():
 
3413
            self.source.tags.merge_to(self.target.tags)
 
3414
 
 
3415
    @needs_write_lock
3193
3416
    def update_revisions(self, stop_revision=None, overwrite=False,
3194
3417
        graph=None):
3195
3418
        """See InterBranch.update_revisions()."""
3196
 
        self.source.lock_read()
3197
 
        try:
3198
 
            other_revno, other_last_revision = self.source.last_revision_info()
3199
 
            stop_revno = None # unknown
3200
 
            if stop_revision is None:
3201
 
                stop_revision = other_last_revision
3202
 
                if _mod_revision.is_null(stop_revision):
3203
 
                    # if there are no commits, we're done.
3204
 
                    return
3205
 
                stop_revno = other_revno
3206
 
 
3207
 
            # what's the current last revision, before we fetch [and change it
3208
 
            # possibly]
3209
 
            last_rev = _mod_revision.ensure_null(self.target.last_revision())
3210
 
            # we fetch here so that we don't process data twice in the common
3211
 
            # case of having something to pull, and so that the check for
3212
 
            # already merged can operate on the just fetched graph, which will
3213
 
            # be cached in memory.
3214
 
            self.target.fetch(self.source, stop_revision)
3215
 
            # Check to see if one is an ancestor of the other
3216
 
            if not overwrite:
3217
 
                if graph is None:
3218
 
                    graph = self.target.repository.get_graph()
3219
 
                if self.target._check_if_descendant_or_diverged(
3220
 
                        stop_revision, last_rev, graph, self.source):
3221
 
                    # stop_revision is a descendant of last_rev, but we aren't
3222
 
                    # overwriting, so we're done.
3223
 
                    return
3224
 
            if stop_revno is None:
3225
 
                if graph is None:
3226
 
                    graph = self.target.repository.get_graph()
3227
 
                this_revno, this_last_revision = \
3228
 
                        self.target.last_revision_info()
3229
 
                stop_revno = graph.find_distance_to_null(stop_revision,
3230
 
                                [(other_last_revision, other_revno),
3231
 
                                 (this_last_revision, this_revno)])
3232
 
            self.target.set_last_revision_info(stop_revno, stop_revision)
3233
 
        finally:
3234
 
            self.source.unlock()
3235
 
 
 
3419
        other_revno, other_last_revision = self.source.last_revision_info()
 
3420
        stop_revno = None # unknown
 
3421
        if stop_revision is None:
 
3422
            stop_revision = other_last_revision
 
3423
            if _mod_revision.is_null(stop_revision):
 
3424
                # if there are no commits, we're done.
 
3425
                return
 
3426
            stop_revno = other_revno
 
3427
 
 
3428
        # what's the current last revision, before we fetch [and change it
 
3429
        # possibly]
 
3430
        last_rev = _mod_revision.ensure_null(self.target.last_revision())
 
3431
        # we fetch here so that we don't process data twice in the common
 
3432
        # case of having something to pull, and so that the check for
 
3433
        # already merged can operate on the just fetched graph, which will
 
3434
        # be cached in memory.
 
3435
        self.target.fetch(self.source, stop_revision)
 
3436
        # Check to see if one is an ancestor of the other
 
3437
        if not overwrite:
 
3438
            if graph is None:
 
3439
                graph = self.target.repository.get_graph()
 
3440
            if self.target._check_if_descendant_or_diverged(
 
3441
                    stop_revision, last_rev, graph, self.source):
 
3442
                # stop_revision is a descendant of last_rev, but we aren't
 
3443
                # overwriting, so we're done.
 
3444
                return
 
3445
        if stop_revno is None:
 
3446
            if graph is None:
 
3447
                graph = self.target.repository.get_graph()
 
3448
            this_revno, this_last_revision = \
 
3449
                    self.target.last_revision_info()
 
3450
            stop_revno = graph.find_distance_to_null(stop_revision,
 
3451
                            [(other_last_revision, other_revno),
 
3452
                             (this_last_revision, this_revno)])
 
3453
        self.target.set_last_revision_info(stop_revno, stop_revision)
 
3454
 
 
3455
    @needs_write_lock
3236
3456
    def pull(self, overwrite=False, stop_revision=None,
3237
 
             possible_transports=None, _hook_master=None, run_hooks=True,
 
3457
             possible_transports=None, run_hooks=True,
3238
3458
             _override_hook_target=None, local=False):
3239
 
        """See Branch.pull.
 
3459
        """Pull from source into self, updating my master if any.
3240
3460
 
3241
 
        :param _hook_master: Private parameter - set the branch to
3242
 
            be supplied as the master to pull hooks.
3243
3461
        :param run_hooks: Private parameter - if false, this branch
3244
3462
            is being called because it's the master of the primary branch,
3245
3463
            so it should not run its hooks.
3246
 
        :param _override_hook_target: Private parameter - set the branch to be
3247
 
            supplied as the target_branch to pull hooks.
3248
 
        :param local: Only update the local branch, and not the bound branch.
3249
3464
        """
3250
 
        # This type of branch can't be bound.
3251
 
        if local:
 
3465
        bound_location = self.target.get_bound_location()
 
3466
        if local and not bound_location:
3252
3467
            raise errors.LocalRequiresBoundBranch()
3253
 
        result = PullResult()
3254
 
        result.source_branch = self.source
3255
 
        if _override_hook_target is None:
3256
 
            result.target_branch = self.target
3257
 
        else:
3258
 
            result.target_branch = _override_hook_target
3259
 
        self.source.lock_read()
 
3468
        master_branch = None
 
3469
        source_is_master = (self.source.user_url == bound_location)
 
3470
        if not local and bound_location and not source_is_master:
 
3471
            # not pulling from master, so we need to update master.
 
3472
            master_branch = self.target.get_master_branch(possible_transports)
 
3473
            master_branch.lock_write()
3260
3474
        try:
3261
 
            # We assume that during 'pull' the target repository is closer than
3262
 
            # the source one.
3263
 
            self.source.update_references(self.target)
3264
 
            graph = self.target.repository.get_graph(self.source.repository)
3265
 
            # TODO: Branch formats should have a flag that indicates 
3266
 
            # that revno's are expensive, and pull() should honor that flag.
3267
 
            # -- JRV20090506
3268
 
            result.old_revno, result.old_revid = \
3269
 
                self.target.last_revision_info()
3270
 
            self.target.update_revisions(self.source, stop_revision,
3271
 
                overwrite=overwrite, graph=graph)
3272
 
            # TODO: The old revid should be specified when merging tags, 
3273
 
            # so a tags implementation that versions tags can only 
3274
 
            # pull in the most recent changes. -- JRV20090506
3275
 
            result.tag_conflicts = self.source.tags.merge_to(self.target.tags,
3276
 
                overwrite)
3277
 
            result.new_revno, result.new_revid = self.target.last_revision_info()
3278
 
            if _hook_master:
3279
 
                result.master_branch = _hook_master
3280
 
                result.local_branch = result.target_branch
3281
 
            else:
3282
 
                result.master_branch = result.target_branch
3283
 
                result.local_branch = None
3284
 
            if run_hooks:
3285
 
                for hook in Branch.hooks['post_pull']:
3286
 
                    hook(result)
 
3475
            if master_branch:
 
3476
                # pull from source into master.
 
3477
                master_branch.pull(self.source, overwrite, stop_revision,
 
3478
                    run_hooks=False)
 
3479
            return self._pull(overwrite,
 
3480
                stop_revision, _hook_master=master_branch,
 
3481
                run_hooks=run_hooks,
 
3482
                _override_hook_target=_override_hook_target,
 
3483
                merge_tags_to_master=not source_is_master)
3287
3484
        finally:
3288
 
            self.source.unlock()
3289
 
        return result
 
3485
            if master_branch:
 
3486
                master_branch.unlock()
3290
3487
 
3291
3488
    def push(self, overwrite=False, stop_revision=None,
3292
3489
             _override_hook_source_branch=None):
3332
3529
                # push into the master from the source branch.
3333
3530
                self.source._basic_push(master_branch, overwrite, stop_revision)
3334
3531
                # and push into the target branch from the source. Note that we
3335
 
                # push from the source branch again, because its considered the
 
3532
                # push from the source branch again, because it's considered the
3336
3533
                # highest bandwidth repository.
3337
3534
                result = self.source._basic_push(self.target, overwrite,
3338
3535
                    stop_revision)
3354
3551
            _run_hooks()
3355
3552
            return result
3356
3553
 
3357
 
    @classmethod
3358
 
    def is_compatible(self, source, target):
3359
 
        # GenericBranch uses the public API, so always compatible
3360
 
        return True
3361
 
 
3362
 
 
3363
 
class InterToBranch5(GenericInterBranch):
3364
 
 
3365
 
    @staticmethod
3366
 
    def _get_branch_formats_to_test():
3367
 
        return BranchFormat._default_format, BzrBranchFormat5()
3368
 
 
3369
 
    def pull(self, overwrite=False, stop_revision=None,
3370
 
             possible_transports=None, run_hooks=True,
3371
 
             _override_hook_target=None, local=False):
3372
 
        """Pull from source into self, updating my master if any.
3373
 
 
 
3554
    def _pull(self, overwrite=False, stop_revision=None,
 
3555
             possible_transports=None, _hook_master=None, run_hooks=True,
 
3556
             _override_hook_target=None, local=False,
 
3557
             merge_tags_to_master=True):
 
3558
        """See Branch.pull.
 
3559
 
 
3560
        This function is the core worker, used by GenericInterBranch.pull to
 
3561
        avoid duplication when pulling source->master and source->local.
 
3562
 
 
3563
        :param _hook_master: Private parameter - set the branch to
 
3564
            be supplied as the master to pull hooks.
3374
3565
        :param run_hooks: Private parameter - if false, this branch
3375
3566
            is being called because it's the master of the primary branch,
3376
3567
            so it should not run its hooks.
 
3568
        :param _override_hook_target: Private parameter - set the branch to be
 
3569
            supplied as the target_branch to pull hooks.
 
3570
        :param local: Only update the local branch, and not the bound branch.
3377
3571
        """
3378
 
        bound_location = self.target.get_bound_location()
3379
 
        if local and not bound_location:
 
3572
        # This type of branch can't be bound.
 
3573
        if local:
3380
3574
            raise errors.LocalRequiresBoundBranch()
3381
 
        master_branch = None
3382
 
        if not local and bound_location and self.source.user_url != bound_location:
3383
 
            # not pulling from master, so we need to update master.
3384
 
            master_branch = self.target.get_master_branch(possible_transports)
3385
 
            master_branch.lock_write()
 
3575
        result = PullResult()
 
3576
        result.source_branch = self.source
 
3577
        if _override_hook_target is None:
 
3578
            result.target_branch = self.target
 
3579
        else:
 
3580
            result.target_branch = _override_hook_target
 
3581
        self.source.lock_read()
3386
3582
        try:
3387
 
            if master_branch:
3388
 
                # pull from source into master.
3389
 
                master_branch.pull(self.source, overwrite, stop_revision,
3390
 
                    run_hooks=False)
3391
 
            return super(InterToBranch5, self).pull(overwrite,
3392
 
                stop_revision, _hook_master=master_branch,
3393
 
                run_hooks=run_hooks,
3394
 
                _override_hook_target=_override_hook_target)
 
3583
            # We assume that during 'pull' the target repository is closer than
 
3584
            # the source one.
 
3585
            self.source.update_references(self.target)
 
3586
            graph = self.target.repository.get_graph(self.source.repository)
 
3587
            # TODO: Branch formats should have a flag that indicates 
 
3588
            # that revno's are expensive, and pull() should honor that flag.
 
3589
            # -- JRV20090506
 
3590
            result.old_revno, result.old_revid = \
 
3591
                self.target.last_revision_info()
 
3592
            self.target.update_revisions(self.source, stop_revision,
 
3593
                overwrite=overwrite, graph=graph)
 
3594
            # TODO: The old revid should be specified when merging tags, 
 
3595
            # so a tags implementation that versions tags can only 
 
3596
            # pull in the most recent changes. -- JRV20090506
 
3597
            result.tag_conflicts = self.source.tags.merge_to(self.target.tags,
 
3598
                overwrite, ignore_master=not merge_tags_to_master)
 
3599
            result.new_revno, result.new_revid = self.target.last_revision_info()
 
3600
            if _hook_master:
 
3601
                result.master_branch = _hook_master
 
3602
                result.local_branch = result.target_branch
 
3603
            else:
 
3604
                result.master_branch = result.target_branch
 
3605
                result.local_branch = None
 
3606
            if run_hooks:
 
3607
                for hook in Branch.hooks['post_pull']:
 
3608
                    hook(result)
3395
3609
        finally:
3396
 
            if master_branch:
3397
 
                master_branch.unlock()
 
3610
            self.source.unlock()
 
3611
        return result
3398
3612
 
3399
3613
 
3400
3614
InterBranch.register_optimiser(GenericInterBranch)
3401
 
InterBranch.register_optimiser(InterToBranch5)