809
845
raise errors.NoSuchRevision(self, revno)
810
846
return history[revno - 1]
812
849
def pull(self, source, overwrite=False, stop_revision=None,
813
possible_transports=None, _override_hook_target=None):
850
possible_transports=None, *args, **kwargs):
814
851
"""Mirror source into this branch.
816
853
This branch is considered to be 'local', having low latency.
818
855
:returns: PullResult instance
820
raise NotImplementedError(self.pull)
857
return InterBranch.get(source, self).pull(overwrite=overwrite,
858
stop_revision=stop_revision,
859
possible_transports=possible_transports, *args, **kwargs)
822
def push(self, target, overwrite=False, stop_revision=None):
861
def push(self, target, overwrite=False, stop_revision=None, *args,
823
863
"""Mirror this branch into target.
825
865
This branch is considered to be 'local', having low latency.
827
raise NotImplementedError(self.push)
867
return InterBranch.get(self, target).push(overwrite, stop_revision,
870
def lossy_push(self, target, stop_revision=None):
871
"""Push deltas into another branch.
873
:note: This does not, like push, retain the revision ids from
874
the source branch and will, rather than adding bzr-specific
875
metadata, push only those semantics of the revision that can be
876
natively represented by this branch' VCS.
878
:param target: Target branch
879
:param stop_revision: Revision to push, defaults to last revision.
880
:return: BranchPushResult with an extra member revidmap:
881
A dictionary mapping revision ids from the target branch
882
to new revision ids in the target branch, for each
883
revision that was pushed.
885
inter = InterBranch.get(self, target)
886
lossy_push = getattr(inter, "lossy_push", None)
887
if lossy_push is None:
888
raise errors.LossyPushToSameVCS(self, target)
889
return lossy_push(stop_revision)
829
891
def basis_tree(self):
830
892
"""Return `Tree` object for last revision."""
1116
1205
def create_clone_on_transport(self, to_transport, revision_id=None,
1206
stacked_on=None, create_prefix=False, use_existing_dir=False):
1118
1207
"""Create a clone of this branch and its bzrdir.
1120
1209
:param to_transport: The transport to clone onto.
1121
1210
:param revision_id: The revision id to use as tip in the new branch.
1122
1211
If None the tip is obtained from this branch.
1123
1212
:param stacked_on: An optional URL to stack the clone on.
1213
:param create_prefix: Create any missing directories leading up to
1215
:param use_existing_dir: Use an existing directory if one exists.
1125
1217
# XXX: Fix the bzrdir API to allow getting the branch back from the
1126
1218
# clone call. Or something. 20090224 RBC/spiv.
1127
dir_to = self.bzrdir.clone_on_transport(to_transport,
1128
revision_id=revision_id, stacked_on=stacked_on)
1219
if revision_id is None:
1220
revision_id = self.last_revision()
1222
dir_to = self.bzrdir.clone_on_transport(to_transport,
1223
revision_id=revision_id, stacked_on=stacked_on,
1224
create_prefix=create_prefix, use_existing_dir=use_existing_dir)
1225
except errors.FileExists:
1226
if not use_existing_dir:
1228
except errors.NoSuchFile:
1229
if not create_prefix:
1129
1231
return dir_to.open_branch()
1131
1233
def create_checkout(self, to_location, revision_id=None,
1699
class BzrBranchFormat7(BranchFormatMetadir):
1810
class BzrBranchFormat8(BranchFormatMetadir):
1811
"""Metadir format supporting storing locations of subtree branches."""
1813
def _branch_class(self):
1816
def get_format_string(self):
1817
"""See BranchFormat.get_format_string()."""
1818
return "Bazaar Branch Format 8 (needs bzr 1.15)\n"
1820
def get_format_description(self):
1821
"""See BranchFormat.get_format_description()."""
1822
return "Branch format 8"
1824
def initialize(self, a_bzrdir):
1825
"""Create a branch of this format in a_bzrdir."""
1826
utf8_files = [('last-revision', '0 null:\n'),
1827
('branch.conf', ''),
1831
return self._initialize_helper(a_bzrdir, utf8_files)
1834
super(BzrBranchFormat8, self).__init__()
1835
self._matchingbzrdir.repository_format = \
1836
RepositoryFormatKnitPack5RichRoot()
1838
def make_tags(self, branch):
1839
"""See bzrlib.branch.BranchFormat.make_tags()."""
1840
return BasicTags(branch)
1842
def supports_stacking(self):
1845
supports_reference_locations = True
1848
class BzrBranchFormat7(BzrBranchFormat8):
1700
1849
"""Branch format with last-revision, tags, and a stacked location pointer.
1702
1851
The stacked location pointer is passed down to the repository and requires
1910
2051
return self.control_files.is_locked()
1912
2053
def lock_write(self, token=None):
1913
repo_token = self.repository.lock_write()
2054
# All-in-one needs to always unlock/lock.
2055
repo_control = getattr(self.repository, 'control_files', None)
2056
if self.control_files == repo_control or not self.is_locked():
2057
self.repository.lock_write()
1915
token = self.control_files.lock_write(token=token)
2062
return self.control_files.lock_write(token=token)
1917
self.repository.unlock()
2065
self.repository.unlock()
1921
2068
def lock_read(self):
1922
self.repository.lock_read()
2069
# All-in-one needs to always unlock/lock.
2070
repo_control = getattr(self.repository, 'control_files', None)
2071
if self.control_files == repo_control or not self.is_locked():
2072
self.repository.lock_read()
1924
2077
self.control_files.lock_read()
1926
self.repository.unlock()
2080
self.repository.unlock()
1929
2083
def unlock(self):
1930
# TODO: test for failed two phase locks. This is known broken.
1932
2085
self.control_files.unlock()
1934
self.repository.unlock()
1935
if not self.control_files.is_locked():
1936
# we just released the lock
1937
self._clear_cached_state()
2087
# All-in-one needs to always unlock/lock.
2088
repo_control = getattr(self.repository, 'control_files', None)
2089
if (self.control_files == repo_control or
2090
not self.control_files.is_locked()):
2091
self.repository.unlock()
2092
if not self.control_files.is_locked():
2093
# we just released the lock
2094
self._clear_cached_state()
1939
2096
def peek_lock_mode(self):
1940
2097
if self.control_files._lock_count == 0:
2059
2216
"""See Branch.basis_tree."""
2060
2217
return self.repository.revision_tree(self.last_revision())
2063
def pull(self, source, overwrite=False, stop_revision=None,
2064
_hook_master=None, run_hooks=True, possible_transports=None,
2065
_override_hook_target=None):
2068
:param _hook_master: Private parameter - set the branch to
2069
be supplied as the master to pull hooks.
2070
:param run_hooks: Private parameter - if false, this branch
2071
is being called because it's the master of the primary branch,
2072
so it should not run its hooks.
2073
:param _override_hook_target: Private parameter - set the branch to be
2074
supplied as the target_branch to pull hooks.
2076
result = PullResult()
2077
result.source_branch = source
2078
if _override_hook_target is None:
2079
result.target_branch = self
2081
result.target_branch = _override_hook_target
2084
# We assume that during 'pull' the local repository is closer than
2086
graph = self.repository.get_graph(source.repository)
2087
result.old_revno, result.old_revid = self.last_revision_info()
2088
self.update_revisions(source, stop_revision, overwrite=overwrite,
2090
result.tag_conflicts = source.tags.merge_to(self.tags, overwrite)
2091
result.new_revno, result.new_revid = self.last_revision_info()
2093
result.master_branch = _hook_master
2094
result.local_branch = result.target_branch
2096
result.master_branch = result.target_branch
2097
result.local_branch = None
2099
for hook in Branch.hooks['post_pull']:
2105
2219
def _get_parent_location(self):
2106
2220
_locs = ['parent', 'pull', 'x-pull']
2107
2221
for l in _locs:
2115
def push(self, target, overwrite=False, stop_revision=None,
2116
_override_hook_source_branch=None):
2119
This is the basic concrete implementation of push()
2121
:param _override_hook_source_branch: If specified, run
2122
the hooks passing this Branch as the source, rather than self.
2123
This is for use of RemoteBranch, where push is delegated to the
2124
underlying vfs-based Branch.
2126
# TODO: Public option to disable running hooks - should be trivial but
2128
return _run_with_write_locked_target(
2129
target, self._push_with_bound_branches, target, overwrite,
2131
_override_hook_source_branch=_override_hook_source_branch)
2133
def _push_with_bound_branches(self, target, overwrite,
2135
_override_hook_source_branch=None):
2136
"""Push from self into target, and into target's master if any.
2138
This is on the base BzrBranch class even though it doesn't support
2139
bound branches because the *target* might be bound.
2142
if _override_hook_source_branch:
2143
result.source_branch = _override_hook_source_branch
2144
for hook in Branch.hooks['post_push']:
2147
bound_location = target.get_bound_location()
2148
if bound_location and target.base != bound_location:
2149
# there is a master branch.
2151
# XXX: Why the second check? Is it even supported for a branch to
2152
# be bound to itself? -- mbp 20070507
2153
master_branch = target.get_master_branch()
2154
master_branch.lock_write()
2156
# push into the master from this branch.
2157
self._basic_push(master_branch, overwrite, stop_revision)
2158
# and push into the target branch from this. Note that we push from
2159
# this branch again, because its considered the highest bandwidth
2161
result = self._basic_push(target, overwrite, stop_revision)
2162
result.master_branch = master_branch
2163
result.local_branch = target
2167
master_branch.unlock()
2170
result = self._basic_push(target, overwrite, stop_revision)
2171
# TODO: Why set master_branch and local_branch if there's no
2172
# binding? Maybe cleaner to just leave them unset? -- mbp
2174
result.master_branch = target
2175
result.local_branch = None
2179
2228
def _basic_push(self, target, overwrite, stop_revision):
2180
2229
"""Basic implementation of push without bound branches or hooks.
2182
Must be called with self read locked and target write locked.
2231
Must be called with source read locked and target write locked.
2184
2233
result = BranchPushResult()
2185
2234
result.source_branch = self
2186
2235
result.target_branch = target
2187
2236
result.old_revno, result.old_revid = target.last_revision_info()
2237
self.update_references(target)
2188
2238
if result.old_revid != self.last_revision():
2189
2239
# We assume that during 'push' this repository is closer than
2191
2241
graph = self.repository.get_graph(target.repository)
2192
target.update_revisions(self, stop_revision, overwrite=overwrite,
2242
target.update_revisions(self, stop_revision,
2243
overwrite=overwrite, graph=graph)
2194
2244
if self._push_should_merge_tags():
2195
result.tag_conflicts = self.tags.merge_to(target.tags, overwrite)
2245
result.tag_conflicts = self.tags.merge_to(target.tags,
2196
2247
result.new_revno, result.new_revid = target.last_revision_info()
2237
2270
It has support for a master_branch which is the data for bound branches.
2241
def pull(self, source, overwrite=False, stop_revision=None,
2242
run_hooks=True, possible_transports=None,
2243
_override_hook_target=None):
2244
"""Pull from source into self, updating my master if any.
2246
:param run_hooks: Private parameter - if false, this branch
2247
is being called because it's the master of the primary branch,
2248
so it should not run its hooks.
2250
bound_location = self.get_bound_location()
2251
master_branch = None
2252
if bound_location and source.base != bound_location:
2253
# not pulling from master, so we need to update master.
2254
master_branch = self.get_master_branch(possible_transports)
2255
master_branch.lock_write()
2258
# pull from source into master.
2259
master_branch.pull(source, overwrite, stop_revision,
2261
return super(BzrBranch5, self).pull(source, overwrite,
2262
stop_revision, _hook_master=master_branch,
2263
run_hooks=run_hooks,
2264
_override_hook_target=_override_hook_target)
2267
master_branch.unlock()
2269
2273
def get_bound_location(self):
2271
2275
return self._transport.get_bytes('bound')[:-1]
2377
2381
raise AssertionError(
2378
2382
"'transform_fallback_location' hook %s returned "
2379
2383
"None, not a URL." % hook_name)
2380
self._activate_fallback_location(url)
2384
self._activate_fallback_location(url, None)
2382
2386
def __init__(self, *args, **kwargs):
2383
2387
self._ignore_fallbacks = kwargs.get('ignore_fallbacks', False)
2384
super(BzrBranch7, self).__init__(*args, **kwargs)
2388
super(BzrBranch8, self).__init__(*args, **kwargs)
2385
2389
self._last_revision_info_cache = None
2386
2390
self._partial_revision_history_cache = []
2391
self._reference_info = None
2388
2393
def _clear_cached_state(self):
2389
super(BzrBranch7, self)._clear_cached_state()
2394
super(BzrBranch8, self)._clear_cached_state()
2390
2395
self._last_revision_info_cache = None
2391
2396
self._partial_revision_history_cache = []
2397
self._reference_info = None
2393
2399
def _last_revision_info(self):
2394
2400
revision_string = self._transport.get_bytes('last-revision')
2504
2510
"""Set the parent branch"""
2505
2511
return self._get_config_location('parent_location')
2514
def _set_all_reference_info(self, info_dict):
2515
"""Replace all reference info stored in a branch.
2517
:param info_dict: A dict of {file_id: (tree_path, branch_location)}
2520
writer = rio.RioWriter(s)
2521
for key, (tree_path, branch_location) in info_dict.iteritems():
2522
stanza = rio.Stanza(file_id=key, tree_path=tree_path,
2523
branch_location=branch_location)
2524
writer.write_stanza(stanza)
2525
self._transport.put_bytes('references', s.getvalue())
2526
self._reference_info = info_dict
2529
def _get_all_reference_info(self):
2530
"""Return all the reference info stored in a branch.
2532
:return: A dict of {file_id: (tree_path, branch_location)}
2534
if self._reference_info is not None:
2535
return self._reference_info
2536
rio_file = self._transport.get('references')
2538
stanzas = rio.read_stanzas(rio_file)
2539
info_dict = dict((s['file_id'], (s['tree_path'],
2540
s['branch_location'])) for s in stanzas)
2543
self._reference_info = info_dict
2546
def set_reference_info(self, file_id, tree_path, branch_location):
2547
"""Set the branch location to use for a tree reference.
2549
:param file_id: The file-id of the tree reference.
2550
:param tree_path: The path of the tree reference in the tree.
2551
:param branch_location: The location of the branch to retrieve tree
2554
info_dict = self._get_all_reference_info()
2555
info_dict[file_id] = (tree_path, branch_location)
2556
if None in (tree_path, branch_location):
2557
if tree_path is not None:
2558
raise ValueError('tree_path must be None when branch_location'
2560
if branch_location is not None:
2561
raise ValueError('branch_location must be None when tree_path'
2563
del info_dict[file_id]
2564
self._set_all_reference_info(info_dict)
2566
def get_reference_info(self, file_id):
2567
"""Get the tree_path and branch_location for a tree reference.
2569
:return: a tuple of (tree_path, branch_location)
2571
return self._get_all_reference_info().get(file_id, (None, None))
2573
def reference_parent(self, file_id, path, possible_transports=None):
2574
"""Return the parent branch for a tree-reference file_id.
2576
:param file_id: The file_id of the tree reference
2577
:param path: The path of the file_id in the tree
2578
:return: A branch associated with the file_id
2580
branch_location = self.get_reference_info(file_id)[1]
2581
if branch_location is None:
2582
return Branch.reference_parent(self, file_id, path,
2583
possible_transports)
2584
branch_location = urlutils.join(self.base, branch_location)
2585
return Branch.open(branch_location,
2586
possible_transports=possible_transports)
2507
2588
def set_push_location(self, location):
2508
2589
"""See Branch.set_push_location."""
2509
2590
self._set_config_location('push_location', location)
2872
2994
self.source.unlock()
2996
def pull(self, overwrite=False, stop_revision=None,
2997
possible_transports=None, _hook_master=None, run_hooks=True,
2998
_override_hook_target=None, local=False):
3001
:param _hook_master: Private parameter - set the branch to
3002
be supplied as the master to pull hooks.
3003
:param run_hooks: Private parameter - if false, this branch
3004
is being called because it's the master of the primary branch,
3005
so it should not run its hooks.
3006
:param _override_hook_target: Private parameter - set the branch to be
3007
supplied as the target_branch to pull hooks.
3008
:param local: Only update the local branch, and not the bound branch.
3010
# This type of branch can't be bound.
3012
raise errors.LocalRequiresBoundBranch()
3013
result = PullResult()
3014
result.source_branch = self.source
3015
if _override_hook_target is None:
3016
result.target_branch = self.target
3018
result.target_branch = _override_hook_target
3019
self.source.lock_read()
3021
# We assume that during 'pull' the target repository is closer than
3023
self.source.update_references(self.target)
3024
graph = self.target.repository.get_graph(self.source.repository)
3025
# TODO: Branch formats should have a flag that indicates
3026
# that revno's are expensive, and pull() should honor that flag.
3028
result.old_revno, result.old_revid = \
3029
self.target.last_revision_info()
3030
self.target.update_revisions(self.source, stop_revision,
3031
overwrite=overwrite, graph=graph)
3032
# TODO: The old revid should be specified when merging tags,
3033
# so a tags implementation that versions tags can only
3034
# pull in the most recent changes. -- JRV20090506
3035
result.tag_conflicts = self.source.tags.merge_to(self.target.tags,
3037
result.new_revno, result.new_revid = self.target.last_revision_info()
3039
result.master_branch = _hook_master
3040
result.local_branch = result.target_branch
3042
result.master_branch = result.target_branch
3043
result.local_branch = None
3045
for hook in Branch.hooks['post_pull']:
3048
self.source.unlock()
3051
def push(self, overwrite=False, stop_revision=None,
3052
_override_hook_source_branch=None):
3053
"""See InterBranch.push.
3055
This is the basic concrete implementation of push()
3057
:param _override_hook_source_branch: If specified, run
3058
the hooks passing this Branch as the source, rather than self.
3059
This is for use of RemoteBranch, where push is delegated to the
3060
underlying vfs-based Branch.
3062
# TODO: Public option to disable running hooks - should be trivial but
3064
self.source.lock_read()
3066
return _run_with_write_locked_target(
3067
self.target, self._push_with_bound_branches, overwrite,
3069
_override_hook_source_branch=_override_hook_source_branch)
3071
self.source.unlock()
3074
def _push_with_bound_branches(self, overwrite, stop_revision,
3075
_override_hook_source_branch=None):
3076
"""Push from source into target, and into target's master if any.
3079
if _override_hook_source_branch:
3080
result.source_branch = _override_hook_source_branch
3081
for hook in Branch.hooks['post_push']:
3084
bound_location = self.target.get_bound_location()
3085
if bound_location and self.target.base != bound_location:
3086
# there is a master branch.
3088
# XXX: Why the second check? Is it even supported for a branch to
3089
# be bound to itself? -- mbp 20070507
3090
master_branch = self.target.get_master_branch()
3091
master_branch.lock_write()
3093
# push into the master from the source branch.
3094
self.source._basic_push(master_branch, overwrite, stop_revision)
3095
# and push into the target branch from the source. Note that we
3096
# push from the source branch again, because its considered the
3097
# highest bandwidth repository.
3098
result = self.source._basic_push(self.target, overwrite,
3100
result.master_branch = master_branch
3101
result.local_branch = self.target
3105
master_branch.unlock()
3108
result = self.source._basic_push(self.target, overwrite,
3110
# TODO: Why set master_branch and local_branch if there's no
3111
# binding? Maybe cleaner to just leave them unset? -- mbp
3113
result.master_branch = self.target
3114
result.local_branch = None
2875
3119
def is_compatible(self, source, target):
2876
3120
# GenericBranch uses the public API, so always compatible
3124
class InterToBranch5(GenericInterBranch):
3127
def _get_branch_formats_to_test():
3128
return BranchFormat._default_format, BzrBranchFormat5()
3130
def pull(self, overwrite=False, stop_revision=None,
3131
possible_transports=None, run_hooks=True,
3132
_override_hook_target=None, local=False):
3133
"""Pull from source into self, updating my master if any.
3135
:param run_hooks: Private parameter - if false, this branch
3136
is being called because it's the master of the primary branch,
3137
so it should not run its hooks.
3139
bound_location = self.target.get_bound_location()
3140
if local and not bound_location:
3141
raise errors.LocalRequiresBoundBranch()
3142
master_branch = None
3143
if not local and bound_location and self.source.base != bound_location:
3144
# not pulling from master, so we need to update master.
3145
master_branch = self.target.get_master_branch(possible_transports)
3146
master_branch.lock_write()
3149
# pull from source into master.
3150
master_branch.pull(self.source, overwrite, stop_revision,
3152
return super(InterToBranch5, self).pull(overwrite,
3153
stop_revision, _hook_master=master_branch,
3154
run_hooks=run_hooks,
3155
_override_hook_target=_override_hook_target)
3158
master_branch.unlock()
2880
3161
InterBranch.register_optimiser(GenericInterBranch)
3162
InterBranch.register_optimiser(InterToBranch5)