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