~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/branch.py

  • Committer: Martin von Gagern
  • Date: 2011-06-01 12:53:56 UTC
  • mto: This revision was merged to the branch mainline in revision 6009.
  • Revision ID: martin.vgagern@gmx.net-20110601125356-lwozv2vecea6hxfz
Change from no_decorate to classify as name for the argument.

The command line switch remains as --no-classify, to keep backwards
compatibility.  Users are free to include --no-classify in an alias, and
still use --classify to change back.

Show diffs side-by-side

added added

removed removed

Lines of Context:
16
16
 
17
17
 
18
18
from cStringIO import StringIO
 
19
import sys
19
20
 
20
21
from bzrlib.lazy_import import lazy_import
21
22
lazy_import(globals(), """
22
 
import itertools
 
23
from itertools import chain
23
24
from bzrlib import (
24
25
        bzrdir,
25
26
        cache_utf8,
35
36
        repository,
36
37
        revision as _mod_revision,
37
38
        rio,
38
 
        tag as _mod_tag,
39
39
        transport,
40
40
        ui,
41
41
        urlutils,
42
42
        )
43
 
from bzrlib.i18n import gettext, ngettext
 
43
from bzrlib.config import BranchConfig, TransportConfig
 
44
from bzrlib.tag import (
 
45
    BasicTags,
 
46
    DisabledTags,
 
47
    )
44
48
""")
45
49
 
46
50
from bzrlib import (
62
66
from bzrlib.trace import mutter, mutter_callsite, note, is_quiet
63
67
 
64
68
 
 
69
BZR_BRANCH_FORMAT_4 = "Bazaar-NG branch, format 0.0.4\n"
 
70
BZR_BRANCH_FORMAT_5 = "Bazaar-NG branch, format 5\n"
 
71
BZR_BRANCH_FORMAT_6 = "Bazaar Branch Format 6 (bzr 0.15)\n"
 
72
 
 
73
 
65
74
class Branch(controldir.ControlComponent):
66
75
    """Branch holding a history of revisions.
67
76
 
213
222
 
214
223
        :return: A bzrlib.config.BranchConfig.
215
224
        """
216
 
        return _mod_config.BranchConfig(self)
217
 
 
218
 
    def get_config_stack(self):
219
 
        """Get a bzrlib.config.BranchStack for this Branch.
220
 
 
221
 
        This can then be used to get and set configuration options for the
222
 
        branch.
223
 
 
224
 
        :return: A bzrlib.config.BranchStack.
225
 
        """
226
 
        return _mod_config.BranchStack(self)
 
225
        return BranchConfig(self)
227
226
 
228
227
    def _get_config(self):
229
228
        """Get the concrete config for just the config in this branch.
514
513
        rev_iter = iter(merge_sorted_revisions)
515
514
        if start_revision_id is not None:
516
515
            for node in rev_iter:
517
 
                rev_id = node.key
 
516
                rev_id = node.key[-1]
518
517
                if rev_id != start_revision_id:
519
518
                    continue
520
519
                else:
521
520
                    # The decision to include the start or not
522
521
                    # depends on the stop_rule if a stop is provided
523
522
                    # so pop this node back into the iterator
524
 
                    rev_iter = itertools.chain(iter([node]), rev_iter)
 
523
                    rev_iter = chain(iter([node]), rev_iter)
525
524
                    break
526
525
        if stop_revision_id is None:
527
526
            # Yield everything
528
527
            for node in rev_iter:
529
 
                rev_id = node.key
 
528
                rev_id = node.key[-1]
530
529
                yield (rev_id, node.merge_depth, node.revno,
531
530
                       node.end_of_merge)
532
531
        elif stop_rule == 'exclude':
533
532
            for node in rev_iter:
534
 
                rev_id = node.key
 
533
                rev_id = node.key[-1]
535
534
                if rev_id == stop_revision_id:
536
535
                    return
537
536
                yield (rev_id, node.merge_depth, node.revno,
538
537
                       node.end_of_merge)
539
538
        elif stop_rule == 'include':
540
539
            for node in rev_iter:
541
 
                rev_id = node.key
 
540
                rev_id = node.key[-1]
542
541
                yield (rev_id, node.merge_depth, node.revno,
543
542
                       node.end_of_merge)
544
543
                if rev_id == stop_revision_id:
550
549
            ancestors = graph.find_unique_ancestors(start_revision_id,
551
550
                                                    [stop_revision_id])
552
551
            for node in rev_iter:
553
 
                rev_id = node.key
 
552
                rev_id = node.key[-1]
554
553
                if rev_id not in ancestors:
555
554
                    continue
556
555
                yield (rev_id, node.merge_depth, node.revno,
566
565
            reached_stop_revision_id = False
567
566
            revision_id_whitelist = []
568
567
            for node in rev_iter:
569
 
                rev_id = node.key
 
568
                rev_id = node.key[-1]
570
569
                if rev_id == left_parent:
571
570
                    # reached the left parent after the stop_revision
572
571
                    return
652
651
        """
653
652
        raise errors.UpgradeRequired(self.user_url)
654
653
 
655
 
    def get_append_revisions_only(self):
656
 
        """Whether it is only possible to append revisions to the history.
657
 
        """
658
 
        if not self._format.supports_set_append_revisions_only():
659
 
            return False
660
 
        return self.get_config(
661
 
            ).get_user_option_as_bool('append_revisions_only')
662
 
 
663
654
    def set_append_revisions_only(self, enabled):
664
655
        if not self._format.supports_set_append_revisions_only():
665
656
            raise errors.UpgradeRequired(self.user_url)
794
785
                                  other_branch=None):
