/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: Martin Pool
  • Date: 2011-04-01 03:07:34 UTC
  • mfrom: (5609.29.3 2.3)
  • mto: (5609.29.4 2.3)
  • mto: This revision was merged to the branch mainline in revision 5755.
  • Revision ID: mbp@canonical.com-20110401030734-wip8a66uf8aphgud
merge up to bzr 2.3

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,
64
65
BZR_BRANCH_FORMAT_6 = "Bazaar Branch Format 6 (bzr 0.15)\n"
65
66
 
66
67
 
67
 
class Branch(bzrdir.ControlComponent):
 
68
class Branch(controldir.ControlComponent):
68
69
    """Branch holding a history of revisions.
69
70
 
70
71
    :ivar base:
71
72
        Base directory/url of the branch; using control_url and
72
73
        control_transport is more standardized.
73
 
 
74
 
    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.
75
77
    """
76
78
    # this is really an instance variable - FIXME move it there
77
79
    # - RBC 20060112
91
93
        self._revision_id_to_revno_cache = None
92
94
        self._partial_revision_id_to_revno_cache = {}
93
95
        self._partial_revision_history_cache = []
 
96
        self._tags_bytes = None
94
97
        self._last_revision_info_cache = None
 
98
        self._master_branch_cache = None
95
99
        self._merge_sorted_revisions_cache = None
96
100
        self._open_hook()
97
101
        hooks = Branch.hooks['open']
103
107
 
104
108
    def _activate_fallback_location(self, url):
105
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
106
117
        repo = self._get_fallback_repository(url)
107
118
        if repo.has_same_location(self.repository):
108
119
            raise errors.UnstackableLocationError(self.user_url, url)
226
237
            possible_transports=[self.bzrdir.root_transport])
227
238
        return a_branch.repository
228
239
 
 
240
    @needs_read_lock
229
241
    def _get_tags_bytes(self):
230
242
        """Get the bytes of a serialised tags dict.
231
243
 
238
250
        :return: The bytes of the tags file.
239
251
        :seealso: Branch._set_tags_bytes.
240
252
        """
241
 
        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
242
256
 
243
257
    def _get_nick(self, local=False, possible_transports=None):
244
258
        config = self.get_config()
804
818
            old_repository = self.repository
805
819
            if len(old_repository._fallback_repositories) != 1:
806
820
                raise AssertionError("can't cope with fallback repositories "
807
 
                    "of %r" % (self.repository,))
 
821
                    "of %r (fallbacks: %r)" % (old_repository,
 
822
                        old_repository._fallback_repositories))
808
823
            # Open the new repository object.
809
824
            # Repositories don't offer an interface to remove fallback
810
825
            # repositories today; take the conceptually simpler option and just
875
890
 
876
891
        :seealso: Branch._get_tags_bytes.
877
892
        """
878
 
        return _run_with_write_locked_target(self, self._transport.put_bytes,
879
 
            '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)
880
899
 
881
900
    def _cache_revision_history(self, rev_history):
882
901
        """Set the cached revision history to rev_history.
909
928
        self._revision_history_cache = None
910
929
        self._revision_id_to_revno_cache = None
911
930
        self._last_revision_info_cache = None
 
931
        self._master_branch_cache = None
912
932
        self._merge_sorted_revisions_cache = None
913
933
        self._partial_revision_history_cache = []
914
934
        self._partial_revision_id_to_revno_cache = {}
 
935
        self._tags_bytes = None
915
936
 
916
937
    def _gen_revision_history(self):
917
938
        """Return sequence of revision hashes on to this branch.
1256
1277
        return result
1257
1278
 
1258
1279
    @needs_read_lock
1259
 
    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):
1260
1282
        """Create a new line of development from the branch, into to_bzrdir.
1261
1283
 
1262
1284
        to_bzrdir controls the branch format.
1267
1289
        if (repository_policy is not None and
1268
1290
            repository_policy.requires_stacking()):
1269
1291
            to_bzrdir._format.require_stacking(_skip_repo=True)
1270
 
        result = to_bzrdir.create_branch()
 
