~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/branch.py

  • Committer: Ian Clatworthy
  • Date: 2009-07-02 08:26:00 UTC
  • mto: (4527.1.1 integration)
  • mto: This revision was merged to the branch mainline in revision 4529.
  • Revision ID: ian.clatworthy@canonical.com-20090702082600-qwb1evvvfa8ctnye
first draft of a 2.0 Upgrade Guide

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# Copyright (C) 2005-2010 Canonical Ltd
 
1
# Copyright (C) 2005, 2006, 2007, 2008, 2009 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
46
46
    )
47
47
""")
48
48
 
49
 
from bzrlib.decorators import needs_read_lock, needs_write_lock, only_raises
 
49
from bzrlib.decorators import needs_read_lock, needs_write_lock
50
50
from bzrlib.hooks import HookPoint, Hooks
51
51
from bzrlib.inter import InterObject
52
 
from bzrlib.lock import _RelockDebugMixin
53
52
from bzrlib import registry
54
53
from bzrlib.symbol_versioning import (
55
54
    deprecated_in,
150
149
        if self._partial_revision_history_cache[-1] == _mod_revision.NULL_REVISION:
151
150
            self._partial_revision_history_cache.pop()
152
151
 
153
 
    def _get_check_refs(self):
154
 
        """Get the references needed for check().
155
 
 
156
 
        See bzrlib.check.
157
 
        """
158
 
        revid = self.last_revision()
159
 
        return [('revision-existence', revid), ('lefthand-distance', revid)]
160
 
 
161
152
    @staticmethod
162
153
    def open(base, _unsupported=False, possible_transports=None):
163
154
        """Open the branch rooted at base.
167
158
        """
168
159
        control = bzrdir.BzrDir.open(base, _unsupported,
169
160
                                     possible_transports=possible_transports)
170
 
        return control.open_branch(unsupported=_unsupported)
 
161
        return control.open_branch(_unsupported)
171
162
 
172
163
    @staticmethod
173
 
    def open_from_transport(transport, name=None, _unsupported=False):
 
164
    def open_from_transport(transport, _unsupported=False):
174
165
        """Open the branch rooted at transport"""
175
166
        control = bzrdir.BzrDir.open_from_transport(transport, _unsupported)
176
 
        return control.open_branch(name=name, unsupported=_unsupported)
 
167
        return control.open_branch(_unsupported)
177
168
 
178
169
    @staticmethod
179
170
    def open_containing(url, possible_transports=None):
217
208
    def _get_fallback_repository(self, url):
218
209
        """Get the repository we fallback to at url."""
219
210
        url = urlutils.join(self.base, url)
220
 
        a_branch = Branch.open(url,
 
211
        a_bzrdir = bzrdir.BzrDir.open(url,
221
212
            possible_transports=[self.bzrdir.root_transport])
222
 
        return a_branch.repository
 
213
        return a_bzrdir.open_branch().repository
223
214
 
224
215
    def _get_tags_bytes(self):
225
216
        """Get the bytes of a serialised tags dict.
447
438
        # start_revision_id.
448
439
        if self._merge_sorted_revisions_cache is None:
449
440
            last_revision = self.last_revision()
450
 
            last_key = (last_revision,)
451
 
            known_graph = self.repository.revisions.get_known_graph_ancestry(
452
 
                [last_key])
453
 
            self._merge_sorted_revisions_cache = known_graph.merge_sort(
454
 
                last_key)
 
441
            graph = self.repository.get_graph()
 
442
            parent_map = dict(((key, value) for key, value in
 
443
                     graph.iter_ancestry([last_revision]) if value is not None))
 
444
            revision_graph = repository._strip_NULL_ghosts(parent_map)
 
445
            revs = tsort.merge_sort(revision_graph, last_revision, None,
 
446
                generate_revno=True)
 
447
            # Drop the sequence # before caching
 
448
            self._merge_sorted_revisions_cache = [r[1:] for r in revs]
 
449
 
455
450
        filtered = self._filter_merge_sorted_revisions(
456
451
            self._merge_sorted_revisions_cache, start_revision_id,
457
452
            stop_revision_id, stop_rule)
467
462
        """Iterate over an inclusive range of sorted revisions."""
468
463
        rev_iter = iter(merge_sorted_revisions)
469
464
        if start_revision_id is not None:
470
 
            for node in rev_iter:
471
 
                rev_id = node.key[-1]
 
465
            for rev_id, depth, revno, end_of_merge in rev_iter:
472
466
                if rev_id != start_revision_id:
473
467
                    continue
474
468
                else:
475
469
                    # The decision to include the start or not
476
470
                    # depends on the stop_rule if a stop is provided
477
 
                    # so pop this node back into the iterator
478
 
                    rev_iter = chain(iter([node]), rev_iter)
 
471
                    rev_iter = chain(
 
472
                        iter([(rev_id, depth, revno, end_of_merge)]),
 
473
                        rev_iter)