795
786
        """See Branch.generate_revision_history"""
796
787
        graph = self.repository.get_graph()
797
 
        (last_revno, last_revid) = self.last_revision_info()
798
788
        known_revision_ids = [
799
 
            (last_revid, last_revno),
 
789
            self.last_revision_info(),
800
790
            (_mod_revision.NULL_REVISION, 0),
801
791
            ]
802
792
        if last_rev is not None:
859
849
        """
860
850
        pb = ui.ui_factory.nested_progress_bar()
861
851
        try:
862
 
            pb.update(gettext("Unstacking"))
 
852
            pb.update("Unstacking")
863
853
            # The basic approach here is to fetch the tip of the branch,
864
854
            # including all available ghosts, from the existing stacked
865
855
            # repository into a new repository object without the fallbacks. 
1303
1293
            if repository_policy is not None:
1304
1294
                repository_policy.configure_branch(result)
1305
1295
            self.copy_content_into(result, revision_id=revision_id)
1306
 
            master_url = self.get_bound_location()
1307
 
            if master_url is None:
 
1296
            master_branch = self.get_master_branch()
 
1297
            if master_branch is None:
1308
1298
                result.set_parent(self.bzrdir.root_transport.base)
1309
1299
            else:
1310
 
                result.set_parent(master_url)
 
1300
                result.set_parent(master_branch.bzrdir.root_transport.base)
1311
1301
        finally:
1312
1302
            result.unlock()
1313
1303
        return result
1391
1381
        # specific check.
1392
1382
        return result
1393
1383
 
1394
 
    def _get_checkout_format(self, lightweight=False):
 
1384
    def _get_checkout_format(self):
1395
1385
        """Return the most suitable metadir for a checkout of this branch.
1396
1386
        Weaves are used if this branch's repository uses weaves.
1397
1387
        """
1443
1433
        """
1444
1434
        t = transport.get_transport(to_location)
1445
1435
        t.ensure_base()
1446
 
        format = self._get_checkout_format(lightweight=lightweight)
1447
1436
        if lightweight:
 
1437
            format = self._get_checkout_format()
1448
1438
            checkout = format.initialize_on_transport(t)
1449
1439
            from_branch = BranchReferenceFormat().initialize(checkout, 
1450
1440
                target_branch=self)
1451
1441
        else:
 
1442
            format = self._get_checkout_format()
1452
1443
            checkout_branch = bzrdir.BzrDir.create_branch_convenience(
1453
1444
                to_location, force_new_tree=False, format=format)
1454
1445
            checkout = checkout_branch.bzrdir
1554
1545
        # For bzr native formats must_fetch is just the tip, and if_present_fetch
