128
129
raise errors.UnstackableRepositoryFormat(self.repository._format,
129
130
self.repository.base)
131
def _extend_partial_history(self, stop_index=None, stop_revision=None):
132
"""Extend the partial history to include a given index
134
If a stop_index is supplied, stop when that index has been reached.
135
If a stop_revision is supplied, stop when that revision is
136
encountered. Otherwise, stop when the beginning of history is
139
:param stop_index: The index which should be present. When it is
140
present, history extension will stop.
141
:param stop_revision: The revision id which should be present. When
142
it is encountered, history extension will stop.
144
if len(self._partial_revision_history_cache) == 0:
145
self._partial_revision_history_cache = [self.last_revision()]
146
repository._iter_for_revno(
147
self.repository, self._partial_revision_history_cache,
148
stop_index=stop_index, stop_revision=stop_revision)
149
if self._partial_revision_history_cache[-1] == _mod_revision.NULL_REVISION:
150
self._partial_revision_history_cache.pop()
152
def _get_check_refs(self):
153
"""Get the references needed for check().
157
revid = self.last_revision()
158
return [('revision-existence', revid), ('lefthand-distance', revid)]
161
133
def open(base, _unsupported=False, possible_transports=None):
162
134
"""Open the branch rooted at base.
681
640
except (errors.NotStacked, errors.UnstackableBranchFormat,
682
641
errors.UnstackableRepositoryFormat):
644
# XXX: Lock correctness - should unlock our old repo if we were
646
# repositories don't offer an interface to remove fallback
647
# repositories today; take the conceptually simpler option and just
649
self.repository = self.bzrdir.find_repository()
650
self.repository.lock_write()
651
# for every revision reference the branch has, ensure it is pulled
653
source_repository = self._get_fallback_repository(old_url)
654
for revision_id in chain([self.last_revision()],
655
self.tags.get_reverse_tag_dict()):
656
self.repository.fetch(source_repository, revision_id,
686
self._activate_fallback_location(url)
659
self._activate_fallback_location(url, 'write')
687
660
# write this out after the repository is stacked to avoid setting a
688
661
# stacked config that doesn't work.
689
662
self._set_config_location('stacked_on_location', url)
692
"""Change a branch to be unstacked, copying data as needed.
694
Don't call this directly, use set_stacked_on_url(None).
696
pb = ui.ui_factory.nested_progress_bar()
698
pb.update("Unstacking")
699
# The basic approach here is to fetch the tip of the branch,
700
# including all available ghosts, from the existing stacked
701
# repository into a new repository object without the fallbacks.
703
# XXX: See <https://launchpad.net/bugs/397286> - this may not be
704
# correct for CHKMap repostiories
705
old_repository = self.repository
706
if len(old_repository._fallback_repositories) != 1:
707
raise AssertionError("can't cope with fallback repositories "
708
"of %r" % (self.repository,))
709
# unlock it, including unlocking the fallback
710
old_repository.unlock()
711
old_repository.lock_read()
713
# Repositories don't offer an interface to remove fallback
714
# repositories today; take the conceptually simpler option and just
715
# reopen it. We reopen it starting from the URL so that we
716
# get a separate connection for RemoteRepositories and can
717
# stream from one of them to the other. This does mean doing
718
# separate SSH connection setup, but unstacking is not a
719
# common operation so it's tolerable.
720
new_bzrdir = bzrdir.BzrDir.open(self.bzrdir.root_transport.base)
721
new_repository = new_bzrdir.find_repository()
722
self.repository = new_repository
723
if self.repository._fallback_repositories:
724
raise AssertionError("didn't expect %r to have "
725
"fallback_repositories"
726
% (self.repository,))
727
# this is not paired with an unlock because it's just restoring
728
# the previous state; the lock's released when set_stacked_on_url
730
self.repository.lock_write()
731
# XXX: If you unstack a branch while it has a working tree
732
# with a pending merge, the pending-merged revisions will no
733
# longer be present. You can (probably) revert and remerge.
735
# XXX: This only fetches up to the tip of the repository; it
736
# doesn't bring across any tags. That's fairly consistent
737
# with how branch works, but perhaps not ideal.
738
self.repository.fetch(old_repository,
739
revision_id=self.last_revision(),
742
old_repository.unlock()
746
665
def _set_tags_bytes(self, bytes):
747
666
"""Mirror method for _get_tags_bytes.
914
835
except ValueError:
915
836
raise errors.NoSuchRevision(self, revision_id)
918
838
def get_rev_id(self, revno, history=None):
919
839
"""Find the revision id of the specified revno."""
921
841
return _mod_revision.NULL_REVISION
922
last_revno, last_revid = self.last_revision_info()
923
if revno == last_revno:
925
if revno <= 0 or revno > last_revno:
843
history = self.revision_history()
844
if revno <= 0 or revno > len(history):
926
845
raise errors.NoSuchRevision(self, revno)
927
distance_from_last = last_revno - revno
928
if len(self._partial_revision_history_cache) <= distance_from_last:
929
self._extend_partial_history(distance_from_last)
930
return self._partial_revision_history_cache[distance_from_last]
846
return history[revno - 1]
933
848
def pull(self, source, overwrite=False, stop_revision=None,
934
possible_transports=None, *args, **kwargs):
849
possible_transports=None, _override_hook_target=None):
935
850
"""Mirror source into this branch.
937
852
This branch is considered to be 'local', having low latency.
939
854
:returns: PullResult instance
941
return InterBranch.get(source, self).pull(overwrite=overwrite,
942
stop_revision=stop_revision,
943
possible_transports=possible_transports, *args, **kwargs)
856
raise NotImplementedError(self.pull)
945
def push(self, target, overwrite=False, stop_revision=None, *args,
858
def push(self, target, overwrite=False, stop_revision=None):
947
859
"""Mirror this branch into target.
949
861
This branch is considered to be 'local', having low latency.
951
return InterBranch.get(self, target).push(overwrite, stop_revision,
954
def lossy_push(self, target, stop_revision=None):
955
"""Push deltas into another branch.
957
:note: This does not, like push, retain the revision ids from
958
the source branch and will, rather than adding bzr-specific
959
metadata, push only those semantics of the revision that can be
960
natively represented by this branch' VCS.
962
:param target: Target branch
963
:param stop_revision: Revision to push, defaults to last revision.
964
:return: BranchPushResult with an extra member revidmap:
965
A dictionary mapping revision ids from the target branch
966
to new revision ids in the target branch, for each
967
revision that was pushed.
969
inter = InterBranch.get(self, target)
970
lossy_push = getattr(inter, "lossy_push", None)
971
if lossy_push is None:
972
raise errors.LossyPushToSameVCS(self, target)
973
return lossy_push(stop_revision)
863
raise NotImplementedError(self.push)
975
865
def basis_tree(self):
976
866
"""Return `Tree` object for last revision."""
1173
1059
source_revno, source_revision_id = self.last_revision_info()
1174
1060
if revision_id is None:
1175
1061
revno, revision_id = source_revno, source_revision_id
1062
elif source_revision_id == revision_id:
1063
# we know the revno without needing to walk all of history
1064
revno = source_revno
1177
graph = self.repository.get_graph()
1179
revno = graph.find_distance_to_null(revision_id,
1180
[(source_revision_id, source_revno)])
1181
except errors.GhostRevisionsHaveNoRevno:
1182
# Default to 1, if we can't find anything else
1066
# To figure out the revno for a random revision, we need to build
1067
# the revision history, and count its length.
1068
# We don't care about the order, just how long it is.
1069
# Alternatively, we could start at the current location, and count
1070
# backwards. But there is no guarantee that we will find it since
1071
# it may be a merged revision.
1072
revno = len(list(self.repository.iter_reverse_revision_history(
1184
1074
destination.set_last_revision_info(revno, revision_id)
1186
1076
@needs_read_lock
1230
1120
Callers will typically also want to check the repository.
1232
:param refs: Calculated refs for this branch as specified by
1233
branch._get_check_refs()
1234
1122
:return: A BranchCheckResult.
1236
result = BranchCheckResult(self)
1124
mainline_parent_id = None
1237
1125
last_revno, last_revision_id = self.last_revision_info()
1238
actual_revno = refs[('lefthand-distance', last_revision_id)]
1239
if actual_revno != last_revno:
1240
result.errors.append(errors.BzrCheckError(
1241
'revno does not match len(mainline) %s != %s' % (
1242
last_revno, actual_revno)))
1243
# TODO: We should probably also check that self.revision_history
1244
# matches the repository for older branch formats.
1245
# If looking for the code that cross-checks repository parents against
1246
# the iter_reverse_revision_history output, that is now a repository
1126
real_rev_history = list(self.repository.iter_reverse_revision_history(
1128
real_rev_history.reverse()
1129
if len(real_rev_history) != last_revno:
1130
raise errors.BzrCheckError('revno does not match len(mainline)'
1131
' %s != %s' % (last_revno, len(real_rev_history)))
1132
# TODO: We should probably also check that real_rev_history actually
1133
# matches self.revision_history()
1134
for revision_id in real_rev_history:
1136
revision = self.repository.get_revision(revision_id)
1137
except errors.NoSuchRevision, e:
1138
raise errors.BzrCheckError("mainline revision {%s} not in repository"
1140
# In general the first entry on the revision history has no parents.
1141
# But it's not illegal for it to have parents listed; this can happen
1142
# in imports from Arch when the parents weren't reachable.
1143
if mainline_parent_id is not None:
1144
if mainline_parent_id not in revision.parent_ids:
1145
raise errors.BzrCheckError("previous revision {%s} not listed among "
1147
% (mainline_parent_id, revision_id))
1148
mainline_parent_id = revision_id
1149
return BranchCheckResult(self)
1250
1151
def _get_checkout_format(self):
1251
1152
"""Return the most suitable metadir for a checkout of this branch.
2288
2175
"""See Branch.basis_tree."""
2289
2176
return self.repository.revision_tree(self.last_revision())
2179
def pull(self, source, overwrite=False, stop_revision=None,
2180
_hook_master=None, run_hooks=True, possible_transports=None,
2181
_override_hook_target=None):
2184
:param _hook_master: Private parameter - set the branch to
2185
be supplied as the master to pull hooks.
2186
:param run_hooks: Private parameter - if false, this branch
2187
is being called because it's the master of the primary branch,
2188
so it should not run its hooks.
2189
:param _override_hook_target: Private parameter - set the branch to be
2190
supplied as the target_branch to pull hooks.
2192
result = PullResult()
2193
result.source_branch = source
2194
if _override_hook_target is None:
2195
result.target_branch = self
2197
result.target_branch = _override_hook_target
2200
# We assume that during 'pull' the local repository is closer than
2202
source.update_references(self)
2203
graph = self.repository.get_graph(source.repository)
2204
result.old_revno, result.old_revid = self.last_revision_info()
2205
self.update_revisions(source, stop_revision, overwrite=overwrite,
2207
result.tag_conflicts = source.tags.merge_to(self.tags, overwrite)
2208
result.new_revno, result.new_revid = self.last_revision_info()
2210
result.master_branch = _hook_master
2211
result.local_branch = result.target_branch
2213
result.master_branch = result.target_branch
2214
result.local_branch = None
2216
for hook in Branch.hooks['post_pull']:
2291
2222
def _get_parent_location(self):
2292
2223
_locs = ['parent', 'pull', 'x-pull']
2293
2224
for l in _locs:
2232
def push(self, target, overwrite=False, stop_revision=None,
2233
_override_hook_source_branch=None):
2236
This is the basic concrete implementation of push()
2238
:param _override_hook_source_branch: If specified, run
2239
the hooks passing this Branch as the source, rather than self.
2240
This is for use of RemoteBranch, where push is delegated to the
2241
underlying vfs-based Branch.
2243
# TODO: Public option to disable running hooks - should be trivial but
2245
return _run_with_write_locked_target(
2246
target, self._push_with_bound_branches, target, overwrite,
2248
_override_hook_source_branch=_override_hook_source_branch)
2250
def _push_with_bound_branches(self, target, overwrite,
2252
_override_hook_source_branch=None):
2253
"""Push from self into target, and into target's master if any.
2255
This is on the base BzrBranch class even though it doesn't support
2256
bound branches because the *target* might be bound.
2259
if _override_hook_source_branch:
2260
result.source_branch = _override_hook_source_branch
2261
for hook in Branch.hooks['post_push']:
2264
bound_location = target.get_bound_location()
2265
if bound_location and target.base != bound_location:
2266
# there is a master branch.
2268
# XXX: Why the second check? Is it even supported for a branch to
2269
# be bound to itself? -- mbp 20070507
2270
master_branch = target.get_master_branch()
2271
master_branch.lock_write()
2273
# push into the master from this branch.
2274
self._basic_push(master_branch, overwrite, stop_revision)
2275
# and push into the target branch from this. Note that we push from
2276
# this branch again, because its considered the highest bandwidth
2278
result = self._basic_push(target, overwrite, stop_revision)
2279
result.master_branch = master_branch
2280
result.local_branch = target
2284
master_branch.unlock()
2287
result = self._basic_push(target, overwrite, stop_revision)
2288
# TODO: Why set master_branch and local_branch if there's no
2289
# binding? Maybe cleaner to just leave them unset? -- mbp
2291
result.master_branch = target
2292
result.local_branch = None
2300
2296
def _basic_push(self, target, overwrite, stop_revision):
2301
2297
"""Basic implementation of push without bound branches or hooks.
2303
Must be called with source read locked and target write locked.
2299
Must be called with self read locked and target write locked.
2305
2301
result = BranchPushResult()
2306
2302
result.source_branch = self
2342
2337
It has support for a master_branch which is the data for bound branches.
2341
def pull(self, source, overwrite=False, stop_revision=None,
2342
run_hooks=True, possible_transports=None,
2343
_override_hook_target=None):
2344
"""Pull from source into self, updating my master if any.
2346
:param run_hooks: Private parameter - if false, this branch
2347
is being called because it's the master of the primary branch,
2348
so it should not run its hooks.
2350
bound_location = self.get_bound_location()
2351
master_branch = None
2352
if bound_location and source.base != bound_location:
2353
# not pulling from master, so we need to update master.
2354
master_branch = self.get_master_branch(possible_transports)
2355
master_branch.lock_write()
2358
# pull from source into master.
2359
master_branch.pull(source, overwrite, stop_revision,
2361
return super(BzrBranch5, self).pull(source, overwrite,
2362
stop_revision, _hook_master=master_branch,
2363
run_hooks=run_hooks,
2364
_override_hook_target=_override_hook_target)
2367
master_branch.unlock()
2345
2369
def get_bound_location(self):
2347
2371
return self._transport.get_bytes('bound')[:-1]
2525
2551
self._extend_partial_history(stop_index=last_revno-1)
2526
2552
return list(reversed(self._partial_revision_history_cache))
2554
def _extend_partial_history(self, stop_index=None, stop_revision=None):
2555
"""Extend the partial history to include a given index
2557
If a stop_index is supplied, stop when that index has been reached.
2558
If a stop_revision is supplied, stop when that revision is
2559
encountered. Otherwise, stop when the beginning of history is
2562
:param stop_index: The index which should be present. When it is
2563
present, history extension will stop.
2564
:param revision_id: The revision id which should be present. When
2565
it is encountered, history extension will stop.
2567
repo = self.repository
2568
if len(self._partial_revision_history_cache) == 0:
2569
iterator = repo.iter_reverse_revision_history(self.last_revision())
2571
start_revision = self._partial_revision_history_cache[-1]
2572
iterator = repo.iter_reverse_revision_history(start_revision)
2573
#skip the last revision in the list
2574
next_revision = iterator.next()
2575
for revision_id in iterator:
2576
self._partial_revision_history_cache.append(revision_id)
2577
if (stop_index is not None and
2578
len(self._partial_revision_history_cache) > stop_index):
2580
if revision_id == stop_revision:
2528
2583
def _write_revision_history(self, history):
2529
2584
"""Factored out of set_revision_history.
3026
3069
self.source.unlock()
3028
def pull(self, overwrite=False, stop_revision=None,
3029
possible_transports=None, _hook_master=None, run_hooks=True,
3030
_override_hook_target=None, local=False):
3033
:param _hook_master: Private parameter - set the branch to
3034
be supplied as the master to pull hooks.
3035
:param run_hooks: Private parameter - if false, this branch
3036
is being called because it's the master of the primary branch,
3037
so it should not run its hooks.
3038
:param _override_hook_target: Private parameter - set the branch to be
3039
supplied as the target_branch to pull hooks.
3040
:param local: Only update the local branch, and not the bound branch.
3042
# This type of branch can't be bound.
3044
raise errors.LocalRequiresBoundBranch()
3045
result = PullResult()
3046
result.source_branch = self.source
3047
if _override_hook_target is None:
3048
result.target_branch = self.target
3050
result.target_branch = _override_hook_target
3051
self.source.lock_read()
3053
# We assume that during 'pull' the target repository is closer than
3055
self.source.update_references(self.target)
3056
graph = self.target.repository.get_graph(self.source.repository)
3057
# TODO: Branch formats should have a flag that indicates
3058
# that revno's are expensive, and pull() should honor that flag.
3060
result.old_revno, result.old_revid = \
3061
self.target.last_revision_info()
3062
self.target.update_revisions(self.source, stop_revision,
3063
overwrite=overwrite, graph=graph)
3064
# TODO: The old revid should be specified when merging tags,
3065
# so a tags implementation that versions tags can only
3066
# pull in the most recent changes. -- JRV20090506
3067
result.tag_conflicts = self.source.tags.merge_to(self.target.tags,
3069
result.new_revno, result.new_revid = self.target.last_revision_info()
3071
result.master_branch = _hook_master
3072
result.local_branch = result.target_branch
3074
result.master_branch = result.target_branch
3075
result.local_branch = None
3077
for hook in Branch.hooks['post_pull']:
3080
self.source.unlock()
3083
def push(self, overwrite=False, stop_revision=None,
3084
_override_hook_source_branch=None):
3085
"""See InterBranch.push.
3087
This is the basic concrete implementation of push()
3089
:param _override_hook_source_branch: If specified, run
3090
the hooks passing this Branch as the source, rather than self.
3091
This is for use of RemoteBranch, where push is delegated to the
3092
underlying vfs-based Branch.
3094
# TODO: Public option to disable running hooks - should be trivial but
3096
self.source.lock_read()
3098
return _run_with_write_locked_target(
3099
self.target, self._push_with_bound_branches, overwrite,
3101
_override_hook_source_branch=_override_hook_source_branch)
3103
self.source.unlock()
3105
def _push_with_bound_branches(self, overwrite, stop_revision,
3106
_override_hook_source_branch=None):
3107
"""Push from source into target, and into target's master if any.
3110
if _override_hook_source_branch:
3111
result.source_branch = _override_hook_source_branch
3112
for hook in Branch.hooks['post_push']:
3115
bound_location = self.target.get_bound_location()
3116
if bound_location and self.target.base != bound_location:
3117
# there is a master branch.
3119
# XXX: Why the second check? Is it even supported for a branch to
3120
# be bound to itself? -- mbp 20070507
3121
master_branch = self.target.get_master_branch()
3122
master_branch.lock_write()
3124
# push into the master from the source branch.
3125
self.source._basic_push(master_branch, overwrite, stop_revision)
3126
# and push into the target branch from the source. Note that we
3127
# push from the source branch again, because its considered the
3128
# highest bandwidth repository.
3129
result = self.source._basic_push(self.target, overwrite,
3131
result.master_branch = master_branch
3132
result.local_branch = self.target
3136
master_branch.unlock()
3139
result = self.source._basic_push(self.target, overwrite,
3141
# TODO: Why set master_branch and local_branch if there's no
3142
# binding? Maybe cleaner to just leave them unset? -- mbp
3144
result.master_branch = self.target
3145
result.local_branch = None
3150
3072
def is_compatible(self, source, target):
3151
3073
# GenericBranch uses the public API, so always compatible
3155
class InterToBranch5(GenericInterBranch):
3158
def _get_branch_formats_to_test():
3159
return BranchFormat._default_format, BzrBranchFormat5()
3161
def pull(self, overwrite=False, stop_revision=None,
3162
possible_transports=None, run_hooks=True,
3163
_override_hook_target=None, local=False):
3164
"""Pull from source into self, updating my master if any.
3166
:param run_hooks: Private parameter - if false, this branch
3167
is being called because it's the master of the primary branch,
3168
so it should not run its hooks.
3170
bound_location = self.target.get_bound_location()
3171
if local and not bound_location:
3172
raise errors.LocalRequiresBoundBranch()
3173
master_branch = None
3174
if not local and bound_location and self.source.base != bound_location:
3175
# not pulling from master, so we need to update master.
3176
master_branch = self.target.get_master_branch(possible_transports)
3177
master_branch.lock_write()
3180
# pull from source into master.
3181
master_branch.pull(self.source, overwrite, stop_revision,
3183
return super(InterToBranch5, self).pull(overwrite,
3184
stop_revision, _hook_master=master_branch,
3185
run_hooks=run_hooks,
3186
_override_hook_target=_override_hook_target)
3189
master_branch.unlock()
3192
3077
InterBranch.register_optimiser(GenericInterBranch)
3193
InterBranch.register_optimiser(InterToBranch5)