1292
        result = to_bzrdir.create_branch(repository=repository)
1271
1293
        result.lock_write()
1272
1294
        try:
1273
1295
            if repository_policy is not None:
1361
1383
        """Return the most suitable metadir for a checkout of this branch.
1362
1384
        Weaves are used if this branch's repository uses weaves.
1363
1385
        """
1364
 
        if isinstance(self.bzrdir, bzrdir.BzrDirPreSplitOut):
1365
 
            from bzrlib.repofmt import weaverepo
1366
 
            format = bzrdir.BzrDirMetaFormat1()
1367
 
            format.repository_format = weaverepo.RepositoryFormat7()
1368
 
        else:
1369
 
            format = self.repository.bzrdir.checkout_metadir()
1370
 
            format.set_branch_format(self._format)
 
1386
        format = self.repository.bzrdir.checkout_metadir()
 
1387
        format.set_branch_format(self._format)
1371
1388
        return format
1372
1389
 
1373
1390
    def create_clone_on_transport(self, to_transport, revision_id=None,
1374
 
        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):
1375
1393
        """Create a clone of this branch and its bzrdir.
1376
1394
 
1377
1395
        :param to_transport: The transport to clone onto.
1390
1408
            revision_id = self.last_revision()
1391
1409
        dir_to = self.bzrdir.clone_on_transport(to_transport,
1392
1410
            revision_id=revision_id, stacked_on=stacked_on,
1393
 
            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)
1394
1413
        return dir_to.open_branch()
1395
1414
 
1396
1415
    def create_checkout(self, to_location, revision_id=None,
1521
1540
     * an open routine.
1522
1541
 
1523
1542
    Formats are placed in an dict by their format string for reference
1524
 
    during branch opening. Its not required that these be instances, they
 
1543
    during branch opening. It's not required that these be instances, they
1525
1544
    can be classes themselves with class methods - it simply depends on
1526
1545
    whether state is needed for a given format or not.
1527
1546
 
1622
1641
            hook(params)
1623
1642
 
1624
1643
    def _initialize_helper(self, a_bzrdir, utf8_files, name=None,
1625
 
                           lock_type='metadir', set_format=True):
 
1644
                           repository=None, lock_type='metadir',
 
1645
                           set_format=True):
1626
1646
        """Initialize a branch in a bzrdir, with specified files
1627
1647
 
1628
1648
        :param a_bzrdir: The bzrdir to initialize the branch in
1662
1682
        finally:
1663
1683
            if lock_taken:
1664
1684
                control_files.unlock()
1665
 
        branch = self.open(a_bzrdir, name, _found=True)
 
1685
        branch = self.open(a_bzrdir, name, _found=True,
 
1686
                found_repository=repository)
1666
1687
        self._run_post_branch_init_hooks(a_bzrdir, name, branch)
1667
1688
        return branch
1668
1689
 
1669
 
    def initialize(self, a_bzrdir, name=None):
 
1690
    def initialize(self, a_bzrdir, name=None, repository=None):
1670
1691
        """Create a branch of this format in a_bzrdir.
1671
1692
        
1672
1693
        :param name: Name of the colocated branch to create.
1706
1727
        """
1707
1728
        raise NotImplementedError(self.network_name)
1708
1729
 
1709
 
    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):
