669
669
raise errors.UnsupportedOperation(self.get_reference_info, self)
671
671
@needs_write_lock
672
def fetch(self, from_branch, last_revision=None):
672
def fetch(self, from_branch, last_revision=None, fetch_spec=None):
673
673
"""Copy revisions from from_branch into this branch.
675
675
:param from_branch: Where to copy from.
676
676
:param last_revision: What revision to stop at (None for at the end
678
:param fetch_spec: If specified, a SearchResult or
679
PendingAncestryResult that describes which revisions to copy. This
680
allows copying multiple heads at once. Mutually exclusive with
680
return InterBranch.get(from_branch, self).fetch(last_revision)
684
return InterBranch.get(from_branch, self).fetch(last_revision,
682
687
def get_bound_location(self):
683
688
"""Return the URL of the branch we are bound to.
995
1000
return (0, _mod_revision.NULL_REVISION)
1002
def update_revisions(self, other, stop_revision=None, overwrite=False,
1003
graph=None, fetch_tags=True):
1004
"""Pull in new perfect-fit revisions.
1006
:param other: Another Branch to pull from
1007
:param stop_revision: Updated until the given revision
1008
:param overwrite: Always set the branch pointer, rather than checking
1009
to see if it is a proper descendant.
1010
:param graph: A Graph object that can be used to query history
1011
information. This can be None.
1012
:param fetch_tags: Flag that specifies if tags from other should be
1016
return InterBranch.get(other, self).update_revisions(stop_revision,
1017
overwrite, graph, fetch_tags=fetch_tags)
997
1019
@deprecated_method(deprecated_in((2, 4, 0)))
998
1020
def import_last_revision_info(self, source_repo, revno, revid):
999
1021
"""Set the last revision info, importing from another repo if necessary.
1023
1045
(should only be different from the arguments when lossy=True)
1025
1047
if not self.repository.has_same_location(source.repository):
1026
self.fetch(source, revid)
1049
tags_to_fetch = set(source.tags.get_reverse_tag_dict())
1050
except errors.TagsNotSupported:
1051
tags_to_fetch = set()
1052
fetch_spec = _mod_graph.NotInOtherForRevs(self.repository,
1053
source.repository, [revid],
1054
if_present_ids=tags_to_fetch).execute()
1055
self.repository.fetch(source.repository, fetch_spec=fetch_spec)
1027
1056
self.set_last_revision_info(revno, revid)
1028
1057
return (revno, revid)
2482
2511
'revision-history', '\n'.join(history),
2483
2512
mode=self.bzrdir._get_file_mode())
2485
@deprecated_method(deprecated_in((2, 4, 0)))
2486
2515
def set_revision_history(self, rev_history):
2487
2516
"""See Branch.set_revision_history."""
2488
self._set_revision_history(rev_history)
2491
def _set_revision_history(self, rev_history):
2492
2517
if 'evil' in debug.debug_flags:
2493
2518
mutter_callsite(3, "set_revision_history scales with history.")
2494
2519
check_not_reserved_id = _mod_revision.check_not_reserved_id
2538
2563
except ValueError:
2539
2564
rev = self.repository.get_revision(revision_id)
2540
2565
new_history = rev.get_history(self.repository)[1:]
2541
destination._set_revision_history(new_history)
2566
destination.set_revision_history(new_history)
2543
2568
@needs_write_lock
2544
2569
def set_last_revision_info(self, revno, revision_id):
2552
2577
configured to check constraints on history, in which case this may not
2555
if not revision_id or not isinstance(revision_id, basestring):
2556
raise errors.InvalidRevisionId(revision_id=revision_id, branch=self)
2580
revision_id = _mod_revision.ensure_null(revision_id)
2557
2581
# this old format stores the full history, but this api doesn't
2558
2582
# provide it, so we must generate, and might as well check it's
2560
2584
history = self._lefthand_history(revision_id)
2561
2585
if len(history) != revno:
2562
2586
raise AssertionError('%d != %d' % (len(history), revno))
2563
self._set_revision_history(history)
2587
self.set_revision_history(history)
2565
2589
def _gen_revision_history(self):
2566
2590
history = self._transport.get_bytes('revision-history').split('\n')
2623
def _basic_push(self, target, overwrite, stop_revision):
2624
"""Basic implementation of push without bound branches or hooks.
2626
Must be called with source read locked and target write locked.
2628
result = BranchPushResult()
2629
result.source_branch = self
2630
result.target_branch = target
2631
result.old_revno, result.old_revid = target.last_revision_info()
2632
self.update_references(target)
2633
if result.old_revid != stop_revision:
2634
# We assume that during 'push' this repository is closer than
2636
graph = self.repository.get_graph(target.repository)
2637
target.update_revisions(self, stop_revision,
2638
overwrite=overwrite, graph=graph)
2639
if self._push_should_merge_tags():
2640
result.tag_conflicts = self.tags.merge_to(target.tags, overwrite)
2641
result.new_revno, result.new_revid = target.last_revision_info()
2599
2644
def get_stacked_on_url(self):
2600
2645
raise errors.UnstackableBranchFormat(self._format, self.user_url)
2769
2814
@needs_write_lock
2770
2815
def set_last_revision_info(self, revno, revision_id):
2771
if not revision_id or not isinstance(revision_id, basestring):
2772
raise errors.InvalidRevisionId(revision_id=revision_id, branch=self)
2816
revision_id = _mod_revision.ensure_null(revision_id)
2773
2817
old_revno, old_revid = self.last_revision_info()
2774
2818
if self._get_append_revisions_only():
2775
2819
self._check_history_violation(revision_id)
3251
3295
raise NotImplementedError(self.pull)
3253
3297
@needs_write_lock
3298
def update_revisions(self, stop_revision=None, overwrite=False,
3299
graph=None, fetch_tags=True):
3300
"""Pull in new perfect-fit revisions.
3302
:param stop_revision: Updated until the given revision
3303
:param overwrite: Always set the branch pointer, rather than checking
3304
to see if it is a proper descendant.
3305
:param graph: A Graph object that can be used to query history
3306
information. This can be None.
3307
:param fetch_tags: Flag that specifies if tags from source should be
3311
raise NotImplementedError(self.update_revisions)
3254
3314
def push(self, overwrite=False, stop_revision=None,
3255
3315
_override_hook_source_branch=None):
3256
3316
"""Mirror the source branch into the target branch.
3269
3329
raise NotImplementedError(self.copy_content_into)
3271
3331
@needs_write_lock
3272
def fetch(self, stop_revision=None):
3332
def fetch(self, stop_revision=None, fetch_spec=None):
3273
3333
"""Fetch revisions.
3275
3335
:param stop_revision: Last revision to fetch
3336
:param fetch_spec: Fetch spec.
3277
3338
raise NotImplementedError(self.fetch)
3316
3377
self.source.tags.merge_to(self.target.tags)
3318
3379
@needs_write_lock
3319
def fetch(self, stop_revision=None):
3380
def fetch(self, stop_revision=None, fetch_spec=None):
3381
if fetch_spec is not None and stop_revision is not None:
3382
raise AssertionError(
3383
"fetch_spec and last_revision are mutually exclusive.")
3320
3384
if self.target.base == self.source.base:
3322
3386
self.source.lock_read()
3324
fetch_spec_factory = fetch.FetchSpecFactory()
3325
fetch_spec_factory.source_branch = self.source
3326
fetch_spec_factory.source_branch_stop_revision_id = stop_revision
3327
fetch_spec_factory.source_repo = self.source.repository
3328
fetch_spec_factory.target_repo = self.target.repository
3329
fetch_spec_factory.target_repo_kind = fetch.TargetRepoKinds.PREEXISTING
3330
fetch_spec = fetch_spec_factory.make_fetch_spec()
3388
if stop_revision is None and fetch_spec is None:
3389
stop_revision = self.source.last_revision()
3390
stop_revision = _mod_revision.ensure_null(stop_revision)
3331
3391
return self.target.repository.fetch(self.source.repository,
3332
fetch_spec=fetch_spec)
3392
revision_id=stop_revision, fetch_spec=fetch_spec)
3334
3394
self.source.unlock()
3336
3396
@needs_write_lock
3337
def _update_revisions(self, stop_revision=None, overwrite=False,
3397
def update_revisions(self, stop_revision=None, overwrite=False,
3398
graph=None, fetch_tags=True):
3399
"""See InterBranch.update_revisions()."""
3339
3400
other_revno, other_last_revision = self.source.last_revision_info()
3340
3401
stop_revno = None # unknown
3341
3402
if stop_revision is None:
3352
3413
# case of having something to pull, and so that the check for
3353
3414
# already merged can operate on the just fetched graph, which will
3354
3415
# be cached in memory.
3355
self.fetch(stop_revision=stop_revision)
3417
fetch_spec_factory = fetch.FetchSpecFactory()
3418
fetch_spec_factory.source_branch = self.source
3419
fetch_spec_factory.source_branch_stop_revision_id = stop_revision
3420
fetch_spec_factory.source_repo = self.source.repository
3421
fetch_spec_factory.target_repo = self.target.repository
3422
fetch_spec_factory.target_repo_kind = fetch.TargetRepoKinds.PREEXISTING
3423
fetch_spec = fetch_spec_factory.make_fetch_spec()
3425
fetch_spec = _mod_graph.NotInOtherForRevs(self.target.repository,
3426
self.source.repository, revision_ids=[stop_revision]).execute()
3427
self.target.fetch(self.source, fetch_spec=fetch_spec)
3356
3428
# Check to see if one is an ancestor of the other
3357
3429
if not overwrite:
3358
3430
if graph is None:
3428
3500
self.source.unlock()
3430
def _basic_push(self, overwrite, stop_revision):
3431
"""Basic implementation of push without bound branches or hooks.
3433
Must be called with source read locked and target write locked.
3435
result = BranchPushResult()
3436
result.source_branch = self.source
3437
result.target_branch = self.target
3438
result.old_revno, result.old_revid = self.target.last_revision_info()
3439
self.source.update_references(self.target)
3440
if result.old_revid != stop_revision:
3441
# We assume that during 'push' this repository is closer than
3443
graph = self.source.repository.get_graph(self.target.repository)
3444
self._update_revisions(stop_revision, overwrite=overwrite,
3446
if self.source._push_should_merge_tags():
3447
result.tag_conflicts = self.source.tags.merge_to(self.target.tags,
3449
result.new_revno, result.new_revid = self.target.last_revision_info()
3452
3502
def _push_with_bound_branches(self, overwrite, stop_revision,
3453
3503
_override_hook_source_branch=None):
3454
3504
"""Push from source into target, and into target's master if any.
3469
3519
master_branch.lock_write()
3471
3521
# push into the master from the source branch.
3472
master_inter = InterBranch.get(self.source, master_branch)
3473
master_inter._basic_push(overwrite, stop_revision)
3474
# and push into the target branch from the source. Note that
3475
# we push from the source branch again, because it's considered
3476
# the highest bandwidth repository.
3477
result = self._basic_push(overwrite, stop_revision)
3522
self.source._basic_push(master_branch, overwrite, stop_revision)
3523
# and push into the target branch from the source. Note that we
3524
# push from the source branch again, because it's considered the
3525
# highest bandwidth repository.
3526
result = self.source._basic_push(self.target, overwrite,
3478
3528
result.master_branch = master_branch
3479
3529
result.local_branch = self.target
3483
3533
master_branch.unlock()
3485
3535
# no master branch
3486
result = self._basic_push(overwrite, stop_revision)
3536
result = self.source._basic_push(self.target, overwrite,
3487
3538
# TODO: Why set master_branch and local_branch if there's no
3488
3539
# binding? Maybe cleaner to just leave them unset? -- mbp
3532
3583
# -- JRV20090506
3533
3584
result.old_revno, result.old_revid = \
3534
3585
self.target.last_revision_info()
3535
self._update_revisions(stop_revision, overwrite=overwrite,
3586
self.target.update_revisions(self.source, stop_revision,
3587
overwrite=overwrite, graph=graph)
3537
3588
# TODO: The old revid should be specified when merging tags,
3538
3589
# so a tags implementation that versions tags can only
3539
3590
# pull in the most recent changes. -- JRV20090506