746
746
"""Print `file` to stdout."""
747
747
raise NotImplementedError(self.print_file)
749
@deprecated_method(deprecated_in((2, 4, 0)))
749
750
def set_revision_history(self, rev_history):
750
raise NotImplementedError(self.set_revision_history)
751
"""See Branch.set_revision_history."""
752
self._set_revision_history(rev_history)
755
def _set_revision_history(self, rev_history):
756
if len(rev_history) == 0:
757
revid = _mod_revision.NULL_REVISION
759
revid = rev_history[-1]
760
if rev_history != self._lefthand_history(revid):
761
raise errors.NotLefthandHistory(rev_history)
762
self.set_last_revision_info(len(rev_history), revid)
763
self._cache_revision_history(rev_history)
764
for hook in Branch.hooks['set_rh']:
765
hook(self, rev_history)
768
def set_last_revision_info(self, revno, revision_id):
769
"""Set the last revision of this branch.
771
The caller is responsible for checking that the revno is correct
772
for this revision id.
774
It may be possible to set the branch last revision to an id not
775
present in the repository. However, branches can also be
776
configured to check constraints on history, in which case this may not
779
raise NotImplementedError(self.last_revision_info)
782
def generate_revision_history(self, revision_id, last_rev=None,
784
"""See Branch.generate_revision_history"""
785
# FIXME: This shouldn't have to fetch the entire history
786
history = self._lefthand_history(revision_id, last_rev, other_branch)
788
self.set_last_revision_info(revno, revision_id)
789
self._cache_revision_history(history)
752
791
@needs_write_lock
753
792
def set_parent(self, url):
2477
2511
"""See Branch.print_file."""
2478
2512
return self.repository.print_file(file, revision_id)
2480
def _write_revision_history(self, history):
2481
"""Factored out of set_revision_history.
2483
This performs the actual writing to disk.
2484
It is intended to be called by BzrBranch5.set_revision_history."""
2485
self._transport.put_bytes(
2486
'revision-history', '\n'.join(history),
2487
mode=self.bzrdir._get_file_mode())
2489
@deprecated_method(deprecated_in((2, 4, 0)))
2490
def set_revision_history(self, rev_history):
2491
"""See Branch.set_revision_history."""
2492
self._set_revision_history(rev_history)
2495
def _set_revision_history(self, rev_history):
2496
if 'evil' in debug.debug_flags:
2497
mutter_callsite(3, "set_revision_history scales with history.")
2498
check_not_reserved_id = _mod_revision.check_not_reserved_id
2499
for rev_id in rev_history:
2500
check_not_reserved_id(rev_id)
2501
if Branch.hooks['post_change_branch_tip']:
2502
# Don't calculate the last_revision_info() if there are no hooks
2504
old_revno, old_revid = self.last_revision_info()
2505
if len(rev_history) == 0:
2506
revid = _mod_revision.NULL_REVISION
2508
revid = rev_history[-1]
2509
self._run_pre_change_branch_tip_hooks(len(rev_history), revid)
2510
self._write_revision_history(rev_history)
2511
self._clear_cached_state()
2512
self._cache_revision_history(rev_history)
2513
for hook in Branch.hooks['set_rh']:
2514
hook(self, rev_history)
2515
if Branch.hooks['post_change_branch_tip']:
2516
self._run_post_change_branch_tip_hooks(old_revno, old_revid)
2518
def _synchronize_history(self, destination, revision_id):
2519
"""Synchronize last revision and revision history between branches.
2521
This version is most efficient when the destination is also a
2522
BzrBranch5, but works for BzrBranch6 as long as the revision
2523
history is the true lefthand parent history, and all of the revisions
2524
are in the destination's repository. If not, set_revision_history
2527
:param destination: The branch to copy the history into
2528
:param revision_id: The revision-id to truncate history at. May
2529
be None to copy complete history.
2531
if not isinstance(destination._format, BzrBranchFormat5):
2532
super(BzrBranch, self)._synchronize_history(
2533
destination, revision_id)
2535
if revision_id == _mod_revision.NULL_REVISION:
2538
new_history = self.revision_history()
2539
if revision_id is not None and new_history != []:
2541
new_history = new_history[:new_history.index(revision_id) + 1]
2543
rev = self.repository.get_revision(revision_id)
2544
new_history = rev.get_history(self.repository)[1:]
2545
destination._set_revision_history(new_history)
2547
2514
@needs_write_lock
2548
2515
def set_last_revision_info(self, revno, revision_id):
2549
"""Set the last revision of this branch.
2551
The caller is responsible for checking that the revno is correct
2552
for this revision id.
2554
It may be possible to set the branch last revision to an id not
2555
present in the repository. However, branches can also be
2556
configured to check constraints on history, in which case this may not
2559
2516
if not revision_id or not isinstance(revision_id, basestring):
2560
2517
raise errors.InvalidRevisionId(revision_id=revision_id, branch=self)
2561
# this old format stores the full history, but this api doesn't
2562
# provide it, so we must generate, and might as well check it's
2564
history = self._lefthand_history(revision_id)
2565
if len(history) != revno:
2566
raise AssertionError('%d != %d' % (len(history), revno))
2567
self._set_revision_history(history)
2569
def _gen_revision_history(self):
2570
history = self._transport.get_bytes('revision-history').split('\n')
2571
if history[-1:] == ['']:
2572
# There shouldn't be a trailing newline, but just in case.
2577
def generate_revision_history(self, revision_id, last_rev=None,
2579
"""Create a new revision history that will finish with revision_id.
2581
:param revision_id: the new tip to use.
2582
:param last_rev: The previous last_revision. If not None, then this
2583
must be a ancestory of revision_id, or DivergedBranches is raised.
2584
:param other_branch: The other branch that DivergedBranches should
2585
raise with respect to.
2587
self._set_revision_history(self._lefthand_history(revision_id,
2588
last_rev, other_branch))
2518
revision_id = _mod_revision.ensure_null(revision_id)
2519
old_revno, old_revid = self.last_revision_info()
2520
if self._get_append_revisions_only():
2521
self._check_history_violation(revision_id)
2522
self._run_pre_change_branch_tip_hooks(revno, revision_id)
2523
self._write_last_revision_info(revno, revision_id)
2524
self._clear_cached_state()
2525
self._last_revision_info_cache = revno, revision_id
2526
self._run_post_change_branch_tip_hooks(old_revno, old_revid)
2590
2528
def basis_tree(self):
2591
2529
"""See Branch.basis_tree."""
2616
2554
self._transport.put_bytes('parent', url + '\n',
2617
2555
mode=self.bzrdir._get_file_mode())
2620
class BzrBranch5(BzrBranch):
2621
"""A format 5 branch. This supports new features over plain branches.
2623
It has support for a master_branch which is the data for bound branches.
2559
"""If bound, unbind"""
2560
return self.set_bound_location(None)
2563
def bind(self, other):
2564
"""Bind this branch to the branch other.
2566
This does not push or pull data between the branches, though it does
2567
check for divergence to raise an error when the branches are not
2568
either the same, or one a prefix of the other. That behaviour may not
2569
be useful, so that check may be removed in future.
2571
:param other: The branch to bind to
2574
# TODO: jam 20051230 Consider checking if the target is bound
2575
# It is debatable whether you should be able to bind to
2576
# a branch which is itself bound.
2577
# Committing is obviously forbidden,
2578
# but binding itself may not be.
2579
# Since we *have* to check at commit time, we don't
2580
# *need* to check here
2582
# we want to raise diverged if:
2583
# last_rev is not in the other_last_rev history, AND
2584
# other_last_rev is not in our history, and do it without pulling
2586
self.set_bound_location(other.base)
2626
2588
def get_bound_location(self):
2671
2633
@needs_write_lock
2672
def bind(self, other):
2673
"""Bind this branch to the branch other.
2675
This does not push or pull data between the branches, though it does
2676
check for divergence to raise an error when the branches are not
2677
either the same, or one a prefix of the other. That behaviour may not
2678
be useful, so that check may be removed in future.
2680
:param other: The branch to bind to
2683
# TODO: jam 20051230 Consider checking if the target is bound
2684
# It is debatable whether you should be able to bind to
2685
# a branch which is itself bound.
2686
# Committing is obviously forbidden,
2687
# but binding itself may not be.
2688
# Since we *have* to check at commit time, we don't
2689
# *need* to check here
2691
# we want to raise diverged if:
2692
# last_rev is not in the other_last_rev history, AND
2693
# other_last_rev is not in our history, and do it without pulling
2695
self.set_bound_location(other.base)
2699
"""If bound, unbind"""
2700
return self.set_bound_location(None)
2703
2634
def update(self, possible_transports=None):
2704
2635
"""Synchronise this branch with the master branch if any.
2720
class BzrBranch8(BzrBranch5):
2650
def _read_last_revision_info(self):
2651
revision_string = self._transport.get_bytes('last-revision')
2652
revno, revision_id = revision_string.rstrip('\n').split(' ', 1)
2653
revision_id = cache_utf8.get_cached_utf8(revision_id)
2655
return revno, revision_id
2657
def _write_last_revision_info(self, revno, revision_id):
2658
"""Simply write out the revision id, with no checks.
2660
Use set_last_revision_info to perform this safely.
2662
Does not update the revision_history cache.
2664
revision_id = _mod_revision.ensure_null(revision_id)
2665
out_string = '%d %s\n' % (revno, revision_id)
2666
self._transport.put_bytes('last-revision', out_string,
2667
mode=self.bzrdir._get_file_mode())
2670
class FullHistoryBzrBranch(BzrBranch):
2671
"""Bzr branch which contains the full revision history."""
2674
def set_last_revision_info(self, revno, revision_id):
2675
if not revision_id or not isinstance(revision_id, basestring):
2676
raise errors.InvalidRevisionId(revision_id=revision_id, branch=self)
2677
revision_id = _mod_revision.ensure_null(revision_id)
2678
# this old format stores the full history, but this api doesn't
2679
# provide it, so we must generate, and might as well check it's
2681
history = self._lefthand_history(revision_id)
2682
if len(history) != revno:
2683
raise AssertionError('%d != %d' % (len(history), revno))
2684
self._set_revision_history(history)
2686
def _read_last_revision_info(self):
2687
rh = self.revision_history()
2690
return (revno, rh[-1])
2692
return (0, _mod_revision.NULL_REVISION)
2694
@deprecated_method(deprecated_in((2, 4, 0)))
2696
def set_revision_history(self, rev_history):
2697
"""See Branch.set_revision_history."""
2698
self._set_revision_history(rev_history)
2700
def _set_revision_history(self, rev_history):
2701
if 'evil' in debug.debug_flags:
2702
mutter_callsite(3, "set_revision_history scales with history.")
2703
check_not_reserved_id = _mod_revision.check_not_reserved_id
2704
for rev_id in rev_history:
2705
check_not_reserved_id(rev_id)
2706
if Branch.hooks['post_change_branch_tip']:
2707
# Don't calculate the last_revision_info() if there are no hooks
2709
old_revno, old_revid = self.last_revision_info()
2710
if len(rev_history) == 0:
2711
revid = _mod_revision.NULL_REVISION
2713
revid = rev_history[-1]
2714
self._run_pre_change_branch_tip_hooks(len(rev_history), revid)
2715
self._write_revision_history(rev_history)
2716
self._clear_cached_state()
2717
self._cache_revision_history(rev_history)
2718
for hook in Branch.hooks['set_rh']:
2719
hook(self, rev_history)
2720
if Branch.hooks['post_change_branch_tip']:
2721
self._run_post_change_branch_tip_hooks(old_revno, old_revid)
2723
def _write_revision_history(self, history):
2724
"""Factored out of set_revision_history.
2726
This performs the actual writing to disk.
2727
It is intended to be called by set_revision_history."""
2728
self._transport.put_bytes(
2729
'revision-history', '\n'.join(history),
2730
mode=self.bzrdir._get_file_mode())
2732
def _gen_revision_history(self):
2733
history = self._transport.get_bytes('revision-history').split('\n')
2734
if history[-1:] == ['']:
2735
# There shouldn't be a trailing newline, but just in case.
2739
def _synchronize_history(self, destination, revision_id):
2740
if not isinstance(destination, FullHistoryBzrBranch):
2741
super(BzrBranch, self)._synchronize_history(
2742
destination, revision_id)
2744
if revision_id == _mod_revision.NULL_REVISION:
2747
new_history = self.revision_history()
2748
if revision_id is not None and new_history != []:
2750
new_history = new_history[:new_history.index(revision_id) + 1]
2752
rev = self.repository.get_revision(revision_id)
2753
new_history = rev.get_history(self.repository)[1:]
2754
destination._set_revision_history(new_history)
2757
def generate_revision_history(self, revision_id, last_rev=None,
2759
"""Create a new revision history that will finish with revision_id.
2761
:param revision_id: the new tip to use.
2762
:param last_rev: The previous last_revision. If not None, then this
2763
must be a ancestory of revision_id, or DivergedBranches is raised.
2764
:param other_branch: The other branch that DivergedBranches should
2765
raise with respect to.
2767
self._set_revision_history(self._lefthand_history(revision_id,
2768
last_rev, other_branch))
2771
class BzrBranch5(FullHistoryBzrBranch):
2772
"""A format 5 branch. This supports new features over plain branches.
2774
It has support for a master_branch which is the data for bound branches.
2778
class BzrBranch8(BzrBranch):
2721
2779
"""A branch that stores tree-reference locations."""
2723
2781
def _open_hook(self):
2749
2807
self._last_revision_info_cache = None
2750
2808
self._reference_info = None
2752
def _last_revision_info(self):
2753
revision_string = self._transport.get_bytes('last-revision')
2754
revno, revision_id = revision_string.rstrip('\n').split(' ', 1)
2755
revision_id = cache_utf8.get_cached_utf8(revision_id)
2757
return revno, revision_id
2759
def _write_last_revision_info(self, revno, revision_id):
2760
"""Simply write out the revision id, with no checks.
2762
Use set_last_revision_info to perform this safely.
2764
Does not update the revision_history cache.
2765
Intended to be called by set_last_revision_info and
2766
_write_revision_history.
2768
revision_id = _mod_revision.ensure_null(revision_id)
2769
out_string = '%d %s\n' % (revno, revision_id)
2770
self._transport.put_bytes('last-revision', out_string,
2771
mode=self.bzrdir._get_file_mode())
2774
def set_last_revision_info(self, revno, revision_id):
2775
if not revision_id or not isinstance(revision_id, basestring):
2776
raise errors.InvalidRevisionId(revision_id=revision_id, branch=self)
2777
old_revno, old_revid = self.last_revision_info()
2778
if self._get_append_revisions_only():
2779
self._check_history_violation(revision_id)
2780
self._run_pre_change_branch_tip_hooks(revno, revision_id)
2781
self._write_last_revision_info(revno, revision_id)
2782
self._clear_cached_state()
2783
self._last_revision_info_cache = revno, revision_id
2784
self._run_post_change_branch_tip_hooks(old_revno, old_revid)
2786
def _synchronize_history(self, destination, revision_id):
2787
"""Synchronize last revision and revision history between branches.
2789
:see: Branch._synchronize_history
2791
# XXX: The base Branch has a fast implementation of this method based
2792
# on set_last_revision_info, but BzrBranch/BzrBranch5 have a slower one
2793
# that uses set_revision_history. This class inherits from BzrBranch5,
2794
# but wants the fast implementation, so it calls
2795
# Branch._synchronize_history directly.
2796
Branch._synchronize_history(self, destination, revision_id)
2798
2810
def _check_history_violation(self, revision_id):
2799
2811
last_revision = _mod_revision.ensure_null(self.last_revision())
2800
2812
if _mod_revision.is_null(last_revision):