479
474
                    break
480
475
        if stop_revision_id is None:
481
 
            # Yield everything
482
 
            for node in rev_iter:
483
 
                rev_id = node.key[-1]
484
 
                yield (rev_id, node.merge_depth, node.revno,
485
 
                       node.end_of_merge)
 
476
            for rev_id, depth, revno, end_of_merge in rev_iter:
 
477
                yield rev_id, depth, revno, end_of_merge
486
478
        elif stop_rule == 'exclude':
487
 
            for node in rev_iter:
488
 
                rev_id = node.key[-1]
 
479
            for rev_id, depth, revno, end_of_merge in rev_iter:
489
480
                if rev_id == stop_revision_id:
490
481
                    return
491
 
                yield (rev_id, node.merge_depth, node.revno,
492
 
                       node.end_of_merge)
 
482
                yield rev_id, depth, revno, end_of_merge
493
483
        elif stop_rule == 'include':
494
 
            for node in rev_iter:
495
 
                rev_id = node.key[-1]
496
 
                yield (rev_id, node.merge_depth, node.revno,
497
 
                       node.end_of_merge)
 
484
            for rev_id, depth, revno, end_of_merge in rev_iter:
 
485
                yield rev_id, depth, revno, end_of_merge
498
486
                if rev_id == stop_revision_id:
499
487
                    return
500
488
        elif stop_rule == 'with-merges':
503
491
                left_parent = stop_rev.parent_ids[0]
504
492
            else:
505
493
                left_parent = _mod_revision.NULL_REVISION
506
 
            # left_parent is the actual revision we want to stop logging at,
507
 
            # since we want to show the merged revisions after the stop_rev too
508
 
            reached_stop_revision_id = False
509
 
            revision_id_whitelist = []
510
 
            for node in rev_iter:
511
 
                rev_id = node.key[-1]
 
494
            for rev_id, depth, revno, end_of_merge in rev_iter:
512
495
                if rev_id == left_parent:
513
 
                    # reached the left parent after the stop_revision
514
496
                    return
515
 
                if (not reached_stop_revision_id or
516
 
                        rev_id in revision_id_whitelist):
517
 
                    yield (rev_id, node.merge_depth, node.revno,
518
 
                       node.end_of_merge)
519
 
                    if reached_stop_revision_id or rev_id == stop_revision_id:
520
 
                        # only do the merged revs of rev_id from now on
521
 
                        rev = self.repository.get_revision(rev_id)
522
 
                        if rev.parent_ids:
523
 
                            reached_stop_revision_id = True
524
 
                            revision_id_whitelist.extend(rev.parent_ids)
 
497
                yield rev_id, depth, revno, end_of_merge
525
498
        else:
526
499
            raise ValueError('invalid stop_rule %r' % stop_rule)
527
500
 
690
663
        """
691
664
        if not self._format.supports_stacking():
692
665
            raise errors.UnstackableBranchFormat(self._format, self.base)
693
 
        # XXX: Changing from one fallback repository to another does not check
694
 
        # that all the data you need is present in the new fallback.
695
 
        # Possibly it should.
696
666
        self._check_stackable_repo()
697
667
        if not url:
698
668
            try:
700
670
            except (errors.NotStacked, errors.UnstackableBranchFormat,
701
671
                errors.UnstackableRepositoryFormat):
702
672
                return
703
 
            self._unstack()
 
673
            url = ''
 
674
            # XXX: Lock correctness - should unlock our old repo if we were
 
675
            # locked.
 
676
            # repositories don't offer an interface to remove fallback
 
677
            # repositories today; take the conceptually simpler option and just
 
678
            # reopen it.
 
679
            self.repository = self.bzrdir.find_repository()
 
680
            self.repository.lock_write()
 
681
            # for every revision reference the branch has, ensure it is pulled
 
682
            # in.
 
683
            source_repository = self._get_fallback_repository(old_url)
 
684
            for revision_id in chain([self.last_revision()],
 
685
                self.tags.get_reverse_tag_dict()):
 
686
                self.repository.fetch(source_repository, revision_id,
 
687
                    find_ghosts=True)
704
688
        else:
705
689
            self._activate_fallback_location(url)
706
690
        # write this out after the repository is stacked to avoid setting a
707
691
        # stacked config that doesn't work.
708
692
        self._set_config_location('stacked_on_location', url)
709
693
 
710
 
    def _unstack(self):
711
 
        """Change a branch to be unstacked, copying data as needed.
712
 
        
713
 
        Don't call this directly, use set_stacked_on_url(None).