1710
1732
        """Return the branch object for a_bzrdir
1711
1733
 
1712
1734
        :param a_bzrdir: A BzrDir that contains a branch.
1818
1840
            "with a bzrlib.branch.PullResult object and only runs in the "
1819
1841
            "bzr client.", (0, 15), None))
1820
1842
        self.create_hook(HookPoint('pre_commit',
1821
 
            "Called after a commit is calculated but before it is is "
 
1843
            "Called after a commit is calculated but before it is "
1822
1844
            "completed. pre_commit is called with (local, master, old_revno, "
1823
1845
            "old_revid, future_revno, future_revid, tree_delta, future_tree"
1824
1846
            "). old_revid is NULL_REVISION for the first commit to a branch, "
2006
2028
        """See BranchFormat.get_format_description()."""
2007
2029
        return "Branch format 4"
2008
2030
 
2009
 
    def initialize(self, a_bzrdir, name=None):
 
2031
    def initialize(self, a_bzrdir, name=None, repository=None):
2010
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,))
2011
2036
        utf8_files = [('revision-history', ''),
2012
2037
                      ('branch-name', ''),
2013
2038
                      ]
2022
2047
        """The network name for this format is the control dirs disk label."""
2023
2048
        return self._matchingbzrdir.get_format_string()
2024
2049
 
2025
 
    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):
2026
2052
        """See BranchFormat.open()."""
2027
2053
        if not _found:
2028
2054
            # we are being called directly and must probe.
2029
2055
            raise NotImplementedError
2030
 
        return BzrBranch(_format=self,
 
2056
        if found_repository is None:
 
2057
            found_repository = a_bzrdir.open_repository()
 
2058
        return BzrBranchPreSplitOut(_format=self,
2031
2059
                         _control_files=a_bzrdir._control_files,
2032
2060
                         a_bzrdir=a_bzrdir,
2033
2061
                         name=name,
2034
 
                         _repository=a_bzrdir.open_repository())
 
2062
                         _repository=found_repository)
2035
2063
 
2036
2064
    def __str__(self):
2037
2065
        return "Bazaar-NG branch format 4"
2051
2079
        """
2052
2080
        return self.get_format_string()
2053
2081
 
2054
 
    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):
2055
2084
        """See BranchFormat.open()."""
2056
2085
        if not _found:
2057
2086
            format = BranchFormat.find_format(a_bzrdir, name=name)
2062
2091
        try:
2063
2092
            control_files = lockable_files.LockableFiles(transport, 'lock',
2064
2093
                                                         lockdir.LockDir)
 
2094
            if found_repository is None:
 
2095
                found_repository = a_bzrdir.find_repository()
2065
2096
            return self._branch_class()(_format=self,
2066
2097
                              _control_files=control_files,
2067
2098
                              name=name,
2068
2099
                              a_bzrdir=a_bzrdir,
2069
 
                              _repository=a_bzrdir.find_repository(),
 
2100
                              _repository=found_repository,
2070
2101
                              ignore_fallbacks=ignore_fallbacks)
2071
2102
        except errors.NoSuchFile:
2072
2103
            raise errors.NotBranchError(path=transport.base, bzrdir=a_bzrdir)
2104
2135
        """See BranchFormat.get_format_description()."""
2105
2136
        return "Branch format 5"
2106
2137
 
2107
 
    def initialize(self, a_bzrdir, name=None):
 
2138
    def initialize(self, a_bzrdir, name=None, repository=None):
2108
2139
        """Create a branch of this format in a_bzrdir."""
2109
2140
        utf8_files = [('revision-history', ''),
2110
2141
                      ('branch-name', ''),
2111
2142
                      ]
2112
 
        return self._initialize_helper(a_bzrdir, utf8_files, name)
 
2143
        return self._initialize_helper(a_bzrdir, utf8_files, name, repository)
2113
2144
 
2114
2145
    def supports_tags(self):
2115
2146
        return False
2137
2168
        """See BranchFormat.get_format_description()."""
2138
2169
        return "Branch format 6"
2139
2170
 
2140
 
    def initialize(self, a_bzrdir, name=None):
 
2171
    def initialize(self, a_bzrdir, name=None, repository=None):
2141
2172
        """Create a branch of this format in a_bzrdir."""
2142
2173
        utf8_files = [('last-revision', '0 null:\n'),
2143
2174
                      ('branch.conf', ''),
2144
2175
                      ('tags', ''),
2145
2176
                      ]
2146
 
        return self._initialize_helper(a_bzrdir, utf8_files, name)
 
2177
        return self._initialize_helper(a_bzrdir, utf8_files, name, repository)
2147
2178
 
2148
2179
    def make_tags(self, branch):
2149
2180
        """See bzrlib.branch.BranchFormat.make_tags()."""
2167
2198
        """See BranchFormat.get_format_description()."""
2168
2199
        return "Branch format 8"