1555
1546
        # are the tags.
1556
1547
        must_fetch = set([self.last_revision()])
1557
 
        if_present_fetch = set()
1558
 
        c = self.get_config()
1559
 
        include_tags = c.get_user_option_as_bool('branch.fetch_tags',
1560
 
                                                 default=False)
1561
 
        if include_tags:
1562
 
            try:
1563
 
                if_present_fetch = set(self.tags.get_reverse_tag_dict())
1564
 
            except errors.TagsNotSupported:
1565
 
                pass
 
1548
        try:
 
1549
            if_present_fetch = set(self.tags.get_reverse_tag_dict())
 
1550
        except errors.TagsNotSupported:
 
1551
            if_present_fetch = set()
1566
1552
        must_fetch.discard(_mod_revision.NULL_REVISION)
1567
1553
        if_present_fetch.discard(_mod_revision.NULL_REVISION)
1568
1554
        return must_fetch, if_present_fetch
1586
1572
    object will be created every time regardless.
1587
1573
    """
1588
1574
 
 
1575
    can_set_append_revisions_only = True
 
1576
 
1589
1577
    def __eq__(self, other):
1590
1578
        return self.__class__ is other.__class__
1591
1579
 
1663
1651
        for hook in hooks:
1664
1652
            hook(params)
1665
1653
 
1666
 
    def initialize(self, a_bzrdir, name=None, repository=None,
1667
 
                   append_revisions_only=None):
 
1654
    def initialize(self, a_bzrdir, name=None, repository=None):
1668
1655
        """Create a branch of this format in a_bzrdir.
1669
1656
        
1670
1657
        :param name: Name of the colocated branch to create.
1692
1679
        Note that it is normal for branch to be a RemoteBranch when using tags
1693
1680
        on a RemoteBranch.
1694
1681
        """
1695
 
        return _mod_tag.DisabledTags(branch)
 
1682
        return DisabledTags(branch)
1696
1683
 
1697
1684
    def network_name(self):
1698
1685
        """A simple byte string uniquely identifying this format for RPC calls.
1756
1743
        """True if this format supports tags stored in the branch"""
1757
1744
        return False  # by default
1758
1745
 
1759
 
    def tags_are_versioned(self):
1760
 
        """Whether the tag container for this branch versions tags."""
1761
 
        return False
1762
 
 
1763
 
    def supports_tags_referencing_ghosts(self):
1764
 
        """True if tags can reference ghost revisions."""
1765
 
        return True
1766
 
 
1767
1746
 
1768
1747
class MetaDirBranchFormatFactory(registry._LazyObjectGetter):
1769
1748
    """A factory for a BranchFormat object, permitting simple lazy registration.
2008
1987
        """What class to instantiate on open calls."""
2009
1988
        raise NotImplementedError(self._branch_class)
2010
1989
 
2011
 
    def _get_initial_config(self, append_revisions_only=None):
2012
 
        if append_revisions_only:
2013
 
            return "append_revisions_only = True\n"
2014
 
        else:
2015
 
            # Avoid writing anything if append_revisions_only is disabled,
2016
 
            # as that is the default.
2017
 
            return ""
2018
 
 
2019
1990
    def _initialize_helper(self, a_bzrdir, utf8_files, name=None,
2020
1991
                           repository=None):
2021
1992
        """Initialize a branch in a bzrdir, with specified files
2111
2082
        """See BranchFormat.get_format_description()."""
2112
2083
        return "Branch format 5"
2113
2084
 
2114
 
    def initialize(self, a_bzrdir, name=None, repository=None,
2115
 
                   append_revisions_only=None):
 
2085
    def initialize(self, a_bzrdir, name=None, repository=None):
2116
2086
        """Create a branch of this format in a_bzrdir."""
2117
 
        if append_revisions_only:
2118
 
            raise errors.UpgradeRequired(a_bzrdir.user_url)
2119
2087
        utf8_files = [('revision-history', ''),
2120
2088
                      ('branch-name', ''),
2121
2089
                      ]
2147
2115
        """See BranchFormat.get_format_description()."""
2148
2116
        return "Branch format 6"