714
 
        """
715
 
        pb = ui.ui_factory.nested_progress_bar()
716
 
        try:
717
 
            pb.update("Unstacking")
718
 
            # The basic approach here is to fetch the tip of the branch,
719
 
            # including all available ghosts, from the existing stacked
720
 
            # repository into a new repository object without the fallbacks. 
721
 
            #
722
 
            # XXX: See <https://launchpad.net/bugs/397286> - this may not be
723
 
            # correct for CHKMap repostiories
724
 
            old_repository = self.repository
725
 
            if len(old_repository._fallback_repositories) != 1:
726
 
                raise AssertionError("can't cope with fallback repositories "
727
 
                    "of %r" % (self.repository,))
728
 
            # unlock it, including unlocking the fallback
729
 
            old_repository.unlock()
730
 
            old_repository.lock_read()
731
 
            try:
732
 
                # Repositories don't offer an interface to remove fallback
733
 
                # repositories today; take the conceptually simpler option and just
734
 
                # reopen it.  We reopen it starting from the URL so that we
735
 
                # get a separate connection for RemoteRepositories and can
736
 
                # stream from one of them to the other.  This does mean doing
737
 
                # separate SSH connection setup, but unstacking is not a
738
 
                # common operation so it's tolerable.
739
 
                new_bzrdir = bzrdir.BzrDir.open(self.bzrdir.root_transport.base)
740
 
                new_repository = new_bzrdir.find_repository()
741
 
                self.repository = new_repository
742
 
                if self.repository._fallback_repositories:
743
 
                    raise AssertionError("didn't expect %r to have "
744
 
                        "fallback_repositories"
745
 
                        % (self.repository,))
746
 
                # this is not paired with an unlock because it's just restoring
747
 
                # the previous state; the lock's released when set_stacked_on_url
748
 
                # returns
749
 
                self.repository.lock_write()
750
 
                # XXX: If you unstack a branch while it has a working tree
751
 
                # with a pending merge, the pending-merged revisions will no
752
 
                # longer be present.  You can (probably) revert and remerge.
753
 
                #
754
 
                # XXX: This only fetches up to the tip of the repository; it
755
 
                # doesn't bring across any tags.  That's fairly consistent
756
 
                # with how branch works, but perhaps not ideal.
757
 
                self.repository.fetch(old_repository,
758
 
                    revision_id=self.last_revision(),
759
 
                    find_ghosts=True)
760
 
            finally:
761
 
                old_repository.unlock()
762
 
        finally:
763
 
            pb.finished()
764
694
 
765
695
    def _set_tags_bytes(self, bytes):
766
696
        """Mirror method for _get_tags_bytes.
1103
1033
        params = ChangeBranchTipParams(
1104
1034
            self, old_revno, new_revno, old_revid, new_revid)
1105
1035
        for hook in hooks:
1106
 
            hook(params)
 
1036
            try:
 
1037
                hook(params)
 
1038
            except errors.TipChangeRejected:
 
1039
                raise
 
1040
            except Exception:
 
1041
                exc_info = sys.exc_info()
 
1042
                hook_name = Branch.hooks.get_hook_name(hook)
 
1043
                raise errors.HookFailed(
 
1044
                    'pre_change_branch_tip', hook_name, exc_info)
1107
1045
 
1108
1046
    @needs_write_lock
1109
1047
    def update(self):
1158
1096
        revision_id: if not None, the revision history in the new branch will
1159
1097
                     be truncated to end with revision_id.
1160
1098
        """
1161
 
        if (repository_policy is not None and
1162
 
            repository_policy.requires_stacking()):
1163
 
            to_bzrdir._format.require_stacking(_skip_repo=True)
1164
1099
        result = to_bzrdir.create_branch()
1165
1100
        result.lock_write()
1166
1101
        try:
1234
1169
        target._set_all_reference_info(target_reference_dict)
1235
1170
 
1236
1171
    @needs_read_lock
1237
 
    def check(self, refs):
 
1172
    def check(self):
1238
1173
        """Check consistency of the branch.
1239
1174
 
1240
1175
        In particular this checks that revisions given in the revision-history
1243
1178
 
1244
1179
        Callers will typically also want to check the repository.
1245
1180
 
1246
 
        :param refs: Calculated refs for this branch as specified by
1247
 
            branch._get_check_refs()
1248
1181
        :return: A BranchCheckResult.