2169
2200
 
2170
 
    def initialize(self, a_bzrdir, name=None):
 
2201
    def initialize(self, a_bzrdir, name=None, repository=None):
2171
2202
        """Create a branch of this format in a_bzrdir."""
2172
2203
        utf8_files = [('last-revision', '0 null:\n'),
2173
2204
                      ('branch.conf', ''),
2174
2205
                      ('tags', ''),
2175
2206
                      ('references', '')
2176
2207
                      ]
2177
 
        return self._initialize_helper(a_bzrdir, utf8_files, name)
 
2208
        return self._initialize_helper(a_bzrdir, utf8_files, name, repository)
2178
2209
 
2179
2210
    def __init__(self):
2180
2211
        super(BzrBranchFormat8, self).__init__()
2203
2234
    This format was introduced in bzr 1.6.
2204
2235
    """
2205
2236
 
2206
 
    def initialize(self, a_bzrdir, name=None):
 
2237
    def initialize(self, a_bzrdir, name=None, repository=None):
2207
2238
        """Create a branch of this format in a_bzrdir."""
2208
2239
        utf8_files = [('last-revision', '0 null:\n'),
2209
2240
                      ('branch.conf', ''),
2210
2241
                      ('tags', ''),
2211
2242
                      ]
2212
 
        return self._initialize_helper(a_bzrdir, utf8_files, name)
 
2243
        return self._initialize_helper(a_bzrdir, utf8_files, name, repository)
2213
2244
 
2214
2245
    def _branch_class(self):
2215
2246
        return BzrBranch7
2257
2288
        transport = a_bzrdir.get_branch_transport(None, name=name)
2258
2289
        location = transport.put_bytes('location', to_branch.base)
2259
2290
 
2260
 
    def initialize(self, a_bzrdir, name=None, target_branch=None):
 
2291
    def initialize(self, a_bzrdir, name=None, target_branch=None,
 
2292
            repository=None):
2261
2293
        """Create a branch of this format in a_bzrdir."""
2262
2294
        if target_branch is None:
2263
2295
            # this format does not implement branch itself, thus the implicit
2291
2323
        return clone
2292
2324
 
2293
2325
    def open(self, a_bzrdir, name=None, _found=False, location=None,
2294
 
             possible_transports=None, ignore_fallbacks=False):
 
2326
             possible_transports=None, ignore_fallbacks=False,
 
2327
             found_repository=None):
2295
2328
        """Return the branch that the branch reference in a_bzrdir points at.
2296
2329
 
2297
2330
        :param a_bzrdir: A BzrDir that contains a branch.
2641
2674
            target.update_revisions(self, stop_revision,
2642
2675
                overwrite=overwrite, graph=graph)
2643
2676
        if self._push_should_merge_tags():
2644
 
            result.tag_conflicts = self.tags.merge_to(target.tags,
2645
 
                overwrite)
 
2677
            result.tag_conflicts = self.tags.merge_to(target.tags, overwrite)
2646
2678
        result.new_revno, result.new_revid = target.last_revision_info()
2647
2679
        return result
2648
2680
 
2663
2695
                mode=self.bzrdir._get_file_mode())
2664
2696
 
2665
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
 
2666
2711
class BzrBranch5(BzrBranch):
2667
2712
    """A format 5 branch. This supports new features over plain branches.
2668
2713
 
2680
2725
        """Return the branch we are bound to.
2681
2726
 
2682
2727
        :return: Either a Branch, or None
2683
 
 
2684
 
        This could memoise the branch, but if thats done
2685
 
        it must be revalidated on each new lock.
2686
 
        So for now we just don't memoise it.
2687
 
        # RBC 20060304 review this decision.
2688
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):
2689
2735
        bound_loc = self.get_bound_location()
2690
2736
        if not bound_loc:
2691
2737
            return None
2702
2748
 
2703
2749
        :param location: URL to the target branch
