1
# Copyright (C) 2005-2011 Canonical Ltd
1
# Copyright (C) 2005-2010 Canonical Ltd
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
94
92
self._revision_id_to_revno_cache = None
95
93
self._partial_revision_id_to_revno_cache = {}
96
94
self._partial_revision_history_cache = []
97
self._tags_bytes = None
98
95
self._last_revision_info_cache = None
99
96
self._merge_sorted_revisions_cache = None
108
105
def _activate_fallback_location(self, url):
109
106
"""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)
117
107
repo = self._get_fallback_repository(url)
118
108
if repo.has_same_location(self.repository):
119
109
raise errors.UnstackableLocationError(self.user_url, url)
250
239
:return: The bytes of the tags file.
251
240
:seealso: Branch._set_tags_bytes.
253
if self._tags_bytes is None:
254
self._tags_bytes = self._transport.get_bytes('tags')
255
return self._tags_bytes
242
return self._transport.get_bytes('tags')
257
244
def _get_nick(self, local=False, possible_transports=None):
258
245
config = self.get_config()
662
649
raise errors.UnsupportedOperation(self.get_reference_info, self)
664
651
@needs_write_lock
665
def fetch(self, from_branch, last_revision=None, pb=None, fetch_spec=None):
652
def fetch(self, from_branch, last_revision=None, pb=None):
666
653
"""Copy revisions from from_branch into this branch.
668
655
:param from_branch: Where to copy from.
669
656
:param last_revision: What revision to stop at (None for at the end
671
658
:param pb: An optional progress bar to use.
672
:param fetch_spec: If specified, a SearchResult or
673
PendingAncestryResult that describes which revisions to copy. This
674
allows copying multiple heads at once. Mutually exclusive with
678
if fetch_spec is not None and last_revision is not None:
679
raise AssertionError(
680
"fetch_spec and last_revision are mutually exclusive.")
681
661
if self.base == from_branch.base:
683
663
if pb is not None:
686
666
% "pb parameter to fetch()")
687
667
from_branch.lock_read()
689
if last_revision is None and fetch_spec is None:
669
if last_revision is None:
690
670
last_revision = from_branch.last_revision()
691
671
last_revision = _mod_revision.ensure_null(last_revision)
692
672
return self.repository.fetch(from_branch.repository,
693
673
revision_id=last_revision,
694
pb=pb, fetch_spec=fetch_spec)
696
676
from_branch.unlock()
825
805
old_repository = self.repository
826
806
if len(old_repository._fallback_repositories) != 1:
827
807
raise AssertionError("can't cope with fallback repositories "
828
"of %r (fallbacks: %r)" % (old_repository,
829
old_repository._fallback_repositories))
808
"of %r" % (self.repository,))
830
809
# Open the new repository object.
831
810
# Repositories don't offer an interface to remove fallback
832
811
# repositories today; take the conceptually simpler option and just
880
859
# XXX: If you unstack a branch while it has a working tree
881
860
# with a pending merge, the pending-merged revisions will no
882
861
# longer be present. You can (probably) revert and remerge.
884
tags_to_fetch = set(self.tags.get_reverse_tag_dict())
885
except errors.TagsNotSupported:
886
tags_to_fetch = set()
887
fetch_spec = _mod_graph.NotInOtherForRevs(self.repository,
888
old_repository, required_ids=[self.last_revision()],
889
if_present_ids=tags_to_fetch, find_ghosts=True).execute()
890
self.repository.fetch(old_repository, fetch_spec=fetch_spec)
863
# XXX: This only fetches up to the tip of the repository; it
864
# doesn't bring across any tags. That's fairly consistent
865
# with how branch works, but perhaps not ideal.
866
self.repository.fetch(old_repository,
867
revision_id=self.last_revision(),
892
870
old_repository.unlock()
899
877
:seealso: Branch._get_tags_bytes.
901
return _run_with_write_locked_target(self, self._set_tags_bytes_locked,
904
def _set_tags_bytes_locked(self, bytes):
905
self._tags_bytes = bytes
906
return self._transport.put_bytes('tags', bytes)
879
return _run_with_write_locked_target(self, self._transport.put_bytes,
908
882
def _cache_revision_history(self, rev_history):
909
883
"""Set the cached revision history to rev_history.
939
913
self._merge_sorted_revisions_cache = None
940
914
self._partial_revision_history_cache = []
941
915
self._partial_revision_id_to_revno_cache = {}
942
self._tags_bytes = None
944
917
def _gen_revision_history(self):
945
918
"""Return sequence of revision hashes on to this branch.
1030
1003
return other_history[self_len:stop_revision]
1032
1005
def update_revisions(self, other, stop_revision=None, overwrite=False,
1033
graph=None, fetch_tags=True):
1034
1007
"""Pull in new perfect-fit revisions.
1036
1009
:param other: Another Branch to pull from
1039
1012
to see if it is a proper descendant.
1040
1013
:param graph: A Graph object that can be used to query history
1041
1014
information. This can be None.
1042
:param fetch_tags: Flag that specifies if tags from other should be
1046
1017
return InterBranch.get(other, self).update_revisions(stop_revision,
1047
overwrite, graph, fetch_tags=fetch_tags)
1049
@deprecated_method(deprecated_in((2, 4, 0)))
1050
1020
def import_last_revision_info(self, source_repo, revno, revid):
1051
1021
"""Set the last revision info, importing from another repo if necessary.
1023
This is used by the bound branch code to upload a revision to
1024
the master branch first before updating the tip of the local branch.
1053
1026
:param source_repo: Source repository to optionally fetch from
1054
1027
:param revno: Revision number of the new tip
1055
1028
:param revid: Revision id of the new tip
1058
1031
self.repository.fetch(source_repo, revision_id=revid)
1059
1032
self.set_last_revision_info(revno, revid)
1061
def import_last_revision_info_and_tags(self, source, revno, revid):
1062
"""Set the last revision info, importing from another repo if necessary.
1064
This is used by the bound branch code to upload a revision to
1065
the master branch first before updating the tip of the local branch.
1066
Revisions referenced by source's tags are also transferred.
1068
:param source: Source branch to optionally fetch from
1069
:param revno: Revision number of the new tip
1070
:param revid: Revision id of the new tip
1072
if not self.repository.has_same_location(source.repository):
1074
tags_to_fetch = set(source.tags.get_reverse_tag_dict())
1075
except errors.TagsNotSupported:
1076
tags_to_fetch = set()
1077
fetch_spec = _mod_graph.NotInOtherForRevs(self.repository,
1078
source.repository, [revid],
1079
if_present_ids=tags_to_fetch).execute()
1080
self.repository.fetch(source.repository, fetch_spec=fetch_spec)
1081
self.set_last_revision_info(revno, revid)
1083
1034
def revision_id_to_revno(self, revision_id):
1084
1035
"""Given a revision id, return its revno"""
1085
1036
if _mod_revision.is_null(revision_id):
1308
1259
@needs_read_lock
1309
def sprout(self, to_bzrdir, revision_id=None, repository_policy=None,
1260
def sprout(self, to_bzrdir, revision_id=None, repository_policy=None):
1311
1261
"""Create a new line of development from the branch, into to_bzrdir.
1313
1263
to_bzrdir controls the branch format.
1318
1268
if (repository_policy is not None and
1319
1269
repository_policy.requires_stacking()):
1320
1270
to_bzrdir._format.require_stacking(_skip_repo=True)
1321
result = to_bzrdir.create_branch(repository=repository)
1271
result = to_bzrdir.create_branch()
1322
1272
result.lock_write()
1324
1274
if repository_policy is not None:
1412
1362
"""Return the most suitable metadir for a checkout of this branch.
1413
1363
Weaves are used if this branch's repository uses weaves.
1415
format = self.repository.bzrdir.checkout_metadir()
1416
format.set_branch_format(self._format)
1365
if isinstance(self.bzrdir, bzrdir.BzrDirPreSplitOut):
1366
from bzrlib.repofmt import weaverepo
1367
format = bzrdir.BzrDirMetaFormat1()
1368
format.repository_format = weaverepo.RepositoryFormat7()
1370
format = self.repository.bzrdir.checkout_metadir()
1371
format.set_branch_format(self._format)
1419
1374
def create_clone_on_transport(self, to_transport, revision_id=None,
1627
1579
if isinstance(fmt, MetaDirBranchFormatFactory):
1629
1581
result.append(fmt)
1630
return result + klass._extra_formats
1632
1584
def get_reference(self, a_bzrdir, name=None):
1633
1585
"""Get the target reference of the branch in a_bzrdir.
1675
1627
def _initialize_helper(self, a_bzrdir, utf8_files, name=None,
1676
repository=None, lock_type='metadir',
1628
lock_type='metadir', set_format=True):
1678
1629
"""Initialize a branch in a bzrdir, with specified files
1680
1631
:param a_bzrdir: The bzrdir to initialize the branch in
1716
1667
control_files.unlock()
1717
branch = self.open(a_bzrdir, name, _found=True,
1718
found_repository=repository)
1668
branch = self.open(a_bzrdir, name, _found=True)
1719
1669
self._run_post_branch_init_hooks(a_bzrdir, name, branch)
1722
def initialize(self, a_bzrdir, name=None, repository=None):
1672
def initialize(self, a_bzrdir, name=None):
1723
1673
"""Create a branch of this format in a_bzrdir.
1725
1675
:param name: Name of the colocated branch to create.
1760
1710
raise NotImplementedError(self.network_name)
1762
def open(self, a_bzrdir, name=None, _found=False, ignore_fallbacks=False,
1763
found_repository=None):
1712
def open(self, a_bzrdir, name=None, _found=False, ignore_fallbacks=False):
1764
1713
"""Return the branch object for a_bzrdir
1766
1715
:param a_bzrdir: A BzrDir that contains a branch.
1773
1722
raise NotImplementedError(self.open)
1776
def register_extra_format(klass, format):
1777
"""Register a branch format that can not be part of a metadir.
1779
This is mainly useful to allow custom branch formats, such as
1780
older Bazaar formats and foreign formats, to be tested
1782
klass._extra_formats.append(format)
1783
network_format_registry.register(
1784
format.network_name(), format.__class__)
1787
1725
def register_format(klass, format):
1788
1726
"""Register a metadir format.
1815
1753
def unregister_format(klass, format):
1816
1754
del klass._formats[format.get_format_string()]
1819
def unregister_extra_format(klass, format):
1820
klass._extra_formats.remove(format)
1822
1756
def __str__(self):
1823
1757
return self.get_format_description().rstrip()
2075
2009
"""See BranchFormat.get_format_description()."""
2076
2010
return "Branch format 4"
2078
def initialize(self, a_bzrdir, name=None, repository=None):
2012
def initialize(self, a_bzrdir, name=None):
2079
2013
"""Create a branch of this format in a_bzrdir."""
2080
if repository is not None:
2081
raise NotImplementedError(
2082
"initialize(repository=<not None>) on %r" % (self,))
2083
2014
utf8_files = [('revision-history', ''),
2084
2015
('branch-name', ''),
2094
2025
"""The network name for this format is the control dirs disk label."""
2095
2026
return self._matchingbzrdir.get_format_string()
2097
def open(self, a_bzrdir, name=None, _found=False, ignore_fallbacks=False,
2098
found_repository=None):
2028
def open(self, a_bzrdir, name=None, _found=False, ignore_fallbacks=False):
2099
2029
"""See BranchFormat.open()."""
2101
2031
# we are being called directly and must probe.
2102
2032
raise NotImplementedError
2103
if found_repository is None:
2104
found_repository = a_bzrdir.open_repository()
2105
return BzrBranchPreSplitOut(_format=self,
2033
return BzrBranch(_format=self,
2106
2034
_control_files=a_bzrdir._control_files,
2107
2035
a_bzrdir=a_bzrdir,
2109
_repository=found_repository)
2037
_repository=a_bzrdir.open_repository())
2111
2039
def __str__(self):
2112
2040
return "Bazaar-NG branch format 4"
2127
2055
return self.get_format_string()
2129
def open(self, a_bzrdir, name=None, _found=False, ignore_fallbacks=False,
2130
found_repository=None):
2057
def open(self, a_bzrdir, name=None, _found=False, ignore_fallbacks=False):
2131
2058
"""See BranchFormat.open()."""
2133
2060
format = BranchFormat.find_format(a_bzrdir, name=name)
2139
2066
control_files = lockable_files.LockableFiles(transport, 'lock',
2140
2067
lockdir.LockDir)
2141
if found_repository is None:
2142
found_repository = a_bzrdir.find_repository()
2143
2068
return self._branch_class()(_format=self,
2144
2069
_control_files=control_files,
2146
2071
a_bzrdir=a_bzrdir,
2147
_repository=found_repository,
2072
_repository=a_bzrdir.find_repository(),
2148
2073
ignore_fallbacks=ignore_fallbacks)
2149
2074
except errors.NoSuchFile:
2150
2075
raise errors.NotBranchError(path=transport.base, bzrdir=a_bzrdir)
2182
2107
"""See BranchFormat.get_format_description()."""
2183
2108
return "Branch format 5"
2185
def initialize(self, a_bzrdir, name=None, repository=None):
2110
def initialize(self, a_bzrdir, name=None):
2186
2111
"""Create a branch of this format in a_bzrdir."""
2187
2112
utf8_files = [('revision-history', ''),
2188
2113
('branch-name', ''),
2190
return self._initialize_helper(a_bzrdir, utf8_files, name, repository)
2115
return self._initialize_helper(a_bzrdir, utf8_files, name)
2192
2117
def supports_tags(self):
2215
2140
"""See BranchFormat.get_format_description()."""
2216
2141
return "Branch format 6"
2218
def initialize(self, a_bzrdir, name=None, repository=None):
2143
def initialize(self, a_bzrdir, name=None):
2219
2144
"""Create a branch of this format in a_bzrdir."""
2220
2145
utf8_files = [('last-revision', '0 null:\n'),
2221
2146
('branch.conf', ''),
2224
return self._initialize_helper(a_bzrdir, utf8_files, name, repository)
2149
return self._initialize_helper(a_bzrdir, utf8_files, name)
2226
2151
def make_tags(self, branch):
2227
2152
"""See bzrlib.branch.BranchFormat.make_tags()."""
2245
2170
"""See BranchFormat.get_format_description()."""
2246
2171
return "Branch format 8"
2248
def initialize(self, a_bzrdir, name=None, repository=None):
2173
def initialize(self, a_bzrdir, name=None):
2249
2174
"""Create a branch of this format in a_bzrdir."""
2250
2175
utf8_files = [('last-revision', '0 null:\n'),
2251
2176
('branch.conf', ''),
2253
2178
('references', '')
2255
return self._initialize_helper(a_bzrdir, utf8_files, name, repository)
2180
return self._initialize_helper(a_bzrdir, utf8_files, name)
2257
2182
def __init__(self):
2258
2183
super(BzrBranchFormat8, self).__init__()
2281
2206
This format was introduced in bzr 1.6.
2284
def initialize(self, a_bzrdir, name=None, repository=None):
2209
def initialize(self, a_bzrdir, name=None):
2285
2210
"""Create a branch of this format in a_bzrdir."""
2286
2211
utf8_files = [('last-revision', '0 null:\n'),
2287
2212
('branch.conf', ''),
2290
return self._initialize_helper(a_bzrdir, utf8_files, name, repository)
2215
return self._initialize_helper(a_bzrdir, utf8_files, name)
2292
2217
def _branch_class(self):
2293
2218
return BzrBranch7
2335
2260
transport = a_bzrdir.get_branch_transport(None, name=name)
2336
2261
location = transport.put_bytes('location', to_branch.base)
2338
def initialize(self, a_bzrdir, name=None, target_branch=None,
2263
def initialize(self, a_bzrdir, name=None, target_branch=None):
2340
2264
"""Create a branch of this format in a_bzrdir."""
2341
2265
if target_branch is None:
2342
2266
# this format does not implement branch itself, thus the implicit
2372
2296
def open(self, a_bzrdir, name=None, _found=False, location=None,
2373
possible_transports=None, ignore_fallbacks=False,
2374
found_repository=None):
2297
possible_transports=None, ignore_fallbacks=False):
2375
2298
"""Return the branch that the branch reference in a_bzrdir points at.
2377
2300
:param a_bzrdir: A BzrDir that contains a branch.
2429
2352
BranchFormat.register_format(__format7)
2430
2353
BranchFormat.register_format(__format8)
2431
2354
BranchFormat.set_default_format(__format7)
2432
BranchFormat.register_extra_format(BzrBranchFormat4())
2355
_legacy_formats = [BzrBranchFormat4(),
2357
network_format_registry.register(
2358
_legacy_formats[0].network_name(), _legacy_formats[0].__class__)
2435
2361
class BranchWriteLockResult(LogicalLockResult):
2711
2637
result.target_branch = target
2712
2638
result.old_revno, result.old_revid = target.last_revision_info()
2713
2639
self.update_references(target)
2714
if result.old_revid != stop_revision:
2640
if result.old_revid != self.last_revision():
2715
2641
# We assume that during 'push' this repository is closer than
2717
2643
graph = self.repository.get_graph(target.repository)
2740
2666
mode=self.bzrdir._get_file_mode())
2743
class BzrBranchPreSplitOut(BzrBranch):
2745
def _get_checkout_format(self):
2746
"""Return the most suitable metadir for a checkout of this branch.
2747
Weaves are used if this branch's repository uses weaves.
2749
from bzrlib.repofmt.weaverepo import RepositoryFormat7
2750
from bzrlib.bzrdir import BzrDirMetaFormat1
2751
format = BzrDirMetaFormat1()
2752
format.repository_format = RepositoryFormat7()
2756
2669
class BzrBranch5(BzrBranch):
2757
2670
"""A format 5 branch. This supports new features over plain branches.
3386
3299
@needs_write_lock
3387
3300
def update_revisions(self, stop_revision=None, overwrite=False,
3388
graph=None, fetch_tags=True):
3389
3302
"""Pull in new perfect-fit revisions.
3391
3304
:param stop_revision: Updated until the given revision
3393
3306
to see if it is a proper descendant.
3394
3307
:param graph: A Graph object that can be used to query history
3395
3308
information. This can be None.
3396
:param fetch_tags: Flag that specifies if tags from source should be
3400
3311
raise NotImplementedError(self.update_revisions)
3459
3370
@needs_write_lock
3460
3371
def update_revisions(self, stop_revision=None, overwrite=False,
3461
graph=None, fetch_tags=True):
3462
3373
"""See InterBranch.update_revisions()."""
3463
3374
other_revno, other_last_revision = self.source.last_revision_info()
3464
3375
stop_revno = None # unknown
3476
3387
# case of having something to pull, and so that the check for
3477
3388
# already merged can operate on the just fetched graph, which will
3478
3389
# be cached in memory.
3480
fetch_spec_factory = fetch.FetchSpecFactory()
3481
fetch_spec_factory.source_branch = self.source
3482
fetch_spec_factory.source_branch_stop_revision_id = stop_revision
3483
fetch_spec_factory.source_repo = self.source.repository
3484
fetch_spec_factory.target_repo = self.target.repository
3485
fetch_spec_factory.target_repo_kind = fetch.TargetRepoKinds.PREEXISTING
3486
fetch_spec = fetch_spec_factory.make_fetch_spec()
3488
fetch_spec = _mod_graph.NotInOtherForRevs(self.target.repository,
3489
self.source.repository, revision_ids=[stop_revision]).execute()
3490
self.target.fetch(self.source, fetch_spec=fetch_spec)
3390
self.target.fetch(self.source, stop_revision)
3491
3391
# Check to see if one is an ancestor of the other
3492
3392
if not overwrite:
3493
3393
if graph is None:
3521
3421
if local and not bound_location:
3522
3422
raise errors.LocalRequiresBoundBranch()
3523
3423
master_branch = None
3524
source_is_master = (self.source.user_url == bound_location)
3525
if not local and bound_location and not source_is_master:
3424
if not local and bound_location and self.source.user_url != bound_location:
3526
3425
# not pulling from master, so we need to update master.
3527
3426
master_branch = self.target.get_master_branch(possible_transports)
3528
3427
master_branch.lock_write()
3534
3433
return self._pull(overwrite,
3535
3434
stop_revision, _hook_master=master_branch,
3536
3435
run_hooks=run_hooks,
3537
_override_hook_target=_override_hook_target,
3538
merge_tags_to_master=not source_is_master)
3436
_override_hook_target=_override_hook_target)
3540
3438
if master_branch:
3541
3439
master_branch.unlock()
3609
3507
def _pull(self, overwrite=False, stop_revision=None,
3610
3508
possible_transports=None, _hook_master=None, run_hooks=True,
3611
_override_hook_target=None, local=False,
3612
merge_tags_to_master=True):
3509
_override_hook_target=None, local=False):
3613
3510
"""See Branch.pull.
3615
3512
This function is the core worker, used by GenericInterBranch.pull to
3650
3547
# so a tags implementation that versions tags can only
3651
3548
# pull in the most recent changes. -- JRV20090506
3652
3549
result.tag_conflicts = self.source.tags.merge_to(self.target.tags,
3653
overwrite, ignore_master=not merge_tags_to_master)
3654
3551
result.new_revno, result.new_revid = self.target.last_revision_info()
3655
3552
if _hook_master:
3656
3553
result.master_branch = _hook_master