1249
1182
        """
1250
 
        result = BranchCheckResult(self)
 
1183
        ret = BranchCheckResult(self)
 
1184
        mainline_parent_id = None
1251
1185
        last_revno, last_revision_id = self.last_revision_info()
1252
 
        actual_revno = refs[('lefthand-distance', last_revision_id)]
1253
 
        if actual_revno != last_revno:
1254
 
            result.errors.append(errors.BzrCheckError(
1255
 
                'revno does not match len(mainline) %s != %s' % (
1256
 
                last_revno, actual_revno)))
1257
 
        # TODO: We should probably also check that self.revision_history
1258
 
        # matches the repository for older branch formats.
1259
 
        # If looking for the code that cross-checks repository parents against
1260
 
        # the iter_reverse_revision_history output, that is now a repository
1261
 
        # specific check.
1262
 
        return result
 
1186
        real_rev_history = []
 
1187
        try:
 
1188
            for revid in self.repository.iter_reverse_revision_history(
 
1189
                last_revision_id):
 
1190
                real_rev_history.append(revid)
 
1191
        except errors.RevisionNotPresent:
 
1192
            ret.ghosts_in_mainline = True
 
1193
        else:
 
1194
            ret.ghosts_in_mainline = False
 
1195
        real_rev_history.reverse()
 
1196
        if len(real_rev_history) != last_revno:
 
1197
            raise errors.BzrCheckError('revno does not match len(mainline)'
 
1198
                ' %s != %s' % (last_revno, len(real_rev_history)))
 
1199
        # TODO: We should probably also check that real_rev_history actually
 
1200
        #       matches self.revision_history()
 
1201
        for revision_id in real_rev_history:
 
1202
            try:
 
1203
                revision = self.repository.get_revision(revision_id)
 
1204
            except errors.NoSuchRevision, e:
 
1205
                raise errors.BzrCheckError("mainline revision {%s} not in repository"
 
1206
                            % revision_id)
 
1207
            # In general the first entry on the revision history has no parents.
 
1208
            # But it's not illegal for it to have parents listed; this can happen
 
1209
            # in imports from Arch when the parents weren't reachable.
 
1210
            if mainline_parent_id is not None:
 
1211
                if mainline_parent_id not in revision.parent_ids:
 
1212
                    raise errors.BzrCheckError("previous revision {%s} not listed among "
 
1213
                                        "parents of {%s}"
 
1214
                                        % (mainline_parent_id, revision_id))
 
1215
            mainline_parent_id = revision_id
 
1216
        return ret
1263
1217
 
1264
1218
    def _get_checkout_format(self):
1265
1219
        """Return the most suitable metadir for a checkout of this branch.
1290
1244
        # clone call. Or something. 20090224 RBC/spiv.
1291
1245
        if revision_id is None:
1292
1246
            revision_id = self.last_revision()
1293
 
        dir_to = self.bzrdir.clone_on_transport(to_transport,
1294
 
            revision_id=revision_id, stacked_on=stacked_on,
1295
 
            create_prefix=create_prefix, use_existing_dir=use_existing_dir)
 
1247
        try:
 
1248
            dir_to = self.bzrdir.clone_on_transport(to_transport,
 
1249
                revision_id=revision_id, stacked_on=stacked_on,
 
1250
                create_prefix=create_prefix, use_existing_dir=use_existing_dir)
 
1251
        except errors.FileExists:
 
1252
            if not use_existing_dir:
 
1253
                raise
 
1254
        except errors.NoSuchFile:
 
1255
            if not create_prefix:
 
1256
                raise
1296
1257
        return dir_to.open_branch()
1297
1258
 
