526
573
raise ValueError('invalid stop_rule %r' % stop_rule)
575
def _filter_start_non_ancestors(self, rev_iter):
576
# If we started from a dotted revno, we want to consider it as a tip
577
# and don't want to yield revisions that are not part of its
578
# ancestry. Given the order guaranteed by the merge sort, we will see
579
# uninteresting descendants of the first parent of our tip before the
581
first = rev_iter.next()
582
(rev_id, merge_depth, revno, end_of_merge) = first
585
# We start at a mainline revision so by definition, all others
586
# revisions in rev_iter are ancestors
587
for node in rev_iter:
592
pmap = self.repository.get_parent_map([rev_id])
593
parents = pmap.get(rev_id, [])
595
whitelist.update(parents)
597
# If there is no parents, there is nothing of interest left
599
# FIXME: It's hard to test this scenario here as this code is never
600
# called in that case. -- vila 20100322
603
for (rev_id, merge_depth, revno, end_of_merge) in rev_iter:
605
if rev_id in whitelist:
606
pmap = self.repository.get_parent_map([rev_id])
607
parents = pmap.get(rev_id, [])
608
whitelist.remove(rev_id)
609
whitelist.update(parents)
611
# We've reached the mainline, there is nothing left to
615
# A revision that is not part of the ancestry of our
618
yield (rev_id, merge_depth, revno, end_of_merge)
528
620
def leave_lock_in_place(self):
529
621
"""Tell this branch object not to release the physical lock when this
530
622
object is unlocked.
724
816
old_repository = self.repository
725
817
if len(old_repository._fallback_repositories) != 1:
726
818
raise AssertionError("can't cope with fallback repositories "
727
"of %r" % (self.repository,))
728
# unlock it, including unlocking the fallback
819
"of %r (fallbacks: %r)" % (old_repository,
820
old_repository._fallback_repositories))
821
# Open the new repository object.
822
# Repositories don't offer an interface to remove fallback
823
# repositories today; take the conceptually simpler option and just
824
# reopen it. We reopen it starting from the URL so that we
825
# get a separate connection for RemoteRepositories and can
826
# stream from one of them to the other. This does mean doing
827
# separate SSH connection setup, but unstacking is not a
828
# common operation so it's tolerable.
829
new_bzrdir = bzrdir.BzrDir.open(self.bzrdir.root_transport.base)
830
new_repository = new_bzrdir.find_repository()
831
if new_repository._fallback_repositories:
832
raise AssertionError("didn't expect %r to have "
833
"fallback_repositories"
834
% (self.repository,))
835
# Replace self.repository with the new repository.
836
# Do our best to transfer the lock state (i.e. lock-tokens and
837
# lock count) of self.repository to the new repository.
838
lock_token = old_repository.lock_write().repository_token
839
self.repository = new_repository
840
if isinstance(self, remote.RemoteBranch):
841
# Remote branches can have a second reference to the old
842
# repository that need to be replaced.
843
if self._real_branch is not None:
844
self._real_branch.repository = new_repository
845
self.repository.lock_write(token=lock_token)
846
if lock_token is not None:
847
old_repository.leave_lock_in_place()
729
848
old_repository.unlock()
849
if lock_token is not None:
850
# XXX: self.repository.leave_lock_in_place() before this
851
# function will not be preserved. Fortunately that doesn't
852
# affect the current default format (2a), and would be a
853
# corner-case anyway.
854
# - Andrew Bennetts, 2010/06/30
855
self.repository.dont_leave_lock_in_place()
859
old_repository.unlock()
860
except errors.LockNotHeld:
863
if old_lock_count == 0:
864
raise AssertionError(
865
'old_repository should have been locked at least once.')
866
for i in range(old_lock_count-1):
867
self.repository.lock_write()
868
# Fetch from the old repository into the new.
730
869
old_repository.lock_read()
732
# Repositories don't offer an interface to remove fallback
733
# repositories today; take the conceptually simpler option and just
734
# reopen it. We reopen it starting from the URL so that we
735
# get a separate connection for RemoteRepositories and can
736
# stream from one of them to the other. This does mean doing
737
# separate SSH connection setup, but unstacking is not a
738
# common operation so it's tolerable.
739
new_bzrdir = bzrdir.BzrDir.open(self.bzrdir.root_transport.base)
740
new_repository = new_bzrdir.find_repository()
741
self.repository = new_repository
742
if self.repository._fallback_repositories:
743
raise AssertionError("didn't expect %r to have "
744
"fallback_repositories"
745
% (self.repository,))
746
# this is not paired with an unlock because it's just restoring
747
# the previous state; the lock's released when set_stacked_on_url
749
self.repository.lock_write()
750
871
# XXX: If you unstack a branch while it has a working tree
751
872
# with a pending merge, the pending-merged revisions will no
752
873
# longer be present. You can (probably) revert and remerge.
1483
1634
"""Return the short format description for this format."""
1484
1635
raise NotImplementedError(self.get_format_description)
1486
def _initialize_helper(self, a_bzrdir, utf8_files, lock_type='metadir',
1637
def _run_post_branch_init_hooks(self, a_bzrdir, name, branch):
1638
hooks = Branch.hooks['post_branch_init']
1641
params = BranchInitHookParams(self, a_bzrdir, name, branch)
1645
def _initialize_helper(self, a_bzrdir, utf8_files, name=None,
1646
repository=None, lock_type='metadir',
1487
1647
set_format=True):
1488
1648
"""Initialize a branch in a bzrdir, with specified files
1490
1650
:param a_bzrdir: The bzrdir to initialize the branch in
1491
1651
:param utf8_files: The files to create as a list of
1492
1652
(filename, content) tuples
1653
:param name: Name of colocated branch to create, if any
1493
1654
:param set_format: If True, set the format with
1494
1655
self.get_format_string. (BzrBranch4 has its format set
1496
1657
:return: a branch in this format
1498
mutter('creating branch %r in %s', self, a_bzrdir.transport.base)
1499
branch_transport = a_bzrdir.get_branch_transport(self)
1659
mutter('creating branch %r in %s', self, a_bzrdir.user_url)
1660
branch_transport = a_bzrdir.get_branch_transport(self, name=name)
1501
1662
'metadir': ('lock', lockdir.LockDir),
1502
1663
'branch4': ('branch-lock', lockable_files.TransportLock),
1723
1945
self.old_revno, self.old_revid, self.new_revno, self.new_revid)
1948
class BranchInitHookParams(object):
1949
"""Object holding parameters passed to *_branch_init hooks.
1951
There are 4 fields that hooks may wish to access:
1953
:ivar format: the branch format
1954
:ivar bzrdir: the BzrDir where the branch will be/has been initialized
1955
:ivar name: name of colocated branch, if any (or None)
1956
:ivar branch: the branch created
1958
Note that for lightweight checkouts, the bzrdir and format fields refer to
1959
the checkout, hence they are different from the corresponding fields in
1960
branch, which refer to the original branch.
1963
def __init__(self, format, a_bzrdir, name, branch):
1964
"""Create a group of BranchInitHook parameters.
1966
:param format: the branch format
1967
:param a_bzrdir: the BzrDir where the branch will be/has been
1969
:param name: name of colocated branch, if any (or None)
1970
:param branch: the branch created
1972
Note that for lightweight checkouts, the bzrdir and format fields refer
1973
to the checkout, hence they are different from the corresponding fields
1974
in branch, which refer to the original branch.
1976
self.format = format
1977
self.bzrdir = a_bzrdir
1979
self.branch = branch
1981
def __eq__(self, other):
1982
return self.__dict__ == other.__dict__
1985
return "<%s of %s>" % (self.__class__.__name__, self.branch)
1988
class SwitchHookParams(object):
1989
"""Object holding parameters passed to *_switch hooks.
1991
There are 4 fields that hooks may wish to access:
1993
:ivar control_dir: BzrDir of the checkout to change
1994
:ivar to_branch: branch that the checkout is to reference
1995
:ivar force: skip the check for local commits in a heavy checkout
1996
:ivar revision_id: revision ID to switch to (or None)
1999
def __init__(self, control_dir, to_branch, force, revision_id):
2000
"""Create a group of SwitchHook parameters.
2002
:param control_dir: BzrDir of the checkout to change
2003
:param to_branch: branch that the checkout is to reference
2004
:param force: skip the check for local commits in a heavy checkout
2005
:param revision_id: revision ID to switch to (or None)
2007
self.control_dir = control_dir
2008
self.to_branch = to_branch
2010
self.revision_id = revision_id
2012
def __eq__(self, other):
2013
return self.__dict__ == other.__dict__
2016
return "<%s for %s to (%s, %s)>" % (self.__class__.__name__,
2017
self.control_dir, self.to_branch,
1726
2021
class BzrBranchFormat4(BranchFormat):
1727
2022
"""Bzr branch format 4.
1974
2280
"""See BranchFormat.get_format_description()."""
1975
2281
return "Checkout reference format 1"
1977
def get_reference(self, a_bzrdir):
2283
def get_reference(self, a_bzrdir, name=None):
1978
2284
"""See BranchFormat.get_reference()."""
1979
transport = a_bzrdir.get_branch_transport(None)
2285
transport = a_bzrdir.get_branch_transport(None, name=name)
1980
2286
return transport.get_bytes('location')
1982
def set_reference(self, a_bzrdir, to_branch):
2288
def set_reference(self, a_bzrdir, name, to_branch):
1983
2289
"""See BranchFormat.set_reference()."""
1984
transport = a_bzrdir.get_branch_transport(None)
2290
transport = a_bzrdir.get_branch_transport(None, name=name)
1985
2291
location = transport.put_bytes('location', to_branch.base)
1987
def initialize(self, a_bzrdir, target_branch=None):
2293
def initialize(self, a_bzrdir, name=None, target_branch=None,
1988
2295
"""Create a branch of this format in a_bzrdir."""
1989
2296
if target_branch is None:
1990
2297
# this format does not implement branch itself, thus the implicit
1991
2298
# creation contract must see it as uninitializable
1992
2299
raise errors.UninitializableFormat(self)
1993
mutter('creating branch reference in %s', a_bzrdir.transport.base)
1994
branch_transport = a_bzrdir.get_branch_transport(self)
2300
mutter('creating branch reference in %s', a_bzrdir.user_url)
2301
branch_transport = a_bzrdir.get_branch_transport(self, name=name)
1995
2302
branch_transport.put_bytes('location',
1996
target_branch.bzrdir.root_transport.base)
2303
target_branch.bzrdir.user_url)
1997
2304
branch_transport.put_bytes('format', self.get_format_string())
1999
a_bzrdir, _found=True,
2306
a_bzrdir, name, _found=True,
2000
2307
possible_transports=[target_branch.bzrdir.root_transport])
2308
self._run_post_branch_init_hooks(a_bzrdir, name, branch)
2002
2311
def __init__(self):
2003
2312
super(BranchReferenceFormat, self).__init__()
2988
3352
raise NotImplementedError(self.push)
3355
def copy_content_into(self, revision_id=None):
3356
"""Copy the content of source into target
3358
revision_id: if not None, the revision history in the new branch will
3359
be truncated to end with revision_id.
3361
raise NotImplementedError(self.copy_content_into)
2991
3364
class GenericInterBranch(InterBranch):
2992
"""InterBranch implementation that uses public Branch functions.
2996
def _get_branch_formats_to_test():
2997
return BranchFormat._default_format, BranchFormat._default_format
3365
"""InterBranch implementation that uses public Branch functions."""
3368
def is_compatible(klass, source, target):
3369
# GenericBranch uses the public API, so always compatible
3373
def _get_branch_formats_to_test(klass):
3374
return [(BranchFormat._default_format, BranchFormat._default_format)]
3377
def unwrap_format(klass, format):
3378
if isinstance(format, remote.RemoteBranchFormat):
3379
format._ensure_real()
3380
return format._custom_format
3384
def copy_content_into(self, revision_id=None):
3385
"""Copy the content of source into target
3387
revision_id: if not None, the revision history in the new branch will
3388
be truncated to end with revision_id.
3390
self.source.update_references(self.target)
3391
self.source._synchronize_history(self.target, revision_id)
3393
parent = self.source.get_parent()
3394
except errors.InaccessibleParent, e:
3395
mutter('parent was not accessible to copy: %s', e)
3398
self.target.set_parent(parent)
3399
if self.source._push_should_merge_tags():
3400
self.source.tags.merge_to(self.target.tags)
2999
3403
def update_revisions(self, stop_revision=None, overwrite=False,
3001
3405
"""See InterBranch.update_revisions()."""
3002
self.source.lock_read()
3004
other_revno, other_last_revision = self.source.last_revision_info()
3005
stop_revno = None # unknown
3006
if stop_revision is None:
3007
stop_revision = other_last_revision
3008
if _mod_revision.is_null(stop_revision):
3009
# if there are no commits, we're done.
3011
stop_revno = other_revno
3013
# what's the current last revision, before we fetch [and change it
3015
last_rev = _mod_revision.ensure_null(self.target.last_revision())
3016
# we fetch here so that we don't process data twice in the common
3017
# case of having something to pull, and so that the check for
3018
# already merged can operate on the just fetched graph, which will
3019
# be cached in memory.
3020
self.target.fetch(self.source, stop_revision)
3021
# Check to see if one is an ancestor of the other
3024
graph = self.target.repository.get_graph()
3025
if self.target._check_if_descendant_or_diverged(
3026
stop_revision, last_rev, graph, self.source):
3027
# stop_revision is a descendant of last_rev, but we aren't
3028
# overwriting, so we're done.
3030
if stop_revno is None:
3032
graph = self.target.repository.get_graph()
3033
this_revno, this_last_revision = \
3034
self.target.last_revision_info()
3035
stop_revno = graph.find_distance_to_null(stop_revision,
3036
[(other_last_revision, other_revno),
3037
(this_last_revision, this_revno)])
3038
self.target.set_last_revision_info(stop_revno, stop_revision)
3040
self.source.unlock()
3406
other_revno, other_last_revision = self.source.last_revision_info()
3407
stop_revno = None # unknown
3408
if stop_revision is None:
3409
stop_revision = other_last_revision
3410
if _mod_revision.is_null(stop_revision):
3411
# if there are no commits, we're done.
3413
stop_revno = other_revno
3415
# what's the current last revision, before we fetch [and change it
3417
last_rev = _mod_revision.ensure_null(self.target.last_revision())
3418
# we fetch here so that we don't process data twice in the common
3419
# case of having something to pull, and so that the check for
3420
# already merged can operate on the just fetched graph, which will
3421
# be cached in memory.
3422
self.target.fetch(self.source, stop_revision)
3423
# Check to see if one is an ancestor of the other
3426
graph = self.target.repository.get_graph()
3427
if self.target._check_if_descendant_or_diverged(
3428
stop_revision, last_rev, graph, self.source):
3429
# stop_revision is a descendant of last_rev, but we aren't
3430
# overwriting, so we're done.
3432
if stop_revno is None:
3434
graph = self.target.repository.get_graph()
3435
this_revno, this_last_revision = \
3436
self.target.last_revision_info()
3437
stop_revno = graph.find_distance_to_null(stop_revision,
3438
[(other_last_revision, other_revno),
3439
(this_last_revision, this_revno)])
3440
self.target.set_last_revision_info(stop_revno, stop_revision)
3042
3443
def pull(self, overwrite=False, stop_revision=None,
3043
possible_transports=None, _hook_master=None, run_hooks=True,
3444
possible_transports=None, run_hooks=True,
3044
3445
_override_hook_target=None, local=False):
3446
"""Pull from source into self, updating my master if any.
3047
:param _hook_master: Private parameter - set the branch to
3048
be supplied as the master to pull hooks.
3049
3448
:param run_hooks: Private parameter - if false, this branch
3050
3449
is being called because it's the master of the primary branch,
3051
3450
so it should not run its hooks.
3052
:param _override_hook_target: Private parameter - set the branch to be
3053
supplied as the target_branch to pull hooks.
3054
:param local: Only update the local branch, and not the bound branch.
3056
# This type of branch can't be bound.
3452
bound_location = self.target.get_bound_location()
3453
if local and not bound_location:
3058
3454
raise errors.LocalRequiresBoundBranch()
3059
result = PullResult()
3060
result.source_branch = self.source
3061
if _override_hook_target is None:
3062
result.target_branch = self.target
3064
result.target_branch = _override_hook_target
3065
self.source.lock_read()
3455
master_branch = None
3456
if not local and bound_location and self.source.user_url != bound_location:
3457
# not pulling from master, so we need to update master.
3458
master_branch = self.target.get_master_branch(possible_transports)
3459
master_branch.lock_write()
3067
# We assume that during 'pull' the target repository is closer than
3069
self.source.update_references(self.target)
3070
graph = self.target.repository.get_graph(self.source.repository)
3071
# TODO: Branch formats should have a flag that indicates
3072
# that revno's are expensive, and pull() should honor that flag.
3074
result.old_revno, result.old_revid = \
3075
self.target.last_revision_info()
3076
self.target.update_revisions(self.source, stop_revision,
3077
overwrite=overwrite, graph=graph)
3078
# TODO: The old revid should be specified when merging tags,
3079
# so a tags implementation that versions tags can only
3080
# pull in the most recent changes. -- JRV20090506
3081
result.tag_conflicts = self.source.tags.merge_to(self.target.tags,
3083
result.new_revno, result.new_revid = self.target.last_revision_info()
3085
result.master_branch = _hook_master
3086
result.local_branch = result.target_branch
3088
result.master_branch = result.target_branch
3089
result.local_branch = None
3091
for hook in Branch.hooks['post_pull']:
3462
# pull from source into master.
3463
master_branch.pull(self.source, overwrite, stop_revision,
3465
return self._pull(overwrite,
3466
stop_revision, _hook_master=master_branch,
3467
run_hooks=run_hooks,
3468
_override_hook_target=_override_hook_target)
3094
self.source.unlock()
3471
master_branch.unlock()
3097
3473
def push(self, overwrite=False, stop_revision=None,
3098
3474
_override_hook_source_branch=None):
3164
def is_compatible(self, source, target):
3165
# GenericBranch uses the public API, so always compatible
3169
class InterToBranch5(GenericInterBranch):
3172
def _get_branch_formats_to_test():
3173
return BranchFormat._default_format, BzrBranchFormat5()
3175
def pull(self, overwrite=False, stop_revision=None,
3176
possible_transports=None, run_hooks=True,
3539
def _pull(self, overwrite=False, stop_revision=None,
3540
possible_transports=None, _hook_master=None, run_hooks=True,
3177
3541
_override_hook_target=None, local=False):
3178
"""Pull from source into self, updating my master if any.
3544
This function is the core worker, used by GenericInterBranch.pull to
3545
avoid duplication when pulling source->master and source->local.
3547
:param _hook_master: Private parameter - set the branch to
3548
be supplied as the master to pull hooks.
3180
3549
:param run_hooks: Private parameter - if false, this branch
3181
3550
is being called because it's the master of the primary branch,
3182
3551
so it should not run its hooks.
3552
:param _override_hook_target: Private parameter - set the branch to be
3553
supplied as the target_branch to pull hooks.
3554
:param local: Only update the local branch, and not the bound branch.
3184
bound_location = self.target.get_bound_location()
3185
if local and not bound_location:
3556
# This type of branch can't be bound.
3186
3558
raise errors.LocalRequiresBoundBranch()
3187
master_branch = None
3188
if not local and bound_location and self.source.base != bound_location:
3189
# not pulling from master, so we need to update master.
3190
master_branch = self.target.get_master_branch(possible_transports)
3191
master_branch.lock_write()
3559
result = PullResult()
3560
result.source_branch = self.source
3561
if _override_hook_target is None:
3562
result.target_branch = self.target
3564
result.target_branch = _override_hook_target
3565
self.source.lock_read()
3194
# pull from source into master.
3195
master_branch.pull(self.source, overwrite, stop_revision,
3197
return super(InterToBranch5, self).pull(overwrite,
3198
stop_revision, _hook_master=master_branch,
3199
run_hooks=run_hooks,
3200
_override_hook_target=_override_hook_target)
3567
# We assume that during 'pull' the target repository is closer than
3569
self.source.update_references(self.target)
3570
graph = self.target.repository.get_graph(self.source.repository)
3571
# TODO: Branch formats should have a flag that indicates
3572
# that revno's are expensive, and pull() should honor that flag.
3574
result.old_revno, result.old_revid = \
3575
self.target.last_revision_info()
3576
self.target.update_revisions(self.source, stop_revision,
3577
overwrite=overwrite, graph=graph)
3578
# TODO: The old revid should be specified when merging tags,
3579
# so a tags implementation that versions tags can only
3580
# pull in the most recent changes. -- JRV20090506
3581
result.tag_conflicts = self.source.tags.merge_to(self.target.tags,
3583
result.new_revno, result.new_revid = self.target.last_revision_info()
3585
result.master_branch = _hook_master
3586
result.local_branch = result.target_branch
3588
result.master_branch = result.target_branch
3589
result.local_branch = None
3591
for hook in Branch.hooks['post_pull']:
3203
master_branch.unlock()
3594
self.source.unlock()
3206
3598
InterBranch.register_optimiser(GenericInterBranch)
3207
InterBranch.register_optimiser(InterToBranch5)