2149
2117
 
2150
 
    def initialize(self, a_bzrdir, name=None, repository=None,
2151
 
                   append_revisions_only=None):
 
2118
    def initialize(self, a_bzrdir, name=None, repository=None):
2152
2119
        """Create a branch of this format in a_bzrdir."""
2153
2120
        utf8_files = [('last-revision', '0 null:\n'),
2154
 
                      ('branch.conf',
2155
 
                          self._get_initial_config(append_revisions_only)),
 
2121
                      ('branch.conf', ''),
2156
2122
                      ('tags', ''),
2157
2123
                      ]
2158
2124
        return self._initialize_helper(a_bzrdir, utf8_files, name, repository)
2159
2125
 
2160
2126
    def make_tags(self, branch):
2161
2127
        """See bzrlib.branch.BranchFormat.make_tags()."""
2162
 
        return _mod_tag.BasicTags(branch)
 
2128
        return BasicTags(branch)
2163
2129
 
2164
2130
    def supports_set_append_revisions_only(self):
2165
2131
        return True
2179
2145
        """See BranchFormat.get_format_description()."""
2180
2146
        return "Branch format 8"
2181
2147
 
2182
 
    def initialize(self, a_bzrdir, name=None, repository=None,
2183
 
                   append_revisions_only=None):
 
2148
    def initialize(self, a_bzrdir, name=None, repository=None):
2184
2149
        """Create a branch of this format in a_bzrdir."""
2185
2150
        utf8_files = [('last-revision', '0 null:\n'),
2186
 
                      ('branch.conf',
2187
 
                          self._get_initial_config(append_revisions_only)),
 
2151
                      ('branch.conf', ''),
2188
2152
                      ('tags', ''),
2189
2153
                      ('references', '')
2190
2154
                      ]
2192
2156
 
2193
2157
    def make_tags(self, branch):
2194
2158
        """See bzrlib.branch.BranchFormat.make_tags()."""
2195
 
        return _mod_tag.BasicTags(branch)
 
2159
        return BasicTags(branch)
2196
2160
 
2197
2161
    def supports_set_append_revisions_only(self):
2198
2162
        return True
2212
2176
    This format was introduced in bzr 1.6.
