806
793
if len(old_repository._fallback_repositories) != 1:
807
794
raise AssertionError("can't cope with fallback repositories "
808
795
"of %r" % (self.repository,))
809
# Open the new repository object.
810
# Repositories don't offer an interface to remove fallback
811
# repositories today; take the conceptually simpler option and just
812
# reopen it. We reopen it starting from the URL so that we
813
# get a separate connection for RemoteRepositories and can
814
# stream from one of them to the other. This does mean doing
815
# separate SSH connection setup, but unstacking is not a
816
# common operation so it's tolerable.
817
new_bzrdir = bzrdir.BzrDir.open(self.bzrdir.root_transport.base)
818
new_repository = new_bzrdir.find_repository()
819
if new_repository._fallback_repositories:
820
raise AssertionError("didn't expect %r to have "
821
"fallback_repositories"
822
% (self.repository,))
823
# Replace self.repository with the new repository.
824
# Do our best to transfer the lock state (i.e. lock-tokens and
825
# lock count) of self.repository to the new repository.
826
lock_token = old_repository.lock_write().repository_token
827
self.repository = new_repository
828
if isinstance(self, remote.RemoteBranch):
829
# Remote branches can have a second reference to the old
830
# repository that need to be replaced.
831
if self._real_branch is not None:
832
self._real_branch.repository = new_repository
833
self.repository.lock_write(token=lock_token)
834
if lock_token is not None:
835
old_repository.leave_lock_in_place()
796
# unlock it, including unlocking the fallback
836
797
old_repository.unlock()
837
if lock_token is not None:
838
# XXX: self.repository.leave_lock_in_place() before this
839
# function will not be preserved. Fortunately that doesn't
840
# affect the current default format (2a), and would be a
841
# corner-case anyway.
842
# - Andrew Bennetts, 2010/06/30
843
self.repository.dont_leave_lock_in_place()
847
old_repository.unlock()
848
except errors.LockNotHeld:
851
if old_lock_count == 0:
852
raise AssertionError(
853
'old_repository should have been locked at least once.')
854
for i in range(old_lock_count-1):
798
old_repository.lock_read()
800
# Repositories don't offer an interface to remove fallback
801
# repositories today; take the conceptually simpler option and just
802
# reopen it. We reopen it starting from the URL so that we
803
# get a separate connection for RemoteRepositories and can
804
# stream from one of them to the other. This does mean doing
805
# separate SSH connection setup, but unstacking is not a
806
# common operation so it's tolerable.
807
new_bzrdir = bzrdir.BzrDir.open(self.bzrdir.root_transport.base)
808
new_repository = new_bzrdir.find_repository()
809
self.repository = new_repository
810
if self.repository._fallback_repositories:
811
raise AssertionError("didn't expect %r to have "
812
"fallback_repositories"
813
% (self.repository,))
814
# this is not paired with an unlock because it's just restoring
815
# the previous state; the lock's released when set_stacked_on_url
855
817
self.repository.lock_write()
856
# Fetch from the old repository into the new.
857
old_repository.lock_read()
859
818
# XXX: If you unstack a branch while it has a working tree
860
819
# with a pending merge, the pending-merged revisions will no
861
820
# longer be present. You can (probably) revert and remerge.
3318
3225
raise NotImplementedError(self.push)
3321
def copy_content_into(self, revision_id=None):
3322
"""Copy the content of source into target
3324
revision_id: if not None, the revision history in the new branch will
3325
be truncated to end with revision_id.
3327
raise NotImplementedError(self.copy_content_into)
3330
3228
class GenericInterBranch(InterBranch):
3331
"""InterBranch implementation that uses public Branch functions."""
3334
def is_compatible(klass, source, target):
3335
# GenericBranch uses the public API, so always compatible
3339
def _get_branch_formats_to_test(klass):
3340
return [(BranchFormat._default_format, BranchFormat._default_format)]
3343
def unwrap_format(klass, format):
3344
if isinstance(format, remote.RemoteBranchFormat):
3345
format._ensure_real()
3346
return format._custom_format
3350
def copy_content_into(self, revision_id=None):
3351
"""Copy the content of source into target
3353
revision_id: if not None, the revision history in the new branch will
3354
be truncated to end with revision_id.
3356
self.source.update_references(self.target)
3357
self.source._synchronize_history(self.target, revision_id)
3359
parent = self.source.get_parent()
3360
except errors.InaccessibleParent, e:
3361
mutter('parent was not accessible to copy: %s', e)
3364
self.target.set_parent(parent)
3365
if self.source._push_should_merge_tags():
3366
self.source.tags.merge_to(self.target.tags)
3229
"""InterBranch implementation that uses public Branch functions.
3233
def _get_branch_formats_to_test():
3234
return BranchFormat._default_format, BranchFormat._default_format
3369
3236
def update_revisions(self, stop_revision=None, overwrite=False,
3371
3238
"""See InterBranch.update_revisions()."""
3372
other_revno, other_last_revision = self.source.last_revision_info()
3373
stop_revno = None # unknown
3374
if stop_revision is None:
3375
stop_revision = other_last_revision
3376
if _mod_revision.is_null(stop_revision):
3377
# if there are no commits, we're done.
3379
stop_revno = other_revno
3381
# what's the current last revision, before we fetch [and change it
3383
last_rev = _mod_revision.ensure_null(self.target.last_revision())
3384
# we fetch here so that we don't process data twice in the common
3385
# case of having something to pull, and so that the check for
3386
# already merged can operate on the just fetched graph, which will
3387
# be cached in memory.
3388
self.target.fetch(self.source, stop_revision)
3389
# Check to see if one is an ancestor of the other
3392
graph = self.target.repository.get_graph()
3393
if self.target._check_if_descendant_or_diverged(
3394
stop_revision, last_rev, graph, self.source):
3395
# stop_revision is a descendant of last_rev, but we aren't
3396
# overwriting, so we're done.
3398
if stop_revno is None:
3400
graph = self.target.repository.get_graph()
3401
this_revno, this_last_revision = \
3402
self.target.last_revision_info()
3403
stop_revno = graph.find_distance_to_null(stop_revision,
3404
[(other_last_revision, other_revno),
3405
(this_last_revision, this_revno)])
3406
self.target.set_last_revision_info(stop_revno, stop_revision)
3239
self.source.lock_read()
3241
other_revno, other_last_revision = self.source.last_revision_info()
3242
stop_revno = None # unknown
3243
if stop_revision is None:
3244
stop_revision = other_last_revision
3245
if _mod_revision.is_null(stop_revision):
3246
# if there are no commits, we're done.
3248
stop_revno = other_revno
3250
# what's the current last revision, before we fetch [and change it
3252
last_rev = _mod_revision.ensure_null(self.target.last_revision())
3253
# we fetch here so that we don't process data twice in the common
3254
# case of having something to pull, and so that the check for
3255
# already merged can operate on the just fetched graph, which will
3256
# be cached in memory.
3257
self.target.fetch(self.source, stop_revision)
3258
# Check to see if one is an ancestor of the other
3261
graph = self.target.repository.get_graph()
3262
if self.target._check_if_descendant_or_diverged(
3263
stop_revision, last_rev, graph, self.source):
3264
# stop_revision is a descendant of last_rev, but we aren't
3265
# overwriting, so we're done.
3267
if stop_revno is None:
3269
graph = self.target.repository.get_graph()
3270
this_revno, this_last_revision = \
3271
self.target.last_revision_info()
3272
stop_revno = graph.find_distance_to_null(stop_revision,
3273
[(other_last_revision, other_revno),
3274
(this_last_revision, this_revno)])
3275
self.target.set_last_revision_info(stop_revno, stop_revision)
3277
self.source.unlock()
3409
3279
def pull(self, overwrite=False, stop_revision=None,
3410
possible_transports=None, run_hooks=True,
3280
possible_transports=None, _hook_master=None, run_hooks=True,
3411
3281
_override_hook_target=None, local=False):
3412
"""Pull from source into self, updating my master if any.
3284
:param _hook_master: Private parameter - set the branch to
3285
be supplied as the master to pull hooks.
3414
3286
:param run_hooks: Private parameter - if false, this branch
3415
3287
is being called because it's the master of the primary branch,
3416
3288
so it should not run its hooks.
3289
:param _override_hook_target: Private parameter - set the branch to be
3290
supplied as the target_branch to pull hooks.
3291
:param local: Only update the local branch, and not the bound branch.
3418
bound_location = self.target.get_bound_location()
3419
if local and not bound_location:
3293
# This type of branch can't be bound.
3420
3295
raise errors.LocalRequiresBoundBranch()
3421
master_branch = None
3422
if not local and bound_location and self.source.user_url != bound_location:
3423
# not pulling from master, so we need to update master.
3424
master_branch = self.target.get_master_branch(possible_transports)
3425
master_branch.lock_write()
3296
result = PullResult()
3297
result.source_branch = self.source
3298
if _override_hook_target is None:
3299
result.target_branch = self.target
3301
result.target_branch = _override_hook_target
3302
self.source.lock_read()
3428
# pull from source into master.
3429
master_branch.pull(self.source, overwrite, stop_revision,
3431
return self._pull(overwrite,
3432
stop_revision, _hook_master=master_branch,
3433
run_hooks=run_hooks,
3434
_override_hook_target=_override_hook_target)
3304
# We assume that during 'pull' the target repository is closer than
3306
self.source.update_references(self.target)
3307
graph = self.target.repository.get_graph(self.source.repository)
3308
# TODO: Branch formats should have a flag that indicates
3309
# that revno's are expensive, and pull() should honor that flag.
3311
result.old_revno, result.old_revid = \
3312
self.target.last_revision_info()
3313
self.target.update_revisions(self.source, stop_revision,
3314
overwrite=overwrite, graph=graph)
3315
# TODO: The old revid should be specified when merging tags,
3316
# so a tags implementation that versions tags can only
3317
# pull in the most recent changes. -- JRV20090506
3318
result.tag_conflicts = self.source.tags.merge_to(self.target.tags,
3320
result.new_revno, result.new_revid = self.target.last_revision_info()
3322
result.master_branch = _hook_master
3323
result.local_branch = result.target_branch
3325
result.master_branch = result.target_branch
3326
result.local_branch = None
3328
for hook in Branch.hooks['post_pull']:
3437
master_branch.unlock()
3331
self.source.unlock()
3439
3334
def push(self, overwrite=False, stop_revision=None,
3440
3335
_override_hook_source_branch=None):
3505
def _pull(self, overwrite=False, stop_revision=None,
3506
possible_transports=None, _hook_master=None, run_hooks=True,
3401
def is_compatible(self, source, target):
3402
# GenericBranch uses the public API, so always compatible
3406
class InterToBranch5(GenericInterBranch):
3409
def _get_branch_formats_to_test():
3410
return BranchFormat._default_format, BzrBranchFormat5()
3412
def pull(self, overwrite=False, stop_revision=None,
3413
possible_transports=None, run_hooks=True,
3507
3414
_override_hook_target=None, local=False):
3510
This function is the core worker, used by GenericInterBranch.pull to
3511
avoid duplication when pulling source->master and source->local.
3513
:param _hook_master: Private parameter - set the branch to
3514
be supplied as the master to pull hooks.
3415
"""Pull from source into self, updating my master if any.
3515
3417
:param run_hooks: Private parameter - if false, this branch
3516
3418
is being called because it's the master of the primary branch,
3517
3419
so it should not run its hooks.
3518
:param _override_hook_target: Private parameter - set the branch to be
3519
supplied as the target_branch to pull hooks.
3520
:param local: Only update the local branch, and not the bound branch.
3522
# This type of branch can't be bound.
3421
bound_location = self.target.get_bound_location()
3422
if local and not bound_location:
3524
3423
raise errors.LocalRequiresBoundBranch()
3525
result = PullResult()
3526
result.source_branch = self.source
3527
if _override_hook_target is None:
3528
result.target_branch = self.target
3530
result.target_branch = _override_hook_target
3531
self.source.lock_read()
3424
master_branch = None
3425
if not local and bound_location and self.source.user_url != bound_location:
3426
# not pulling from master, so we need to update master.
3427
master_branch = self.target.get_master_branch(possible_transports)
3428
master_branch.lock_write()
3533
# We assume that during 'pull' the target repository is closer than
3535
self.source.update_references(self.target)
3536
graph = self.target.repository.get_graph(self.source.repository)
3537
# TODO: Branch formats should have a flag that indicates
3538
# that revno's are expensive, and pull() should honor that flag.
3540
result.old_revno, result.old_revid = \
3541
self.target.last_revision_info()
3542
self.target.update_revisions(self.source, stop_revision,
3543
overwrite=overwrite, graph=graph)
3544
# TODO: The old revid should be specified when merging tags,
3545
# so a tags implementation that versions tags can only
3546
# pull in the most recent changes. -- JRV20090506
3547
result.tag_conflicts = self.source.tags.merge_to(self.target.tags,
3549
result.new_revno, result.new_revid = self.target.last_revision_info()
3551
result.master_branch = _hook_master
3552
result.local_branch = result.target_branch
3554
result.master_branch = result.target_branch
3555
result.local_branch = None
3557
for hook in Branch.hooks['post_pull']:
3431
# pull from source into master.
3432
master_branch.pull(self.source, overwrite, stop_revision,
3434
return super(InterToBranch5, self).pull(overwrite,
3435
stop_revision, _hook_master=master_branch,
3436
run_hooks=run_hooks,
3437
_override_hook_target=_override_hook_target)
3560
self.source.unlock()
3440
master_branch.unlock()
3564
3443
InterBranch.register_optimiser(GenericInterBranch)
3444
InterBranch.register_optimiser(InterToBranch5)