455
454
after. If None, the rest of history is included.
456
455
:param stop_rule: if stop_revision_id is not None, the precise rule
457
456
to use for termination:
459
457
* 'exclude' - leave the stop revision out of the result (default)
460
458
* 'include' - the stop revision is the last item in the result
461
459
* 'with-merges' - include the stop revision and all of its
463
461
* 'with-merges-without-common-ancestry' - filter out revisions
464
462
that are in both ancestries
465
463
:param direction: either 'reverse' or 'forward':
467
464
* reverse means return the start_revision_id first, i.e.
468
465
start at the most recent revision and go backwards in history
469
466
* forward returns tuples in the opposite order to reverse.
525
522
if stop_revision_id is None:
526
523
# Yield everything
527
524
for node in rev_iter:
525
rev_id = node.key[-1]
529
526
yield (rev_id, node.merge_depth, node.revno,
530
527
node.end_of_merge)
531
528
elif stop_rule == 'exclude':
532
529
for node in rev_iter:
530
rev_id = node.key[-1]
534
531
if rev_id == stop_revision_id:
536
533
yield (rev_id, node.merge_depth, node.revno,
537
534
node.end_of_merge)
538
535
elif stop_rule == 'include':
539
536
for node in rev_iter:
537
rev_id = node.key[-1]
541
538
yield (rev_id, node.merge_depth, node.revno,
542
539
node.end_of_merge)
543
540
if rev_id == stop_revision_id:
549
546
ancestors = graph.find_unique_ancestors(start_revision_id,
550
547
[stop_revision_id])
551
548
for node in rev_iter:
549
rev_id = node.key[-1]
553
550
if rev_id not in ancestors:
555
552
yield (rev_id, node.merge_depth, node.revno,
670
667
raise errors.UnsupportedOperation(self.get_reference_info, self)
672
669
@needs_write_lock
673
def fetch(self, from_branch, last_revision=None, limit=None):
670
def fetch(self, from_branch, last_revision=None):
674
671
"""Copy revisions from from_branch into this branch.
676
673
:param from_branch: Where to copy from.
677
674
:param last_revision: What revision to stop at (None for at the end
679
:param limit: Optional rough limit of revisions to fetch
682
return InterBranch.get(from_branch, self).fetch(last_revision, limit=limit)
678
return InterBranch.get(from_branch, self).fetch(last_revision)
684
680
def get_bound_location(self):
685
681
"""Return the URL of the branch we are bound to.
778
774
configured to check constraints on history, in which case this may not
781
raise NotImplementedError(self.set_last_revision_info)
777
raise NotImplementedError(self.last_revision_info)
783
779
@needs_write_lock
784
780
def generate_revision_history(self, revision_id, last_rev=None,
933
929
:seealso: Branch._get_tags_bytes.
935
op = cleanup.OperationWithCleanups(self._set_tags_bytes_locked)
936
op.add_cleanup(self.lock_write().unlock)
937
return op.run_simple(bytes)
931
return _run_with_write_locked_target(self, self._set_tags_bytes_locked,
939
934
def _set_tags_bytes_locked(self, bytes):
940
935
self._tags_bytes = bytes
1107
1102
stop_revision=stop_revision,
1108
1103
possible_transports=possible_transports, *args, **kwargs)
1110
def push(self, target, overwrite=False, stop_revision=None, lossy=False,
1105
def push(self, target, overwrite=False, stop_revision=None, *args,
1112
1107
"""Mirror this branch into target.
1114
1109
This branch is considered to be 'local', having low latency.
1116
1111
return InterBranch.get(self, target).push(overwrite, stop_revision,
1117
lossy, *args, **kwargs)
1114
def lossy_push(self, target, stop_revision=None):
1115
"""Push deltas into another branch.
1117
:note: This does not, like push, retain the revision ids from
1118
the source branch and will, rather than adding bzr-specific
1119
metadata, push only those semantics of the revision that can be
1120
natively represented by this branch' VCS.
1122
:param target: Target branch
1123
:param stop_revision: Revision to push, defaults to last revision.
1124
:return: BranchPushResult with an extra member revidmap:
1125
A dictionary mapping revision ids from the target branch
1126
to new revision ids in the target branch, for each
1127
revision that was pushed.
1129
inter = InterBranch.get(self, target)
1130
lossy_push = getattr(inter, "lossy_push", None)
1131
if lossy_push is None:
1132
raise errors.LossyPushToSameVCS(self, target)
1133
return lossy_push(stop_revision)
1119
1135
def basis_tree(self):
1120
1136
"""Return `Tree` object for last revision."""
1422
1438
:param to_location: The url to produce the checkout at
1423
1439
:param revision_id: The revision to check out
1424
1440
:param lightweight: If True, produce a lightweight checkout, otherwise,
1425
produce a bound branch (heavyweight checkout)
1441
produce a bound branch (heavyweight checkout)
1426
1442
:param accelerator_tree: A tree which can be used for retrieving file
1427
1443
contents more quickly than the revision tree, i.e. a workingtree.
1428
1444
The revision tree will be used for cases where accelerator_tree's
1475
1491
def reference_parent(self, file_id, path, possible_transports=None):
1476
1492
"""Return the parent branch for a tree-reference file_id
1478
1493
:param file_id: The file_id of the tree reference
1479
1494
:param path: The path of the file_id in the tree
1480
1495
:return: A branch associated with the file_id
1872
1887
class ChangeBranchTipParams(object):
1873
"""Object holding parameters passed to `*_change_branch_tip` hooks.
1888
"""Object holding parameters passed to *_change_branch_tip hooks.
1875
1890
There are 5 fields that hooks may wish to access:
1910
1925
class BranchInitHookParams(object):
1911
"""Object holding parameters passed to `*_branch_init` hooks.
1926
"""Object holding parameters passed to *_branch_init hooks.
1913
1928
There are 4 fields that hooks may wish to access:
2942
2957
# you can always ask for the URL; but you might not be able to use it
2943
2958
# if the repo can't support stacking.
2944
2959
## self._check_stackable_repo()
2945
# stacked_on_location is only ever defined in branch.conf, so don't
2946
# waste effort reading the whole stack of config files.
2947
config = self.get_config()._get_branch_data_config()
2948
stacked_url = self._get_config_location('stacked_on_location',
2960
stacked_url = self._get_config_location('stacked_on_location')
2950
2961
if stacked_url is None:
2951
2962
raise errors.NotStacked(self)
2952
2963
return stacked_url
3174
3185
branch._transport.put_bytes('format', format.get_format_string())
3188
def _run_with_write_locked_target(target, callable, *args, **kwargs):
3189
"""Run ``callable(*args, **kwargs)``, write-locking target for the
3192
_run_with_write_locked_target will attempt to release the lock it acquires.
3194
If an exception is raised by callable, then that exception *will* be
3195
propagated, even if the unlock attempt raises its own error. Thus
3196
_run_with_write_locked_target should be preferred to simply doing::
3200
return callable(*args, **kwargs)
3205
# This is very similar to bzrlib.decorators.needs_write_lock. Perhaps they
3206
# should share code?
3209
result = callable(*args, **kwargs)
3211
exc_info = sys.exc_info()
3215
raise exc_info[0], exc_info[1], exc_info[2]
3177
3221
class InterBranch(InterObject):
3178
3222
"""This class represents operations taking place between two branches.
3207
3251
raise NotImplementedError(self.pull)
3209
3253
@needs_write_lock
3210
def push(self, overwrite=False, stop_revision=None, lossy=False,
3254
def push(self, overwrite=False, stop_revision=None,
3211
3255
_override_hook_source_branch=None):
3212
3256
"""Mirror the source branch into the target branch.
3225
3269
raise NotImplementedError(self.copy_content_into)
3227
3271
@needs_write_lock
3228
def fetch(self, stop_revision=None, limit=None):
3272
def fetch(self, stop_revision=None):
3229
3273
"""Fetch revisions.
3231
3275
:param stop_revision: Last revision to fetch
3232
:param limit: Optional rough limit of revisions to fetch
3234
3277
raise NotImplementedError(self.fetch)
3273
3316
self.source.tags.merge_to(self.target.tags)
3275
3318
@needs_write_lock
3276
def fetch(self, stop_revision=None, limit=None):
3319
def fetch(self, stop_revision=None):
3277
3320
if self.target.base == self.source.base:
3279
3322
self.source.lock_read()
3284
3327
fetch_spec_factory.source_repo = self.source.repository
3285
3328
fetch_spec_factory.target_repo = self.target.repository
3286
3329
fetch_spec_factory.target_repo_kind = fetch.TargetRepoKinds.PREEXISTING
3287
fetch_spec_factory.limit = limit
3288
3330
fetch_spec = fetch_spec_factory.make_fetch_spec()
3289
3331
return self.target.repository.fetch(self.source.repository,
3290
3332
fetch_spec=fetch_spec)
3363
3405
if master_branch:
3364
3406
master_branch.unlock()
3366
def push(self, overwrite=False, stop_revision=None, lossy=False,
3408
def push(self, overwrite=False, stop_revision=None,
3367
3409
_override_hook_source_branch=None):
3368
3410
"""See InterBranch.push.
3370
3412
This is the basic concrete implementation of push()
3372
:param _override_hook_source_branch: If specified, run the hooks
3373
passing this Branch as the source, rather than self. This is for
3374
use of RemoteBranch, where push is delegated to the underlying
3414
:param _override_hook_source_branch: If specified, run
3415
the hooks passing this Branch as the source, rather than self.
3416
This is for use of RemoteBranch, where push is delegated to the
3417
underlying vfs-based Branch.
3378
raise errors.LossyPushToSameVCS(self.source, self.target)
3379
3419
# TODO: Public option to disable running hooks - should be trivial but
3382
op = cleanup.OperationWithCleanups(self._push_with_bound_branches)
3383
op.add_cleanup(self.source.lock_read().unlock)
3384
op.add_cleanup(self.target.lock_write().unlock)
3385
return op.run(overwrite, stop_revision,
3386
_override_hook_source_branch=_override_hook_source_branch)
3421
self.source.lock_read()
3423
return _run_with_write_locked_target(
3424
self.target, self._push_with_bound_branches, overwrite,
3426
_override_hook_source_branch=_override_hook_source_branch)
3428
self.source.unlock()
3388
3430
def _basic_push(self, overwrite, stop_revision):
3389
3431
"""Basic implementation of push without bound branches or hooks.
3407
3449
result.new_revno, result.new_revid = self.target.last_revision_info()
3410
def _push_with_bound_branches(self, operation, overwrite, stop_revision,
3452
def _push_with_bound_branches(self, overwrite, stop_revision,
3411
3453
_override_hook_source_branch=None):
3412
3454
"""Push from source into target, and into target's master if any.
3425
3467
# be bound to itself? -- mbp 20070507
3426
3468
master_branch = self.target.get_master_branch()
3427
3469
master_branch.lock_write()
3428
operation.add_cleanup(master_branch.unlock)
3429
# push into the master from the source branch.
3430
master_inter = InterBranch.get(self.source, master_branch)
3431
master_inter._basic_push(overwrite, stop_revision)
3432
# and push into the target branch from the source. Note that
3433
# we push from the source branch again, because it's considered
3434
# the highest bandwidth repository.
3435
result = self._basic_push(overwrite, stop_revision)
3436
result.master_branch = master_branch
3437
result.local_branch = self.target
3471
# 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)
3478
result.master_branch = master_branch
3479
result.local_branch = self.target
3483
master_branch.unlock()
3439
master_branch = None
3440
3485
# no master branch
3441
3486
result = self._basic_push(overwrite, stop_revision)
3442
3487
# TODO: Why set master_branch and local_branch if there's no
3445
3490
result.master_branch = self.target
3446
3491
result.local_branch = None
3450
3495
def _pull(self, overwrite=False, stop_revision=None,
3451
3496
possible_transports=None, _hook_master=None, run_hooks=True,