2213
2177
    """
2214
2178
 
2215
 
    def initialize(self, a_bzrdir, name=None, repository=None,
2216
 
                   append_revisions_only=None):
 
2179
    def initialize(self, a_bzrdir, name=None, repository=None):
2217
2180
        """Create a branch of this format in a_bzrdir."""
2218
2181
        utf8_files = [('last-revision', '0 null:\n'),
2219
 
                      ('branch.conf',
2220
 
                          self._get_initial_config(append_revisions_only)),
 
2182
                      ('branch.conf', ''),
2221
2183
                      ('tags', ''),
2222
2184
                      ]
2223
2185
        return self._initialize_helper(a_bzrdir, utf8_files, name, repository)
2241
2203
 
2242
2204
    def make_tags(self, branch):
2243
2205
        """See bzrlib.branch.BranchFormat.make_tags()."""
2244
 
        return _mod_tag.BasicTags(branch)
 
2206
        return BasicTags(branch)
2245
2207
 
2246
2208
    supports_reference_locations = False
2247
2209
 
2276
2238
        location = transport.put_bytes('location', to_branch.base)
2277
2239
 
2278
2240
    def initialize(self, a_bzrdir, name=None, target_branch=None,
2279
 
            repository=None, append_revisions_only=None):
 
2241
            repository=None):
2280
2242
        """Create a branch of this format in a_bzrdir."""
2281
2243
        if target_branch is None:
2282
2244
            # this format does not implement branch itself, thus the implicit
2283
2245
            # creation contract must see it as uninitializable
2284
2246
            raise errors.UninitializableFormat(self)
2285
2247
        mutter('creating branch reference in %s', a_bzrdir.user_url)
2286
 
        if a_bzrdir._format.fixed_components:
2287
 
            raise errors.IncompatibleFormat(self, a_bzrdir._format)
2288
2248
        branch_transport = a_bzrdir.get_branch_transport(self, name=name)
2289
2249
        branch_transport.put_bytes('location',
2290
2250
            target_branch.bzrdir.user_url)
2459
2419
    base = property(_get_base, doc="The URL for the root of this branch.")
2460
2420
 
2461
2421
    def _get_config(self):
2462
 
        return _mod_config.TransportConfig(self._transport, 'branch.conf')
 
2422
        return TransportConfig(self._transport, 'branch.conf')
2463
2423
 
2464
2424
    def is_locked(self):
2465
2425
        return self.control_files.is_locked()
2546
2506
            raise errors.InvalidRevisionId(revision_id=revision_id, branch=self)
2547
2507
        revision_id = _mod_revision.ensure_null(revision_id)
2548
2508
        old_revno, old_revid = self.last_revision_info()
2549
 
        if self.get_append_revisions_only():
 
2509
        if self._get_append_revisions_only():
2550
2510
            self._check_history_violation(revision_id)
2551
2511
        self._run_pre_change_branch_tip_hooks(revno, revision_id)
2552
2512
        self._write_last_revision_info(revno, revision_id)
2982
2942
        # you can always ask for the URL; but you might not be able to use it
2983
2943
        # if the repo can't support stacking.
2984
2944
        ## self._check_stackable_repo()
2985
 
        # stacked_on_location is only ever defined in branch.conf, so don't
2986
 
        # waste effort reading the whole stack of config files.
2987
 
        config = self.get_config()._get_branch_data_config()
2988
 
        stacked_url = self._get_config_location('stacked_on_location',
2989
 
            config=config)
 
2945
        stacked_url = self._get_config_location('stacked_on_location')
2990
2946
        if stacked_url is None:
2991
2947
            raise errors.NotStacked(self)
2992
2948
        return stacked_url
2993
2949
 
 
2950
    def _get_append_revisions_only(self):
 
2951
        return self.get_config(
 
2952
            ).get_user_option_as_bool('append_revisions_only')
 
2953
 
2994
2954
    @needs_read_lock
2995
2955
    def get_rev_id(self, revno, history=None):
2996
2956
        """Find the revision id of the specified revno."""
3082
3042
    :ivar local_branch: target branch if there is a Master, else None
3083
3043
    :ivar target_branch: Target/destination branch object. (write locked)
3084
3044
    :ivar tag_conflicts: A list of tag conflicts, see BasicTags.merge_to
3085
 
    :ivar tag_updates: A dict with new tags, see BasicTags.merge_to
3086
3045
    """
3087
3046
 
3088
3047
    @deprecated_method(deprecated_in((2, 3, 0)))
3094
3053
        return self.new_revno - self.old_revno
3095
3054
 
3096
3055
    def report(self, to_file):
3097
 
        tag_conflicts = getattr(self, "tag_conflicts", None)
3098
 
        tag_updates = getattr(self, "tag_updates", None)
3099
3056
        if not is_quiet():
3100
 
            if self.old_revid != self.new_revid:
 
3057
            if self.old_revid == self.new_revid:
 
3058
                to_file.write('No revisions to pull.\n')
 
3059
            else:
3101
3060
                to_file.write('Now on revision %d.\n' % self.new_revno)
3102
 
            if tag_updates:
3103
 
                to_file.write('%d tag(s) updated.\n' % len(tag_updates))
3104
 
            if self.old_revid == self.new_revid and not tag_updates:
3105
 
                if not tag_conflicts:
3106
 
                    to_file.write('No revisions or tags to pull.\n')
3107
 
                else:
3108
 
                    to_file.write('No revisions to pull.\n')
3109
3061
        self._show_tag_conficts(to_file)
3110
3062
 
3111
3063
 
3137
3089
        return self.new_revno - self.old_revno
3138
3090
 
3139
3091
    def report(self, to_file):
3140
 
        # TODO: This function gets passed a to_file, but then
3141
 
        # ignores it and calls note() instead. This is also
3142
 
        # inconsistent with PullResult(), which writes to stdout.
3143
 
        # -- JRV20110901, bug #838853
3144
 
        tag_conflicts = getattr(self, "tag_conflicts", None)
