491
442
"""Iterate over an inclusive range of sorted revisions."""
492
443
rev_iter = iter(merge_sorted_revisions)
493
444
if start_revision_id is not None:
494
for node in rev_iter:
495
rev_id = node.key[-1]
445
for rev_id, depth, revno, end_of_merge in rev_iter:
496
446
if rev_id != start_revision_id:
499
449
# The decision to include the start or not
500
450
# depends on the stop_rule if a stop is provided
501
# so pop this node back into the iterator
502
rev_iter = chain(iter([node]), rev_iter)
452
iter([(rev_id, depth, revno, end_of_merge)]),
504
455
if stop_revision_id is None:
506
for node in rev_iter:
507
rev_id = node.key[-1]
508
yield (rev_id, node.merge_depth, node.revno,
456
for rev_id, depth, revno, end_of_merge in rev_iter:
457
yield rev_id, depth, revno, end_of_merge
510
458
elif stop_rule == 'exclude':
511
for node in rev_iter:
512
rev_id = node.key[-1]
459
for rev_id, depth, revno, end_of_merge in rev_iter:
513
460
if rev_id == stop_revision_id:
515
yield (rev_id, node.merge_depth, node.revno,
462
yield rev_id, depth, revno, end_of_merge
517
463
elif stop_rule == 'include':
518
for node in rev_iter:
519
rev_id = node.key[-1]
520
yield (rev_id, node.merge_depth, node.revno,
464
for rev_id, depth, revno, end_of_merge in rev_iter:
465
yield rev_id, depth, revno, end_of_merge
522
466
if rev_id == stop_revision_id:
524
elif stop_rule == 'with-merges-without-common-ancestry':
525
# We want to exclude all revisions that are already part of the
526
# stop_revision_id ancestry.
527
graph = self.repository.get_graph()
528
ancestors = graph.find_unique_ancestors(start_revision_id,
530
for node in rev_iter:
531
rev_id = node.key[-1]
532
if rev_id not in ancestors:
534
yield (rev_id, node.merge_depth, node.revno,
536
468
elif stop_rule == 'with-merges':
537
469
stop_rev = self.repository.get_revision(stop_revision_id)
538
470
if stop_rev.parent_ids:
539
471
left_parent = stop_rev.parent_ids[0]
541
473
left_parent = _mod_revision.NULL_REVISION
542
# left_parent is the actual revision we want to stop logging at,
543
# since we want to show the merged revisions after the stop_rev too
544
reached_stop_revision_id = False
545
revision_id_whitelist = []
546
for node in rev_iter:
547
rev_id = node.key[-1]
474
for rev_id, depth, revno, end_of_merge in rev_iter:
548
475
if rev_id == left_parent:
549
# reached the left parent after the stop_revision
551
if (not reached_stop_revision_id or
552
rev_id in revision_id_whitelist):
553
yield (rev_id, node.merge_depth, node.revno,
555
if reached_stop_revision_id or rev_id == stop_revision_id:
556
# only do the merged revs of rev_id from now on
557
rev = self.repository.get_revision(rev_id)
559
reached_stop_revision_id = True
560
revision_id_whitelist.extend(rev.parent_ids)
477
yield rev_id, depth, revno, end_of_merge
562
479
raise ValueError('invalid stop_rule %r' % stop_rule)
564
def _filter_start_non_ancestors(self, rev_iter):
565
# If we started from a dotted revno, we want to consider it as a tip
566
# and don't want to yield revisions that are not part of its
567
# ancestry. Given the order guaranteed by the merge sort, we will see
568
# uninteresting descendants of the first parent of our tip before the
570
first = rev_iter.next()
571
(rev_id, merge_depth, revno, end_of_merge) = first
574
# We start at a mainline revision so by definition, all others
575
# revisions in rev_iter are ancestors
576
for node in rev_iter:
581
pmap = self.repository.get_parent_map([rev_id])
582
parents = pmap.get(rev_id, [])
584
whitelist.update(parents)
586
# If there is no parents, there is nothing of interest left
588
# FIXME: It's hard to test this scenario here as this code is never
589
# called in that case. -- vila 20100322
592
for (rev_id, merge_depth, revno, end_of_merge) in rev_iter:
594
if rev_id in whitelist:
595
pmap = self.repository.get_parent_map([rev_id])
596
parents = pmap.get(rev_id, [])
597
whitelist.remove(rev_id)
598
whitelist.update(parents)
600
# We've reached the mainline, there is nothing left to
604
# A revision that is not part of the ancestry of our
607
yield (rev_id, merge_depth, revno, end_of_merge)
609
481
def leave_lock_in_place(self):
610
482
"""Tell this branch object not to release the physical lock when this
611
483
object is unlocked.
781
640
except (errors.NotStacked, errors.UnstackableBranchFormat,
782
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,
786
self._activate_fallback_location(url)
659
self._activate_fallback_location(url, 'write')
787
660
# write this out after the repository is stacked to avoid setting a
788
661
# stacked config that doesn't work.
789
662
self._set_config_location('stacked_on_location', url)
792
"""Change a branch to be unstacked, copying data as needed.
794
Don't call this directly, use set_stacked_on_url(None).
796
pb = ui.ui_factory.nested_progress_bar()
798
pb.update("Unstacking")
799
# The basic approach here is to fetch the tip of the branch,
800
# including all available ghosts, from the existing stacked
801
# repository into a new repository object without the fallbacks.
803
# XXX: See <https://launchpad.net/bugs/397286> - this may not be
804
# correct for CHKMap repostiories
805
old_repository = self.repository
806
if len(old_repository._fallback_repositories) != 1:
807
raise AssertionError("can't cope with fallback repositories "
808
"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()
836
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):
855
self.repository.lock_write()
856
# Fetch from the old repository into the new.
857
old_repository.lock_read()
859
# XXX: If you unstack a branch while it has a working tree
860
# with a pending merge, the pending-merged revisions will no
861
# longer be present. You can (probably) revert and remerge.
863
# XXX: This only fetches up to the tip of the repository; it
864
# doesn't bring across any tags. That's fairly consistent
865
# with how branch works, but perhaps not ideal.
866
self.repository.fetch(old_repository,
867
revision_id=self.last_revision(),
870
old_repository.unlock()
874
665
def _set_tags_bytes(self, bytes):
875
666
"""Mirror method for _get_tags_bytes.
1294
1084
source_revno, source_revision_id = self.last_revision_info()
1295
1085
if revision_id is None:
1296
1086
revno, revision_id = source_revno, source_revision_id
1087
elif source_revision_id == revision_id:
1088
# we know the revno without needing to walk all of history
1089
revno = source_revno
1298
graph = self.repository.get_graph()
1300
revno = graph.find_distance_to_null(revision_id,
1301
[(source_revision_id, source_revno)])
1302
except errors.GhostRevisionsHaveNoRevno:
1303
# Default to 1, if we can't find anything else
1091
# To figure out the revno for a random revision, we need to build
1092
# the revision history, and count its length.
1093
# We don't care about the order, just how long it is.
1094
# Alternatively, we could start at the current location, and count
1095
# backwards. But there is no guarantee that we will find it since
1096
# it may be a merged revision.
1097
revno = len(list(self.repository.iter_reverse_revision_history(
1305
1099
destination.set_last_revision_info(revno, revision_id)
1307
1102
def copy_content_into(self, destination, revision_id=None):
1308
1103
"""Copy the content of self into destination.
1310
1105
revision_id: if not None, the revision history in the new branch will
1311
1106
be truncated to end with revision_id.
1313
return InterBranch.get(self, destination).copy_content_into(
1314
revision_id=revision_id)
1108
self.update_references(destination)
1109
self._synchronize_history(destination, revision_id)
1111
parent = self.get_parent()
1112
except errors.InaccessibleParent, e:
1113
mutter('parent was not accessible to copy: %s', e)
1116
destination.set_parent(parent)
1117
if self._push_should_merge_tags():
1118
self.tags.merge_to(destination.tags)
1316
1120
def update_references(self, target):
1317
1121
if not getattr(self._format, 'supports_reference_locations', False):
1341
1145
Callers will typically also want to check the repository.
1343
:param refs: Calculated refs for this branch as specified by
1344
branch._get_check_refs()
1345
1147
:return: A BranchCheckResult.
1347
result = BranchCheckResult(self)
1149
mainline_parent_id = None
1348
1150
last_revno, last_revision_id = self.last_revision_info()
1349
actual_revno = refs[('lefthand-distance', last_revision_id)]
1350
if actual_revno != last_revno:
1351
result.errors.append(errors.BzrCheckError(
1352
'revno does not match len(mainline) %s != %s' % (
1353
last_revno, actual_revno)))
1354
# TODO: We should probably also check that self.revision_history
1355
# matches the repository for older branch formats.
1356
# If looking for the code that cross-checks repository parents against
1357
# the iter_reverse_revision_history output, that is now a repository
1151
real_rev_history = list(self.repository.iter_reverse_revision_history(
1153
real_rev_history.reverse()
1154
if len(real_rev_history) != last_revno:
1155
raise errors.BzrCheckError('revno does not match len(mainline)'
1156
' %s != %s' % (last_revno, len(real_rev_history)))
1157
# TODO: We should probably also check that real_rev_history actually
1158
# matches self.revision_history()
1159
for revision_id in real_rev_history:
1161
revision = self.repository.get_revision(revision_id)
1162
except errors.NoSuchRevision, e:
1163
raise errors.BzrCheckError("mainline revision {%s} not in repository"
1165
# In general the first entry on the revision history has no parents.
1166
# But it's not illegal for it to have parents listed; this can happen
1167
# in imports from Arch when the parents weren't reachable.
1168
if mainline_parent_id is not None:
1169
if mainline_parent_id not in revision.parent_ids:
1170
raise errors.BzrCheckError("previous revision {%s} not listed among "
1172
% (mainline_parent_id, revision_id))
1173
mainline_parent_id = revision_id
1174
return BranchCheckResult(self)
1361
1176
def _get_checkout_format(self):
1362
1177
"""Return the most suitable metadir for a checkout of this branch.
1614
1400
"""Return the short format description for this format."""
1615
1401
raise NotImplementedError(self.get_format_description)
1617
def _run_post_branch_init_hooks(self, a_bzrdir, name, branch):
1618
hooks = Branch.hooks['post_branch_init']
1621
params = BranchInitHookParams(self, a_bzrdir, name, branch)
1625
def _initialize_helper(self, a_bzrdir, utf8_files, name=None,
1626
lock_type='metadir', set_format=True):
1403
def _initialize_helper(self, a_bzrdir, utf8_files, lock_type='metadir',
1627
1405
"""Initialize a branch in a bzrdir, with specified files
1629
1407
:param a_bzrdir: The bzrdir to initialize the branch in
1630
1408
:param utf8_files: The files to create as a list of
1631
1409
(filename, content) tuples
1632
:param name: Name of colocated branch to create, if any
1633
1410
:param set_format: If True, set the format with
1634
1411
self.get_format_string. (BzrBranch4 has its format set
1636
1413
:return: a branch in this format
1638
mutter('creating branch %r in %s', self, a_bzrdir.user_url)
1639
branch_transport = a_bzrdir.get_branch_transport(self, name=name)
1415
mutter('creating branch %r in %s', self, a_bzrdir.transport.base)
1416
branch_transport = a_bzrdir.get_branch_transport(self)
1641
1418
'metadir': ('lock', lockdir.LockDir),
1642
1419
'branch4': ('branch-lock', lockable_files.TransportLock),
1922
1636
self.old_revno, self.old_revid, self.new_revno, self.new_revid)
1925
class BranchInitHookParams(object):
1926
"""Object holding parameters passed to *_branch_init hooks.
1928
There are 4 fields that hooks may wish to access:
1930
:ivar format: the branch format
1931
:ivar bzrdir: the BzrDir where the branch will be/has been initialized
1932
:ivar name: name of colocated branch, if any (or None)
1933
:ivar branch: the branch created
1935
Note that for lightweight checkouts, the bzrdir and format fields refer to
1936
the checkout, hence they are different from the corresponding fields in
1937
branch, which refer to the original branch.
1940
def __init__(self, format, a_bzrdir, name, branch):
1941
"""Create a group of BranchInitHook parameters.
1943
:param format: the branch format
1944
:param a_bzrdir: the BzrDir where the branch will be/has been
1946
:param name: name of colocated branch, if any (or None)
1947
:param branch: the branch created
1949
Note that for lightweight checkouts, the bzrdir and format fields refer
1950
to the checkout, hence they are different from the corresponding fields
1951
in branch, which refer to the original branch.
1953
self.format = format
1954
self.bzrdir = a_bzrdir
1956
self.branch = branch
1958
def __eq__(self, other):
1959
return self.__dict__ == other.__dict__
1962
return "<%s of %s>" % (self.__class__.__name__, self.branch)
1965
class SwitchHookParams(object):
1966
"""Object holding parameters passed to *_switch hooks.
1968
There are 4 fields that hooks may wish to access:
1970
:ivar control_dir: BzrDir of the checkout to change
1971
:ivar to_branch: branch that the checkout is to reference
1972
:ivar force: skip the check for local commits in a heavy checkout
1973
:ivar revision_id: revision ID to switch to (or None)
1976
def __init__(self, control_dir, to_branch, force, revision_id):
1977
"""Create a group of SwitchHook parameters.
1979
:param control_dir: BzrDir of the checkout to change
1980
:param to_branch: branch that the checkout is to reference
1981
:param force: skip the check for local commits in a heavy checkout
1982
:param revision_id: revision ID to switch to (or None)
1984
self.control_dir = control_dir
1985
self.to_branch = to_branch
1987
self.revision_id = revision_id
1989
def __eq__(self, other):
1990
return self.__dict__ == other.__dict__
1993
return "<%s for %s to (%s, %s)>" % (self.__class__.__name__,
1994
self.control_dir, self.to_branch,
1998
1639
class BzrBranchFormat4(BranchFormat):
1999
1640
"""Bzr branch format 4.
2248
1879
"""See BranchFormat.get_format_description()."""
2249
1880
return "Checkout reference format 1"
2251
def get_reference(self, a_bzrdir, name=None):
1882
def get_reference(self, a_bzrdir):
2252
1883
"""See BranchFormat.get_reference()."""
2253
transport = a_bzrdir.get_branch_transport(None, name=name)
2254
return transport.get_bytes('location')
1884
transport = a_bzrdir.get_branch_transport(None)
1885
return transport.get('location').read()
2256
def set_reference(self, a_bzrdir, name, to_branch):
1887
def set_reference(self, a_bzrdir, to_branch):
2257
1888
"""See BranchFormat.set_reference()."""
2258
transport = a_bzrdir.get_branch_transport(None, name=name)
1889
transport = a_bzrdir.get_branch_transport(None)
2259
1890
location = transport.put_bytes('location', to_branch.base)
2261
def initialize(self, a_bzrdir, name=None, target_branch=None):
1892
def initialize(self, a_bzrdir, target_branch=None):
2262
1893
"""Create a branch of this format in a_bzrdir."""
2263
1894
if target_branch is None:
2264
1895
# this format does not implement branch itself, thus the implicit
2265
1896
# creation contract must see it as uninitializable
2266
1897
raise errors.UninitializableFormat(self)
2267
mutter('creating branch reference in %s', a_bzrdir.user_url)
2268
branch_transport = a_bzrdir.get_branch_transport(self, name=name)
1898
mutter('creating branch reference in %s', a_bzrdir.transport.base)
1899
branch_transport = a_bzrdir.get_branch_transport(self)
2269
1900
branch_transport.put_bytes('location',
2270
target_branch.bzrdir.user_url)
1901
target_branch.bzrdir.root_transport.base)
2271
1902
branch_transport.put_bytes('format', self.get_format_string())
2273
a_bzrdir, name, _found=True,
1904
a_bzrdir, _found=True,
2274
1905
possible_transports=[target_branch.bzrdir.root_transport])
2275
self._run_post_branch_init_hooks(a_bzrdir, name, branch)
2278
1907
def __init__(self):
2279
1908
super(BranchReferenceFormat, self).__init__()
3318
2923
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
2926
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)
2927
"""InterBranch implementation that uses public Branch functions.
2931
def _get_branch_formats_to_test():
2932
return BranchFormat._default_format, BranchFormat._default_format
3369
2934
def update_revisions(self, stop_revision=None, overwrite=False,
3371
2936
"""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)
2937
self.source.lock_read()
2939
other_revno, other_last_revision = self.source.last_revision_info()
2940
stop_revno = None # unknown
2941
if stop_revision is None:
2942
stop_revision = other_last_revision
2943
if _mod_revision.is_null(stop_revision):
2944
# if there are no commits, we're done.
2946
stop_revno = other_revno
2948
# what's the current last revision, before we fetch [and change it
2950
last_rev = _mod_revision.ensure_null(self.target.last_revision())
2951
# we fetch here so that we don't process data twice in the common
2952
# case of having something to pull, and so that the check for
2953
# already merged can operate on the just fetched graph, which will
2954
# be cached in memory.
2955
self.target.fetch(self.source, stop_revision)
2956
# Check to see if one is an ancestor of the other
2959
graph = self.target.repository.get_graph()
2960
if self.target._check_if_descendant_or_diverged(
2961
stop_revision, last_rev, graph, self.source):
2962
# stop_revision is a descendant of last_rev, but we aren't
2963
# overwriting, so we're done.
2965
if stop_revno is None:
2967
graph = self.target.repository.get_graph()
2968
this_revno, this_last_revision = \
2969
self.target.last_revision_info()
2970
stop_revno = graph.find_distance_to_null(stop_revision,
2971
[(other_last_revision, other_revno),
2972
(this_last_revision, this_revno)])
2973
self.target.set_last_revision_info(stop_revno, stop_revision)
2975
self.source.unlock()
3409
2977
def pull(self, overwrite=False, stop_revision=None,
3410
possible_transports=None, run_hooks=True,
2978
possible_transports=None, _hook_master=None, run_hooks=True,
3411
2979
_override_hook_target=None, local=False):
3412
"""Pull from source into self, updating my master if any.
2982
:param _hook_master: Private parameter - set the branch to
2983
be supplied as the master to pull hooks.
3414
2984
:param run_hooks: Private parameter - if false, this branch
3415
2985
is being called because it's the master of the primary branch,
3416
2986
so it should not run its hooks.
2987
:param _override_hook_target: Private parameter - set the branch to be
2988
supplied as the target_branch to pull hooks.
2989
: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:
2991
# This type of branch can't be bound.
3420
2993
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()
2994
result = PullResult()
2995
result.source_branch = self.source
2996
if _override_hook_target is None:
2997
result.target_branch = self.target
2999
result.target_branch = _override_hook_target
3000
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)
3002
# We assume that during 'pull' the target repository is closer than
3004
self.source.update_references(self.target)
3005
graph = self.target.repository.get_graph(self.source.repository)
3006
# TODO: Branch formats should have a flag that indicates
3007
# that revno's are expensive, and pull() should honor that flag.
3009
result.old_revno, result.old_revid = \
3010
self.target.last_revision_info()
3011
self.target.update_revisions(self.source, stop_revision,
3012
overwrite=overwrite, graph=graph)
3013
# TODO: The old revid should be specified when merging tags,
3014
# so a tags implementation that versions tags can only
3015
# pull in the most recent changes. -- JRV20090506
3016
result.tag_conflicts = self.source.tags.merge_to(self.target.tags,
3018
result.new_revno, result.new_revid = self.target.last_revision_info()
3020
result.master_branch = _hook_master
3021
result.local_branch = result.target_branch
3023
result.master_branch = result.target_branch
3024
result.local_branch = None
3026
for hook in Branch.hooks['post_pull']:
3437
master_branch.unlock()
3029
self.source.unlock()
3439
3032
def push(self, overwrite=False, stop_revision=None,
3440
3033
_override_hook_source_branch=None):
3505
def _pull(self, overwrite=False, stop_revision=None,
3506
possible_transports=None, _hook_master=None, run_hooks=True,
3100
def is_compatible(self, source, target):
3101
# GenericBranch uses the public API, so always compatible
3105
class InterToBranch5(GenericInterBranch):
3108
def _get_branch_formats_to_test():
3109
return BranchFormat._default_format, BzrBranchFormat5()
3111
def pull(self, overwrite=False, stop_revision=None,
3112
possible_transports=None, run_hooks=True,
3507
3113
_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.
3114
"""Pull from source into self, updating my master if any.
3515
3116
:param run_hooks: Private parameter - if false, this branch
3516
3117
is being called because it's the master of the primary branch,
3517
3118
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.
3120
bound_location = self.target.get_bound_location()
3121
if local and not bound_location:
3524
3122
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()
3123
master_branch = None
3124
if not local and bound_location and self.source.base != bound_location:
3125
# not pulling from master, so we need to update master.
3126
master_branch = self.target.get_master_branch(possible_transports)
3127
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']:
3130
# pull from source into master.
3131
master_branch.pull(self.source, overwrite, stop_revision,
3133
return super(InterToBranch5, self).pull(overwrite,
3134
stop_revision, _hook_master=master_branch,
3135
run_hooks=run_hooks,
3136
_override_hook_target=_override_hook_target)
3560
self.source.unlock()
3139
master_branch.unlock()
3564
3142
InterBranch.register_optimiser(GenericInterBranch)
3143
InterBranch.register_optimiser(InterToBranch5)