1298
1259
    def create_checkout(self, to_location, revision_id=None,
1317
1278
        if lightweight:
1318
1279
            format = self._get_checkout_format()
1319
1280
            checkout = format.initialize_on_transport(t)
1320
 
            from_branch = BranchReferenceFormat().initialize(checkout, 
1321
 
                target_branch=self)
 
1281
            from_branch = BranchReferenceFormat().initialize(checkout, self)
1322
1282
        else:
1323
1283
            format = self._get_checkout_format()
1324
1284
            checkout_branch = bzrdir.BzrDir.create_branch_convenience(
1366
1326
    def supports_tags(self):
1367
1327
        return self._format.supports_tags()
1368
1328
 
1369
 
    def automatic_tag_name(self, revision_id):
1370
 
        """Try to automatically find the tag name for a revision.
1371
 
 
1372
 
        :param revision_id: Revision id of the revision.
1373
 
        :return: A tag name or None if no tag name could be determined.
1374
 
        """
1375
 
        for hook in Branch.hooks['automatic_tag_name']:
1376
 
            ret = hook(self, revision_id)
1377
 
            if ret is not None:
1378
 
                return ret
1379
 
        return None
1380
 
 
1381
1329
    def _check_if_descendant_or_diverged(self, revision_a, revision_b, graph,
1382
1330
                                         other_branch):
1383
1331
        """Ensure that revision_b is a descendant of revision_a.
1447
1395
        return not (self == other)
1448
1396
 
1449
1397
    @classmethod
1450
 
    def find_format(klass, a_bzrdir, name=None):
 
1398
    def find_format(klass, a_bzrdir):
1451
1399
        """Return the format for the branch object in a_bzrdir."""
1452
1400
        try:
1453
 
            transport = a_bzrdir.get_branch_transport(None, name=name)
1454
 
            format_string = transport.get_bytes("format")
 
1401
            transport = a_bzrdir.get_branch_transport(None)
 
1402
            format_string = transport.get("format").read()
1455
1403
            return klass._formats[format_string]
1456
1404
        except errors.NoSuchFile:
1457
 
            raise errors.NotBranchError(path=transport.base, bzrdir=a_bzrdir)
 
1405
            raise errors.NotBranchError(path=transport.base)
1458
1406
        except KeyError:
1459
1407
            raise errors.UnknownFormatError(format=format_string, kind='branch')
1460
1408
 
1496
1444
        """Return the short format description for this format."""
1497
1445
        raise NotImplementedError(self.get_format_description)
1498
1446
 
1499
 
    def _initialize_helper(self, a_bzrdir, utf8_files, name=None,
1500
 
                           lock_type='metadir', set_format=True):
 
1447
    def _initialize_helper(self, a_bzrdir, utf8_files, lock_type='metadir',
 
1448
                           set_format=True):
1501
1449
        """Initialize a branch in a bzrdir, with specified files
1502
1450
 
1503
1451
        :param a_bzrdir: The bzrdir to initialize the branch in
1504
1452
        :param utf8_files: The files to create as a list of
1505
1453
            (filename, content) tuples
1506
 
        :param name: Name of colocated branch to create, if any
1507
1454
        :param set_format: If True, set the format with
1508
1455
            self.get_format_string.  (BzrBranch4 has its format set
1509
1456
            elsewhere)
1510
1457
        :return: a branch in this format
1511
1458
        """
1512
1459
        mutter('creating branch %r in %s', self, a_bzrdir.transport.base)
1513
 
        branch_transport = a_bzrdir.get_branch_transport(self, name=name)
 
1460
        branch_transport = a_bzrdir.get_branch_transport(self)
1514
1461
        lock_map = {
1515
1462
            'metadir': ('lock', lockdir.LockDir),
1516
1463
            'branch4': ('branch-lock', lockable_files.TransportLock),
1537
1484
        finally:
1538
1485
            if lock_taken:
1539
1486
                control_files.unlock()
1540
 
        return self.open(a_bzrdir, name, _found=True)
 
1487
        return self.open(a_bzrdir, _found=True)
1541
1488
 
1542
 
    def initialize(self, a_bzrdir, name=None):
1543
 
        """Create a branch of this format in a_bzrdir.
1544
 
        
1545
 
        :param name: Name of the colocated branch to create.
1546
 
        """
 
1489
    def initialize(self, a_bzrdir):
 
1490
        """Create a branch of this format in a_bzrdir."""
1547
1491
        raise NotImplementedError(self.initialize)
1548
1492
 
1549
1493
    def is_supported(self):
1579
1523
        """
1580
1524
        raise NotImplementedError(self.network_name)
1581
1525
 
1582
 
    def open(self, a_bzrdir, name=None, _found=False, ignore_fallbacks=False):
 
1526
    def open(self, a_bzrdir, _found=False, ignore_fallbacks=False):
1583
1527
        """Return the branch object for a_bzrdir
1584
1528
 
1585
1529
        :param a_bzrdir: A BzrDir that contains a branch.
1586
 
        :param name: Name of colocated branch to open
1587
1530
        :param _found: a private parameter, do not use it. It is used to
1588
1531
            indicate if format probing has already be done.
1589
1532
        :param ignore_fallbacks: when set, no fallback branches will be opened
1697
1640
            "multiple hooks installed for transform_fallback_location, "
1698
1641
            "all are called with the url returned from the previous hook."
1699
1642
            "The order is however undefined.", (1, 9), None))
1700
 
        self.create_hook(HookPoint('automatic_tag_name',
1701
 
            "Called to determine an automatic tag name for a revision."
1702
 
            "automatic_tag_name is called with (branch, revision_id) and "
1703
 
            "should return a tag name or None if no tag name could be "
1704
 
            "determined. The first non-None tag name returned will be used.",
1705
 
            (2, 2), None))
1706
 
 
1707
1643
 
1708
1644
 
1709
1645
# install the default hooks into the Branch class.
1760
1696
        """See BranchFormat.get_format_description()."""
1761
1697
        return "Branch format 4"
1762
1698
 
1763
 
    def initialize(self, a_bzrdir, name=None):
 
1699
    def initialize(self, a_bzrdir):
1764
1700
        """Create a branch of this format in a_bzrdir."""
1765
1701
        utf8_files = [('revision-history', ''),
1766
1702
                      ('branch-name', ''),
1767
1703
                      ]
1768
 
        return self._initialize_helper(a_bzrdir, utf8_files, name=name,
 
1704
        return self._initialize_helper(a_bzrdir, utf8_files,
1769
1705
                                       lock_type='branch4', set_format=False)
1770
1706
 
1771
1707
    def __init__(self):
1776
1712
        """The network name for this format is the control dirs disk label."""
1777
1713
        return self._matchingbzrdir.get_format_string()
1778
1714
 
1779
 
    def open(self, a_bzrdir, name=None, _found=False, ignore_fallbacks=False):
 
1715
    def open(self, a_bzrdir, _found=False, ignore_fallbacks=False):
1780
1716
        """See BranchFormat.open()."""
1781
1717
        if not _found:
1782
1718
            # we are being called directly and must probe.
1784
1720
        return BzrBranch(_format=self,
1785
1721
                         _control_files=a_bzrdir._control_files,
1786
1722
                         a_bzrdir=a_bzrdir,
1787
 
                         name=name,
1788
1723
                         _repository=a_bzrdir.open_repository())
1789
1724
 
1790
1725
    def __str__(self):
1805
1740
        """
1806
1741
        return self.get_format_string()
1807
1742
 
1808
 
    def open(self, a_bzrdir, name=None, _found=False, ignore_fallbacks=False):
 
1743
    def open(self, a_bzrdir, _found=False, ignore_fallbacks=False):
1809
1744
        """See BranchFormat.open()."""
1810
1745
        if not _found:
1811
 
            format = BranchFormat.find_format(a_bzrdir, name=name)
 
1746
            format = BranchFormat.find_format(a_bzrdir)
1812
1747
            if format.__class__ != self.__class__:
1813
1748
                raise AssertionError("wrong format %r found for %r" %
1814
1749
                    (format, self))
1815
1750
        try:
1816
 
            transport = a_bzrdir.get_branch_transport(None, name=name)
 
1751
            transport = a_bzrdir.get_branch_transport(None)
1817
1752
            control_files = lockable_files.LockableFiles(transport, 'lock',
1818
1753
                                                         lockdir.LockDir)
1819
1754
            return self._branch_class()(_format=self,
1820
1755
                              _control_files=control_files,
1821
 
                              name=name,
1822
1756
                              a_bzrdir=a_bzrdir,
1823
1757
                              _repository=a_bzrdir.find_repository(),
1824
1758
                              ignore_fallbacks=ignore_fallbacks)
1825
1759
        except errors.NoSuchFile:
1826
 
            raise errors.NotBranchError(path=transport.base, bzrdir=a_bzrdir)
 
1760
            raise errors.NotBranchError(path=transport.base)
1827
1761
 
1828
1762
    def __init__(self):
1829
1763
        super(BranchFormatMetadir, self).__init__()
1858
1792
        """See BranchFormat.get_format_description()."""
1859
1793
        return "Branch format 5"
1860
1794
 
1861
 
    def initialize(self, a_bzrdir, name=None):
 
1795
    def initialize(self, a_bzrdir):
1862
1796
        """Create a branch of this format in a_bzrdir."""
1863
1797
        utf8_files = [('revision-history', ''),
1864
1798
                      ('branch-name', ''),
1865
1799
                      ]
1866
 
        return self._initialize_helper(a_bzrdir, utf8_files, name)
 
1800
        return self._initialize_helper(a_bzrdir, utf8_files)
1867
1801
 
1868
1802
    def supports_tags(self):
1869
1803
        return False
1891
1825
        """See BranchFormat.get_format_description()."""
1892
1826
        return "Branch format 6"
1893
1827
 
1894
 
    def initialize(self, a_bzrdir, name=None):
 
1828
    def initialize(self, a_bzrdir):
1895
1829
        """Create a branch of this format in a_bzrdir."""
1896
1830
        utf8_files = [('last-revision', '0 null:\n'),
1897
1831
                      ('branch.conf', ''),
1898
1832
                      ('tags', ''),
1899
1833
                      ]
1900
 
        return self._initialize_helper(a_bzrdir, utf8_files, name)
 
1834
        return self._initialize_helper(a_bzrdir, utf8_files)
1901
1835
 
1902
1836
    def make_tags(self, branch):
1903
1837
        """See bzrlib.branch.BranchFormat.make_tags()."""
1921
1855
        """See BranchFormat.get_format_description()."""
1922
1856
        return "Branch format 8"
1923
1857
 
1924
 
    def initialize(self, a_bzrdir, name=None):
 
1858
    def initialize(self, a_bzrdir):
1925
1859
        """Create a branch of this format in a_bzrdir."""
1926
1860
        utf8_files = [('last-revision', '0 null:\n'),
1927
1861
                      ('branch.conf', ''),
1928
1862
                      ('tags', ''),
1929
1863
                      ('references', '')
1930
1864
                      ]
1931
 
        return self._initialize_helper(a_bzrdir, utf8_files, name)
 
1865
        return self._initialize_helper(a_bzrdir, utf8_files)
1932
1866
 
1933
1867
    def __init__(self):
1934
1868
        super(BzrBranchFormat8, self).__init__()
1957
1891
    This format was introduced in bzr 1.6.
1958
1892
    """
1959
1893
 
1960
 
    def initialize(self, a_bzrdir, name=None):
 
1894
    def initialize(self, a_bzrdir):
1961
1895
        """Create a branch of this format in a_bzrdir."""
1962
1896
        utf8_files = [('last-revision', '0 null:\n'),
1963
1897
                      ('branch.conf', ''),
1964
1898
                      ('tags', ''),
1965
1899
                      ]
1966
 
        return self._initialize_helper(a_bzrdir, utf8_files, name)
 
1900
        return self._initialize_helper(a_bzrdir, utf8_files)
1967
1901
 
1968
1902
    def _branch_class(self):
1969
1903
        return BzrBranch7
2004
1938
    def get_reference(self, a_bzrdir):
2005
1939
        """See BranchFormat.get_reference()."""
2006
1940
        transport = a_bzrdir.get_branch_transport(None)
2007
 
        return transport.get_bytes('location')
 
1941
        return transport.get('location').read()
2008
1942
 
2009
1943
    def set_reference(self, a_bzrdir, to_branch):
2010
1944
        """See BranchFormat.set_reference()."""
2011
1945
        transport = a_bzrdir.get_branch_transport(None)
2012
1946
        location = transport.put_bytes('location', to_branch.base)
2013
1947
 
2014
 
    def initialize(self, a_bzrdir, name=None, target_branch=None):
 
1948
    def initialize(self, a_bzrdir, target_branch=None):
2015
1949
        """Create a branch of this format in a_bzrdir."""
2016
1950
        if target_branch is None:
2017
1951
            # this format does not implement branch itself, thus the implicit
2018
1952
            # creation contract must see it as uninitializable
2019
1953
            raise errors.UninitializableFormat(self)
2020
1954
        mutter('creating branch reference in %s', a_bzrdir.transport.base)
2021
 
        branch_transport = a_bzrdir.get_branch_transport(self, name=name)
 
1955
        branch_transport = a_bzrdir.get_branch_transport(self)
2022
1956
        branch_transport.put_bytes('location',
2023
1957
            target_branch.bzrdir.root_transport.base)
2024
1958
        branch_transport.put_bytes('format', self.get_format_string())
2025
1959
        return self.open(
2026
 
            a_bzrdir, name, _found=True,
 
1960
            a_bzrdir, _found=True,
2027
1961
            possible_transports=[target_branch.bzrdir.root_transport])
2028
1962
 
2029
1963
    def __init__(self):
2036
1970
        def clone(to_bzrdir, revision_id=None,
2037
1971
            repository_policy=None):
2038
1972
            """See Branch.clone()."""
2039
 
            return format.initialize(to_bzrdir, target_branch=a_branch)
 
1973
            return format.initialize(to_bzrdir, a_branch)
2040
1974
            # cannot obey revision_id limits when cloning a reference ...
2041
1975
            # FIXME RBC 20060210 either nuke revision_id for clone, or
2042
1976
            # emit some sort of warning/error to the caller ?!
2043
1977
        return clone
2044
1978
 
2045
 
    def open(self, a_bzrdir, name=None, _found=False, location=None,
 
1979
    def open(self, a_bzrdir, _found=False, location=None,
2046
1980
             possible_transports=None, ignore_fallbacks=False):
2047
1981
        """Return the branch that the branch reference in a_bzrdir points at.
2048
1982
 
2049
1983
        :param a_bzrdir: A BzrDir that contains a branch.
2050
 
        :param name: Name of colocated branch to open, if any
2051
1984
        :param _found: a private parameter, do not use it. It is used to
2052
1985
            indicate if format probing has already be done.
2053
1986
        :param ignore_fallbacks: when set, no fallback branches will be opened
2058
1991
        :param possible_transports: An optional reusable transports list.
2059
1992
        """
2060
1993
        if not _found:
2061
 
            format = BranchFormat.find_format(a_bzrdir, name=name)
 
1994
            format = BranchFormat.find_format(a_bzrdir)
2062
1995
            if format.__class__ != self.__class__:
2063
1996
                raise AssertionError("wrong format %r found for %r" %
2064
1997
                    (format, self))
2066
1999
            location = self.get_reference(a_bzrdir)
2067
2000
        real_bzrdir = bzrdir.BzrDir.open(
2068
2001
            location, possible_transports=possible_transports)
2069
 
        result = real_bzrdir.open_branch(name=name, 
2070
 
            ignore_fallbacks=ignore_fallbacks)
 
2002
        result = real_bzrdir.open_branch(ignore_fallbacks=ignore_fallbacks)
2071
2003
        # this changes the behaviour of result.clone to create a new reference
2072
2004
        # rather than a copy of the content of the branch.
2073
2005
        # I did not use a proxy object because that needs much more extensive
2100
2032
BranchFormat.register_format(__format6)
2101
2033
BranchFormat.register_format(__format7)
2102
2034
BranchFormat.register_format(__format8)
2103
 
BranchFormat.set_default_format(__format7)
 
2035
BranchFormat.set_default_format(__format6)
2104
2036
_legacy_formats = [BzrBranchFormat4(),
2105
2037
    ]
2106
2038
network_format_registry.register(
2107
2039
    _legacy_formats[0].network_name(), _legacy_formats[0].__class__)
2108
2040
 
2109
2041
 
2110
 
class BzrBranch(Branch, _RelockDebugMixin):
 
2042
class BzrBranch(Branch):
2111
2043
    """A branch stored in the actual filesystem.
2112
2044
 
2113
2045
    Note that it's "local" in the context of the filesystem; it doesn't
2119
2051
    :ivar repository: Repository for this branch.
2120
2052
    :ivar base: The url of the base directory for this branch; the one
2121
2053
        containing the .bzr directory.
2122
 
    :ivar name: Optional colocated branch name as it exists in the control
2123
 
        directory.
2124
2054
    """
2125
2055
 
2126
2056
    def __init__(self, _format=None,
2127
 
                 _control_files=None, a_bzrdir=None, name=None,
2128
 
                 _repository=None, ignore_fallbacks=False):
 
2057
                 _control_files=None, a_bzrdir=None, _repository=None,
 
2058
                 ignore_fallbacks=False):
2129
2059
        """Create new branch object at a particular location."""
2130
2060
        if a_bzrdir is None:
2131
2061
            raise ValueError('a_bzrdir must be supplied')
2132
2062
        else:
2133
2063
            self.bzrdir = a_bzrdir
2134
2064
        self._base = self.bzrdir.transport.clone('..').base
2135
 
        self.name = name
2136
2065
        # XXX: We should be able to just do
2137
2066
        #   self.base = self.bzrdir.root_transport.base
2138
2067
        # but this does not quite work yet -- mbp 20080522
2145
2074
        Branch.__init__(self)
2146
2075
 
2147
2076
    def __str__(self):
2148
 
        if self.name is None:
2149
 
            return '%s(%r)' % (self.__class__.__name__, self.base)
2150
 
        else:
2151
 
            return '%s(%r,%r)' % (self.__class__.__name__, self.base, self.name)
 
2077
        return '%s(%r)' % (self.__class__.__name__, self.base)
2152
2078
 
2153
2079
    __repr__ = __str__
2154
2080
 
2165
2091
        return self.control_files.is_locked()
2166
2092
 
2167
2093
    def lock_write(self, token=None):
2168
 
        if not self.is_locked():
2169
 
            self._note_lock('w')
2170
2094
        # All-in-one needs to always unlock/lock.
2171
2095
        repo_control = getattr(self.repository, 'control_files', None)
2172
2096
        if self.control_files == repo_control or not self.is_locked():
2173
 
            self.repository._warn_if_deprecated(self)
2174
2097
            self.repository.lock_write()
2175
2098
            took_lock = True
2176
2099
        else:
2183
2106
            raise
2184
2107
 
2185
2108
    def lock_read(self):
2186
 
        if not self.is_locked():
2187
 
            self._note_lock('r')
2188
2109
        # All-in-one needs to always unlock/lock.
2189
2110
        repo_control = getattr(self.repository, 'control_files', None)
2190
2111
        if self.control_files == repo_control or not self.is_locked():
2191
 
            self.repository._warn_if_deprecated(self)
2192
2112
            self.repository.lock_read()
2193
2113
            took_lock = True
2194
2114
        else:
2200
2120
                self.repository.unlock()
2201
2121
            raise
2202
2122
 
2203
 
    @only_raises(errors.LockNotHeld, errors.LockBroken)
2204
2123
    def unlock(self):
2205
2124
        try:
2206
2125
            self.control_files.unlock()
2877
2796
 
2878
2797
    def __init__(self, branch):
2879
2798
        self.branch = branch
2880
 
        self.errors = []
 
2799
        self.ghosts_in_mainline = False
2881
2800
 
2882
2801
    def report_results(self, verbose):
2883
2802
        """Report the check results via trace.note.
2885
2804
        :param verbose: Requests more detailed display of what was checked,
2886
2805
            if any.
2887
2806
        """
2888
 
        note('checked branch %s format %s', self.branch.base,
2889
 
            self.branch._format)
2890
 
        for error in self.errors:
2891
 
            note('found error:%s', error)
 
2807
        note('checked branch %s format %s',
 
2808
             self.branch.base,
 
2809
             self.branch._format)
 
2810
        if self.ghosts_in_mainline:
 
2811
            note('branch contains ghosts in mainline')
2892
2812
 
2893
2813
 
2894
2814
class Converter5to6(object):
2989
2909
    @staticmethod
2990
2910
    def _get_branch_formats_to_test():
2991
2911
        """Return a tuple with the Branch formats to use when testing."""
2992
 
        raise NotImplementedError(InterBranch._get_branch_formats_to_test)
 
2912
        raise NotImplementedError(self._get_branch_formats_to_test)
2993
2913
 
2994
2914
    def pull(self, overwrite=False, stop_revision=None,
2995
2915
             possible_transports=None, local=False):
3150
3070
                _override_hook_source_branch=_override_hook_source_branch)
3151
3071
        finally:
3152
3072
            self.source.unlock()
 
3073
        return result
3153
3074
 
3154
3075
    def _push_with_bound_branches(self, overwrite, stop_revision,
3155
3076
            _override_hook_source_branch=None):