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.
1041
835
except ValueError:
1042
836
raise errors.NoSuchRevision(self, revision_id)
1045
838
def get_rev_id(self, revno, history=None):
1046
839
"""Find the revision id of the specified revno."""
1048
841
return _mod_revision.NULL_REVISION
1049
last_revno, last_revid = self.last_revision_info()
1050
if revno == last_revno:
1052
if revno <= 0 or revno > last_revno:
843
history = self.revision_history()
844
if revno <= 0 or revno > len(history):
1053
845
raise errors.NoSuchRevision(self, revno)
1054
distance_from_last = last_revno - revno
1055
if len(self._partial_revision_history_cache) <= distance_from_last:
1056
self._extend_partial_history(distance_from_last)
1057
return self._partial_revision_history_cache[distance_from_last]
846
return history[revno - 1]
1059
848
def pull(self, source, overwrite=False, stop_revision=None,
1060
possible_transports=None, *args, **kwargs):
849
possible_transports=None, _override_hook_target=None):
1061
850
"""Mirror source into this branch.
1063
852
This branch is considered to be 'local', having low latency.
1065
854
:returns: PullResult instance
1067
return InterBranch.get(source, self).pull(overwrite=overwrite,
1068
stop_revision=stop_revision,
1069
possible_transports=possible_transports, *args, **kwargs)
856
raise NotImplementedError(self.pull)
1071
def push(self, target, overwrite=False, stop_revision=None, *args,
858
def push(self, target, overwrite=False, stop_revision=None):
1073
859
"""Mirror this branch into target.
1075
861
This branch is considered to be 'local', having low latency.
1077
return InterBranch.get(self, target).push(overwrite, stop_revision,
1080
def lossy_push(self, target, stop_revision=None):
1081
"""Push deltas into another branch.
1083
:note: This does not, like push, retain the revision ids from
1084
the source branch and will, rather than adding bzr-specific
1085
metadata, push only those semantics of the revision that can be
1086
natively represented by this branch' VCS.
1088
:param target: Target branch
1089
:param stop_revision: Revision to push, defaults to last revision.
1090
:return: BranchPushResult with an extra member revidmap:
1091
A dictionary mapping revision ids from the target branch
1092
to new revision ids in the target branch, for each
1093
revision that was pushed.
1095
inter = InterBranch.get(self, target)
1096
lossy_push = getattr(inter, "lossy_push", None)
1097
if lossy_push is None:
1098
raise errors.LossyPushToSameVCS(self, target)
1099
return lossy_push(stop_revision)
863
raise NotImplementedError(self.push)
1101
865
def basis_tree(self):
1102
866
"""Return `Tree` object for last revision."""
1922
1603
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
1606
class BzrBranchFormat4(BranchFormat):
1999
1607
"""Bzr branch format 4.
2248
1846
"""See BranchFormat.get_format_description()."""
2249
1847
return "Checkout reference format 1"
2251
def get_reference(self, a_bzrdir, name=None):
1849
def get_reference(self, a_bzrdir):
2252
1850
"""See BranchFormat.get_reference()."""
2253
transport = a_bzrdir.get_branch_transport(None, name=name)
2254
return transport.get_bytes('location')
1851
transport = a_bzrdir.get_branch_transport(None)
1852
return transport.get('location').read()
2256
def set_reference(self, a_bzrdir, name, to_branch):
1854
def set_reference(self, a_bzrdir, to_branch):
2257
1855
"""See BranchFormat.set_reference()."""
2258
transport = a_bzrdir.get_branch_transport(None, name=name)
1856
transport = a_bzrdir.get_branch_transport(None)
2259
1857
location = transport.put_bytes('location', to_branch.base)
2261
def initialize(self, a_bzrdir, name=None, target_branch=None):
1859
def initialize(self, a_bzrdir, target_branch=None):
2262
1860
"""Create a branch of this format in a_bzrdir."""
2263
1861
if target_branch is None:
2264
1862
# this format does not implement branch itself, thus the implicit
2265
1863
# creation contract must see it as uninitializable
2266
1864
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)
1865
mutter('creating branch reference in %s', a_bzrdir.transport.base)
1866
branch_transport = a_bzrdir.get_branch_transport(self)
2269
1867
branch_transport.put_bytes('location',
2270
target_branch.bzrdir.user_url)
1868
target_branch.bzrdir.root_transport.base)
2271
1869
branch_transport.put_bytes('format', self.get_format_string())
2273
a_bzrdir, name, _found=True,
1871
a_bzrdir, _found=True,
2274
1872
possible_transports=[target_branch.bzrdir.root_transport])
2275
self._run_post_branch_init_hooks(a_bzrdir, name, branch)
2278
1874
def __init__(self):
2279
1875
super(BranchReferenceFormat, self).__init__()
2224
def push(self, target, overwrite=False, stop_revision=None,
2225
_override_hook_source_branch=None):
2228
This is the basic concrete implementation of push()
2230
:param _override_hook_source_branch: If specified, run
2231
the hooks passing this Branch as the source, rather than self.
2232
This is for use of RemoteBranch, where push is delegated to the
2233
underlying vfs-based Branch.
2235
# TODO: Public option to disable running hooks - should be trivial but
2237
return _run_with_write_locked_target(
2238
target, self._push_with_bound_branches, target, overwrite,
2240
_override_hook_source_branch=_override_hook_source_branch)
2242
def _push_with_bound_branches(self, target, overwrite,
2244
_override_hook_source_branch=None):
2245
"""Push from self into target, and into target's master if any.
2247
This is on the base BzrBranch class even though it doesn't support
2248
bound branches because the *target* might be bound.
2251
if _override_hook_source_branch:
2252
result.source_branch = _override_hook_source_branch
2253
for hook in Branch.hooks['post_push']:
2256
bound_location = target.get_bound_location()
2257
if bound_location and target.base != bound_location:
2258
# there is a master branch.
2260
# XXX: Why the second check? Is it even supported for a branch to
2261
# be bound to itself? -- mbp 20070507
2262
master_branch = target.get_master_branch()
2263
master_branch.lock_write()
2265
# push into the master from this branch.
2266
self._basic_push(master_branch, overwrite, stop_revision)
2267
# and push into the target branch from this. Note that we push from
2268
# this branch again, because its considered the highest bandwidth
2270
result = self._basic_push(target, overwrite, stop_revision)
2271
result.master_branch = master_branch
2272
result.local_branch = target
2276
master_branch.unlock()
2279
result = self._basic_push(target, overwrite, stop_revision)
2280
# TODO: Why set master_branch and local_branch if there's no
2281
# binding? Maybe cleaner to just leave them unset? -- mbp
2283
result.master_branch = target
2284
result.local_branch = None
2628
2288
def _basic_push(self, target, overwrite, stop_revision):
2629
2289
"""Basic implementation of push without bound branches or hooks.
2631
Must be called with source read locked and target write locked.
2291
Must be called with self read locked and target write locked.
2633
2293
result = BranchPushResult()
2634
2294
result.source_branch = self
3309
3009
raise NotImplementedError(self.update_revisions)
3312
def push(self, overwrite=False, stop_revision=None,
3313
_override_hook_source_branch=None):
3314
"""Mirror the source branch into the target branch.
3316
The source branch is considered to be 'local', having low latency.
3318
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
3012
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)
3013
"""InterBranch implementation that uses public Branch functions.
3017
def _get_branch_formats_to_test():
3018
return BranchFormat._default_format, BranchFormat._default_format
3369
3020
def update_revisions(self, stop_revision=None, overwrite=False,
3371
3022
"""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)
3409
def pull(self, overwrite=False, stop_revision=None,
3410
possible_transports=None, run_hooks=True,
3411
_override_hook_target=None, local=False):
3412
"""Pull from source into self, updating my master if any.
3414
:param run_hooks: Private parameter - if false, this branch
3415
is being called because it's the master of the primary branch,
3416
so it should not run its hooks.
3418
bound_location = self.target.get_bound_location()
3419
if local and not bound_location:
3420
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()
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)
3437
master_branch.unlock()
3439
def push(self, overwrite=False, stop_revision=None,
3440
_override_hook_source_branch=None):
3441
"""See InterBranch.push.
3443
This is the basic concrete implementation of push()
3445
:param _override_hook_source_branch: If specified, run
3446
the hooks passing this Branch as the source, rather than self.
3447
This is for use of RemoteBranch, where push is delegated to the
3448
underlying vfs-based Branch.
3450
# TODO: Public option to disable running hooks - should be trivial but
3452
self.source.lock_read()
3454
return _run_with_write_locked_target(
3455
self.target, self._push_with_bound_branches, overwrite,
3457
_override_hook_source_branch=_override_hook_source_branch)
3459
self.source.unlock()
3461
def _push_with_bound_branches(self, overwrite, stop_revision,
3462
_override_hook_source_branch=None):
3463
"""Push from source into target, and into target's master if any.
3466
if _override_hook_source_branch:
3467
result.source_branch = _override_hook_source_branch
3468
for hook in Branch.hooks['post_push']:
3471
bound_location = self.target.get_bound_location()
3472
if bound_location and self.target.base != bound_location:
3473
# there is a master branch.
3475
# XXX: Why the second check? Is it even supported for a branch to
3476
# be bound to itself? -- mbp 20070507
3477
master_branch = self.target.get_master_branch()
3478
master_branch.lock_write()
3480
# push into the master from the source branch.
3481
self.source._basic_push(master_branch, overwrite, stop_revision)
3482
# and push into the target branch from the source. Note that we
3483
# push from the source branch again, because it's considered the
3484
# highest bandwidth repository.
3485
result = self.source._basic_push(self.target, overwrite,
3487
result.master_branch = master_branch
3488
result.local_branch = self.target
3492
master_branch.unlock()
3495
result = self.source._basic_push(self.target, overwrite,
3497
# TODO: Why set master_branch and local_branch if there's no
3498
# binding? Maybe cleaner to just leave them unset? -- mbp
3500
result.master_branch = self.target
3501
result.local_branch = None
3505
def _pull(self, overwrite=False, stop_revision=None,
3506
possible_transports=None, _hook_master=None, run_hooks=True,
3507
_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.
3515
:param run_hooks: Private parameter - if false, this branch
3516
is being called because it's the master of the primary branch,
3517
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.
3524
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()
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']:
3560
self.source.unlock()
3023
self.source.lock_read()
3025
other_revno, other_last_revision = self.source.last_revision_info()
3026
stop_revno = None # unknown
3027
if stop_revision is None:
3028
stop_revision = other_last_revision
3029
if _mod_revision.is_null(stop_revision):
3030
# if there are no commits, we're done.
3032
stop_revno = other_revno
3034
# what's the current last revision, before we fetch [and change it
3036
last_rev = _mod_revision.ensure_null(self.target.last_revision())
3037
# we fetch here so that we don't process data twice in the common
3038
# case of having something to pull, and so that the check for
3039
# already merged can operate on the just fetched graph, which will
3040
# be cached in memory.
3041
self.target.fetch(self.source, stop_revision)
3042
# Check to see if one is an ancestor of the other
3045
graph = self.target.repository.get_graph()
3046
if self.target._check_if_descendant_or_diverged(
3047
stop_revision, last_rev, graph, self.source):
3048
# stop_revision is a descendant of last_rev, but we aren't
3049
# overwriting, so we're done.
3051
if stop_revno is None:
3053
graph = self.target.repository.get_graph()
3054
this_revno, this_last_revision = \
3055
self.target.last_revision_info()
3056
stop_revno = graph.find_distance_to_null(stop_revision,
3057
[(other_last_revision, other_revno),
3058
(this_last_revision, this_revno)])
3059
self.target.set_last_revision_info(stop_revno, stop_revision)
3061
self.source.unlock()
3064
def is_compatible(self, source, target):
3065
# GenericBranch uses the public API, so always compatible
3564
3069
InterBranch.register_optimiser(GenericInterBranch)