3145
 
        tag_updates = getattr(self, "tag_updates", None)
3146
 
        if not is_quiet():
3147
 
            if self.old_revid != self.new_revid:
3148
 
                note(gettext('Pushed up to revision %d.') % self.new_revno)
3149
 
            if tag_updates:
3150
 
                note(ngettext('%d tag updated.', '%d tags updated.', len(tag_updates)) % len(tag_updates))
3151
 
            if self.old_revid == self.new_revid and not tag_updates:
3152
 
                if not tag_conflicts:
3153
 
                    note(gettext('No new revisions or tags to push.'))
3154
 
                else:
3155
 
                    note(gettext('No new revisions to push.'))
 
3092
        """Write a human-readable description of the result."""
 
3093
        if self.old_revid == self.new_revid:
 
3094
            note('No new revisions to push.')
 
3095
        else:
 
3096
            note('Pushed up to revision %d.' % self.new_revno)
3156
3097
        self._show_tag_conficts(to_file)
3157
3098
 
3158
3099
 
3172
3113
        :param verbose: Requests more detailed display of what was checked,
3173
3114
            if any.
3174
3115
        """
3175
 
        note(gettext('checked branch {0} format {1}').format(
3176
 
                                self.branch.user_url, self.branch._format))
 
3116
        note('checked branch %s format %s', self.branch.user_url,
 
3117
            self.branch._format)
3177
3118
        for error in self.errors:
3178
 
            note(gettext('found error:%s'), error)
 
3119
            note('found error:%s', error)
3179
3120
 
3180
3121
 
3181
3122
class Converter5to6(object):
3220
3161
 
3221
3162
 
3222
3163
class Converter7to8(object):
3223
 
    """Perform an in-place upgrade of format 7 to format 8"""
 
3164
    """Perform an in-place upgrade of format 6 to format 7"""
3224
3165
 
3225
3166
    def convert(self, branch):
3226
3167
        format = BzrBranchFormat8()
3399
3340
        if local and not bound_location:
3400
3341
            raise errors.LocalRequiresBoundBranch()
3401
3342
        master_branch = None
3402
 
        source_is_master = False
3403
 
        if bound_location:
3404
 
            # bound_location comes from a config file, some care has to be
3405
 
            # taken to relate it to source.user_url
3406
 
            normalized = urlutils.normalize_url(bound_location)
3407
 
            try:
3408
 
                relpath = self.source.user_transport.relpath(normalized)
3409
 
                source_is_master = (relpath == '')
3410
 
            except (errors.PathNotChild, errors.InvalidURL):
3411
 
                source_is_master = False
 
3343
        source_is_master = (self.source.user_url == bound_location)
3412
3344
        if not local and bound_location and not source_is_master:
3413
3345
            # not pulling from master, so we need to update master.
3414
3346
            master_branch = self.target.get_master_branch(possible_transports)
3466
3398
            self._update_revisions(stop_revision, overwrite=overwrite,
3467
3399
                    graph=graph)
3468
3400
        if self.source._push_should_merge_tags():
3469
 
            result.tag_updates, result.tag_conflicts = (
3470
 
                self.source.tags.merge_to(self.target.tags, overwrite))
 
3401
            result.tag_conflicts = self.source.tags.merge_to(self.target.tags,
 
3402
                overwrite)
3471
3403
        result.new_revno, result.new_revid = self.target.last_revision_info()
3472
3404
        return result
3473
3405
 
3556
3488
            # TODO: The old revid should be specified when merging tags, 
3557
3489
            # so a tags implementation that versions tags can only 
3558
3490
            # pull in the most recent changes. -- JRV20090506
3559
 
            result.tag_updates, result.tag_conflicts = (
3560
 
                self.source.tags.merge_to(self.target.tags, overwrite,
3561
 
                    ignore_master=not merge_tags_to_master))
 
3491
            result.tag_conflicts = self.source.tags.merge_to(self.target.tags,
 
3492
                overwrite, ignore_master=not merge_tags_to_master)
3562
3493
            result.new_revno, result.new_revid = self.target.last_revision_info()
3563
3494
            if _hook_master:
3564
3495
                result.master_branch = _hook_master