2704
2750
        """
 
2751
        self._master_branch_cache = None
2705
2752
        if location:
2706
2753
            self._transport.put_bytes('bound', location+'\n',
2707
2754
                mode=self.bzrdir._get_file_mode())
2959
3006
 
2960
3007
    def set_bound_location(self, location):
2961
3008
        """See Branch.set_push_location."""
 
3009
        self._master_branch_cache = None
2962
3010
        result = None
2963
3011
        config = self.get_config()
2964
3012
        if location is None:
3102
3150
    :ivar tag_conflicts: A list of tag conflicts, see BasicTags.merge_to
3103
3151
    """
3104
3152
 
 
3153
    @deprecated_method(deprecated_in((2, 3, 0)))
3105
3154
    def __int__(self):
3106
 
        # 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
        """
3107
3159
        return self.new_revno - self.old_revno
3108
3160
 
3109
3161
    def report(self, to_file):
3134
3186
        target, otherwise it will be None.
3135
3187
    """
3136
3188
 
 
3189
    @deprecated_method(deprecated_in((2, 3, 0)))
3137
3190
    def __int__(self):
3138
 
        # 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
        """
3139
3195
        return self.new_revno - self.old_revno
3140
3196
 
3141
3197
    def report(self, to_file):
3308
3364
        """
3309
3365
        raise NotImplementedError(self.push)
3310
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
 
3311
3376
 
3312
3377
class GenericInterBranch(InterBranch):
3313
3378
    """InterBranch implementation that uses public Branch functions."""
3326
3391
        if isinstance(format, remote.RemoteBranchFormat):
3327
3392
            format._ensure_real()
3328
3393
            return format._custom_format
3329
 
        return format                                                                                                  
 
3394
        return format
3330
3395
 
3331
3396
    @needs_write_lock
3332
3397
    def copy_content_into(self, revision_id=None):
3401
3466
        if local and not bound_location:
3402
3467
            raise errors.LocalRequiresBoundBranch()
3403
3468
        master_branch = None
3404
 
        if not local and bound_location and self.source.user_url != bound_location:
 
3469
        source_is_master = (self.source.user_url == bound_location)
 
3470
        if not local and bound_location and not source_is_master:
3405
3471
            # not pulling from master, so we need to update master.
3406
3472
            master_branch = self.target.get_master_branch(possible_transports)
3407
3473
            master_branch.lock_write()
3413
3479
            return self._pull(overwrite,
3414
3480
                stop_revision, _hook_master=master_branch,
3415
3481
                run_hooks=run_hooks,
3416
 
                _override_hook_target=_override_hook_target)
 
3482
                _override_hook_target=_override_hook_target,
 
3483
                merge_tags_to_master=not source_is_master)
3417
3484
        finally:
3418
3485
            if master_branch:
3419
3486
                master_branch.unlock()
3462
3529
                # push into the master from the source branch.
3463
3530
                self.source._basic_push(master_branch, overwrite, stop_revision)
3464
3531
                # and push into the target branch from the source. Note that we
3465
 
                # push from the source branch again, because its considered the
 
3532
                # push from the source branch again, because it's considered the
3466
3533
                # highest bandwidth repository.
3467
3534
                result = self.source._basic_push(self.target, overwrite,
3468
3535
                    stop_revision)
3486
3553
 
3487
3554
    def _pull(self, overwrite=False, stop_revision=None,
3488
3555
             possible_transports=None, _hook_master=None, run_hooks=True,
3489
 
             _override_hook_target=None, local=False):
 
3556
             _override_hook_target=None, local=False,
 
3557
             merge_tags_to_master=True):
3490
3558
        """See Branch.pull.
3491
3559
 
3492
3560
        This function is the core worker, used by GenericInterBranch.pull to
3527
3595
            # so a tags implementation that versions tags can only 
3528
3596
            # pull in the most recent changes. -- JRV20090506
3529
3597
            result.tag_conflicts = self.source.tags.merge_to(self.target.tags,
3530
 
                overwrite)
 
3598
                overwrite, ignore_master=not merge_tags_to_master)
3531
3599
            result.new_revno, result.new_revid = self.target.last_revision_info()
3532
3600
            if _hook_master:
3533
3601
                result.master_branch = _hook_master