Rev 5842: (jelmer) Make default Branch implementation oriented to storing just tip in file:///home/pqm/archives/thelove/bzr/%2Btrunk/
Canonical.com Patch Queue Manager
pqm at pqm.ubuntu.com
Mon May 9 10:59:57 UTC 2011
At file:///home/pqm/archives/thelove/bzr/%2Btrunk/
------------------------------------------------------------
revno: 5842 [merge]
revision-id: pqm at pqm.ubuntu.com-20110509105953-n94q63064kk8s0ui
parent: pqm at pqm.ubuntu.com-20110509095424-go6263smv6wzc5u1
parent: jelmer at samba.org-20110509100541-lba36ku5nd1s7obe
committer: Canonical.com Patch Queue Manager <pqm at pqm.ubuntu.com>
branch nick: +trunk
timestamp: Mon 2011-05-09 10:59:53 +0000
message:
(jelmer) Make default Branch implementation oriented to storing just tip
rather than full history. (Jelmer Vernooij)
modified:
bzrlib/branch.py branch.py-20050309040759-e4baf4e0d046576e
bzrlib/plugins/weave_fmt/branch.py branch_weave.py-20110303112759-greg4a9dt5pent0m-1
bzrlib/remote.py remote.py-20060720103555-yeeg2x51vn0rbtdp-1
bzrlib/tests/per_workingtree/test_workingtree.py test_workingtree.py-20060203003124-817757d3e31444fb
bzrlib/tests/test_branch.py test_branch.py-20060116013032-97819aa07b8ab3b5
bzrlib/workingtree.py workingtree.py-20050511021032-29b6ec0a681e02e3
doc/en/release-notes/bzr-2.4.txt bzr2.4.txt-20110114053217-k7ym9jfz243fddjm-1
=== modified file 'bzrlib/branch.py'
--- a/bzrlib/branch.py 2011-05-06 07:25:24 +0000
+++ b/bzrlib/branch.py 2011-05-08 13:50:25 +0000
@@ -746,8 +746,47 @@
"""Print `file` to stdout."""
raise NotImplementedError(self.print_file)
+ @deprecated_method(deprecated_in((2, 4, 0)))
def set_revision_history(self, rev_history):
- raise NotImplementedError(self.set_revision_history)
+ """See Branch.set_revision_history."""
+ self._set_revision_history(rev_history)
+
+ @needs_write_lock
+ def _set_revision_history(self, rev_history):
+ if len(rev_history) == 0:
+ revid = _mod_revision.NULL_REVISION
+ else:
+ revid = rev_history[-1]
+ if rev_history != self._lefthand_history(revid):
+ raise errors.NotLefthandHistory(rev_history)
+ self.set_last_revision_info(len(rev_history), revid)
+ self._cache_revision_history(rev_history)
+ for hook in Branch.hooks['set_rh']:
+ hook(self, rev_history)
+
+ @needs_write_lock
+ def set_last_revision_info(self, revno, revision_id):
+ """Set the last revision of this branch.
+
+ The caller is responsible for checking that the revno is correct
+ for this revision id.
+
+ It may be possible to set the branch last revision to an id not
+ present in the repository. However, branches can also be
+ configured to check constraints on history, in which case this may not
+ be permitted.
+ """
+ raise NotImplementedError(self.last_revision_info)
+
+ @needs_write_lock
+ def generate_revision_history(self, revision_id, last_rev=None,
+ other_branch=None):
+ """See Branch.generate_revision_history"""
+ # FIXME: This shouldn't have to fetch the entire history
+ history = self._lefthand_history(revision_id, last_rev, other_branch)
+ revno = len(history)
+ self.set_last_revision_info(revno, revision_id)
+ self._cache_revision_history(history)
@needs_write_lock
def set_parent(self, url):
@@ -983,16 +1022,11 @@
:return: A tuple (revno, revision_id).
"""
if self._last_revision_info_cache is None:
- self._last_revision_info_cache = self._last_revision_info()
+ self._last_revision_info_cache = self._read_last_revision_info()
return self._last_revision_info_cache
- def _last_revision_info(self):
- rh = self.revision_history()
- revno = len(rh)
- if revno:
- return (revno, rh[-1])
- else:
- return (0, _mod_revision.NULL_REVISION)
+ def _read_last_revision_info(self):
+ raise NotImplementedError(self._read_last_revision_info)
@deprecated_method(deprecated_in((2, 4, 0)))
def import_last_revision_info(self, source_repo, revno, revid):
@@ -2477,115 +2511,19 @@
"""See Branch.print_file."""
return self.repository.print_file(file, revision_id)
- def _write_revision_history(self, history):
- """Factored out of set_revision_history.
-
- This performs the actual writing to disk.
- It is intended to be called by BzrBranch5.set_revision_history."""
- self._transport.put_bytes(
- 'revision-history', '\n'.join(history),
- mode=self.bzrdir._get_file_mode())
-
- @deprecated_method(deprecated_in((2, 4, 0)))
- def set_revision_history(self, rev_history):
- """See Branch.set_revision_history."""
- self._set_revision_history(rev_history)
-
- @needs_write_lock
- def _set_revision_history(self, rev_history):
- if 'evil' in debug.debug_flags:
- mutter_callsite(3, "set_revision_history scales with history.")
- check_not_reserved_id = _mod_revision.check_not_reserved_id
- for rev_id in rev_history:
- check_not_reserved_id(rev_id)
- if Branch.hooks['post_change_branch_tip']:
- # Don't calculate the last_revision_info() if there are no hooks
- # that will use it.
- old_revno, old_revid = self.last_revision_info()
- if len(rev_history) == 0:
- revid = _mod_revision.NULL_REVISION
- else:
- revid = rev_history[-1]
- self._run_pre_change_branch_tip_hooks(len(rev_history), revid)
- self._write_revision_history(rev_history)
- self._clear_cached_state()
- self._cache_revision_history(rev_history)
- for hook in Branch.hooks['set_rh']:
- hook(self, rev_history)
- if Branch.hooks['post_change_branch_tip']:
- self._run_post_change_branch_tip_hooks(old_revno, old_revid)
-
- def _synchronize_history(self, destination, revision_id):
- """Synchronize last revision and revision history between branches.
-
- This version is most efficient when the destination is also a
- BzrBranch5, but works for BzrBranch6 as long as the revision
- history is the true lefthand parent history, and all of the revisions
- are in the destination's repository. If not, set_revision_history
- will fail.
-
- :param destination: The branch to copy the history into
- :param revision_id: The revision-id to truncate history at. May
- be None to copy complete history.
- """
- if not isinstance(destination._format, BzrBranchFormat5):
- super(BzrBranch, self)._synchronize_history(
- destination, revision_id)
- return
- if revision_id == _mod_revision.NULL_REVISION:
- new_history = []
- else:
- new_history = self.revision_history()
- if revision_id is not None and new_history != []:
- try:
- new_history = new_history[:new_history.index(revision_id) + 1]
- except ValueError:
- rev = self.repository.get_revision(revision_id)
- new_history = rev.get_history(self.repository)[1:]
- destination._set_revision_history(new_history)
-
@needs_write_lock
def set_last_revision_info(self, revno, revision_id):
- """Set the last revision of this branch.
-
- The caller is responsible for checking that the revno is correct
- for this revision id.
-
- It may be possible to set the branch last revision to an id not
- present in the repository. However, branches can also be
- configured to check constraints on history, in which case this may not
- be permitted.
- """
if not revision_id or not isinstance(revision_id, basestring):
raise errors.InvalidRevisionId(revision_id=revision_id, branch=self)
- # this old format stores the full history, but this api doesn't
- # provide it, so we must generate, and might as well check it's
- # correct
- history = self._lefthand_history(revision_id)
- if len(history) != revno:
- raise AssertionError('%d != %d' % (len(history), revno))
- self._set_revision_history(history)
-
- def _gen_revision_history(self):
- history = self._transport.get_bytes('revision-history').split('\n')
- if history[-1:] == ['']:
- # There shouldn't be a trailing newline, but just in case.
- history.pop()
- return history
-
- @needs_write_lock
- def generate_revision_history(self, revision_id, last_rev=None,
- other_branch=None):
- """Create a new revision history that will finish with revision_id.
-
- :param revision_id: the new tip to use.
- :param last_rev: The previous last_revision. If not None, then this
- must be a ancestory of revision_id, or DivergedBranches is raised.
- :param other_branch: The other branch that DivergedBranches should
- raise with respect to.
- """
- self._set_revision_history(self._lefthand_history(revision_id,
- last_rev, other_branch))
+ revision_id = _mod_revision.ensure_null(revision_id)
+ old_revno, old_revid = self.last_revision_info()
+ if self._get_append_revisions_only():
+ self._check_history_violation(revision_id)
+ self._run_pre_change_branch_tip_hooks(revno, revision_id)
+ self._write_last_revision_info(revno, revision_id)
+ self._clear_cached_state()
+ self._last_revision_info_cache = revno, revision_id
+ self._run_post_change_branch_tip_hooks(old_revno, old_revid)
def basis_tree(self):
"""See Branch.basis_tree."""
@@ -2616,12 +2554,36 @@
self._transport.put_bytes('parent', url + '\n',
mode=self.bzrdir._get_file_mode())
-
-class BzrBranch5(BzrBranch):
- """A format 5 branch. This supports new features over plain branches.
-
- It has support for a master_branch which is the data for bound branches.
- """
+ @needs_write_lock
+ def unbind(self):
+ """If bound, unbind"""
+ return self.set_bound_location(None)
+
+ @needs_write_lock
+ def bind(self, other):
+ """Bind this branch to the branch other.
+
+ This does not push or pull data between the branches, though it does
+ check for divergence to raise an error when the branches are not
+ either the same, or one a prefix of the other. That behaviour may not
+ be useful, so that check may be removed in future.
+
+ :param other: The branch to bind to
+ :type other: Branch
+ """
+ # TODO: jam 20051230 Consider checking if the target is bound
+ # It is debatable whether you should be able to bind to
+ # a branch which is itself bound.
+ # Committing is obviously forbidden,
+ # but binding itself may not be.
+ # Since we *have* to check at commit time, we don't
+ # *need* to check here
+
+ # we want to raise diverged if:
+ # last_rev is not in the other_last_rev history, AND
+ # other_last_rev is not in our history, and do it without pulling
+ # history around
+ self.set_bound_location(other.base)
def get_bound_location(self):
try:
@@ -2669,37 +2631,6 @@
return True
@needs_write_lock
- def bind(self, other):
- """Bind this branch to the branch other.
-
- This does not push or pull data between the branches, though it does
- check for divergence to raise an error when the branches are not
- either the same, or one a prefix of the other. That behaviour may not
- be useful, so that check may be removed in future.
-
- :param other: The branch to bind to
- :type other: Branch
- """
- # TODO: jam 20051230 Consider checking if the target is bound
- # It is debatable whether you should be able to bind to
- # a branch which is itself bound.
- # Committing is obviously forbidden,
- # but binding itself may not be.
- # Since we *have* to check at commit time, we don't
- # *need* to check here
-
- # we want to raise diverged if:
- # last_rev is not in the other_last_rev history, AND
- # other_last_rev is not in our history, and do it without pulling
- # history around
- self.set_bound_location(other.base)
-
- @needs_write_lock
- def unbind(self):
- """If bound, unbind"""
- return self.set_bound_location(None)
-
- @needs_write_lock
def update(self, possible_transports=None):
"""Synchronise this branch with the master branch if any.
@@ -2716,8 +2647,135 @@
return old_tip
return None
-
-class BzrBranch8(BzrBranch5):
+ def _read_last_revision_info(self):
+ revision_string = self._transport.get_bytes('last-revision')
+ revno, revision_id = revision_string.rstrip('\n').split(' ', 1)
+ revision_id = cache_utf8.get_cached_utf8(revision_id)
+ revno = int(revno)
+ return revno, revision_id
+
+ def _write_last_revision_info(self, revno, revision_id):
+ """Simply write out the revision id, with no checks.
+
+ Use set_last_revision_info to perform this safely.
+
+ Does not update the revision_history cache.
+ """
+ revision_id = _mod_revision.ensure_null(revision_id)
+ out_string = '%d %s\n' % (revno, revision_id)
+ self._transport.put_bytes('last-revision', out_string,
+ mode=self.bzrdir._get_file_mode())
+
+
+class FullHistoryBzrBranch(BzrBranch):
+ """Bzr branch which contains the full revision history."""
+
+ @needs_write_lock
+ def set_last_revision_info(self, revno, revision_id):
+ if not revision_id or not isinstance(revision_id, basestring):
+ raise errors.InvalidRevisionId(revision_id=revision_id, branch=self)
+ revision_id = _mod_revision.ensure_null(revision_id)
+ # this old format stores the full history, but this api doesn't
+ # provide it, so we must generate, and might as well check it's
+ # correct
+ history = self._lefthand_history(revision_id)
+ if len(history) != revno:
+ raise AssertionError('%d != %d' % (len(history), revno))
+ self._set_revision_history(history)
+
+ def _read_last_revision_info(self):
+ rh = self.revision_history()
+ revno = len(rh)
+ if revno:
+ return (revno, rh[-1])
+ else:
+ return (0, _mod_revision.NULL_REVISION)
+
+ @deprecated_method(deprecated_in((2, 4, 0)))
+ @needs_write_lock
+ def set_revision_history(self, rev_history):
+ """See Branch.set_revision_history."""
+ self._set_revision_history(rev_history)
+
+ def _set_revision_history(self, rev_history):
+ if 'evil' in debug.debug_flags:
+ mutter_callsite(3, "set_revision_history scales with history.")
+ check_not_reserved_id = _mod_revision.check_not_reserved_id
+ for rev_id in rev_history:
+ check_not_reserved_id(rev_id)
+ if Branch.hooks['post_change_branch_tip']:
+ # Don't calculate the last_revision_info() if there are no hooks
+ # that will use it.
+ old_revno, old_revid = self.last_revision_info()
+ if len(rev_history) == 0:
+ revid = _mod_revision.NULL_REVISION
+ else:
+ revid = rev_history[-1]
+ self._run_pre_change_branch_tip_hooks(len(rev_history), revid)
+ self._write_revision_history(rev_history)
+ self._clear_cached_state()
+ self._cache_revision_history(rev_history)
+ for hook in Branch.hooks['set_rh']:
+ hook(self, rev_history)
+ if Branch.hooks['post_change_branch_tip']:
+ self._run_post_change_branch_tip_hooks(old_revno, old_revid)
+
+ def _write_revision_history(self, history):
+ """Factored out of set_revision_history.
+
+ This performs the actual writing to disk.
+ It is intended to be called by set_revision_history."""
+ self._transport.put_bytes(
+ 'revision-history', '\n'.join(history),
+ mode=self.bzrdir._get_file_mode())
+
+ def _gen_revision_history(self):
+ history = self._transport.get_bytes('revision-history').split('\n')
+ if history[-1:] == ['']:
+ # There shouldn't be a trailing newline, but just in case.
+ history.pop()
+ return history
+
+ def _synchronize_history(self, destination, revision_id):
+ if not isinstance(destination, FullHistoryBzrBranch):
+ super(BzrBranch, self)._synchronize_history(
+ destination, revision_id)
+ return
+ if revision_id == _mod_revision.NULL_REVISION:
+ new_history = []
+ else:
+ new_history = self.revision_history()
+ if revision_id is not None and new_history != []:
+ try:
+ new_history = new_history[:new_history.index(revision_id) + 1]
+ except ValueError:
+ rev = self.repository.get_revision(revision_id)
+ new_history = rev.get_history(self.repository)[1:]
+ destination._set_revision_history(new_history)
+
+ @needs_write_lock
+ def generate_revision_history(self, revision_id, last_rev=None,
+ other_branch=None):
+ """Create a new revision history that will finish with revision_id.
+
+ :param revision_id: the new tip to use.
+ :param last_rev: The previous last_revision. If not None, then this
+ must be a ancestory of revision_id, or DivergedBranches is raised.
+ :param other_branch: The other branch that DivergedBranches should
+ raise with respect to.
+ """
+ self._set_revision_history(self._lefthand_history(revision_id,
+ last_rev, other_branch))
+
+
+class BzrBranch5(FullHistoryBzrBranch):
+ """A format 5 branch. This supports new features over plain branches.
+
+ It has support for a master_branch which is the data for bound branches.
+ """
+
+
+class BzrBranch8(BzrBranch):
"""A branch that stores tree-reference locations."""
def _open_hook(self):
@@ -2749,52 +2807,6 @@
self._last_revision_info_cache = None
self._reference_info = None
- def _last_revision_info(self):
- revision_string = self._transport.get_bytes('last-revision')
- revno, revision_id = revision_string.rstrip('\n').split(' ', 1)
- revision_id = cache_utf8.get_cached_utf8(revision_id)
- revno = int(revno)
- return revno, revision_id
-
- def _write_last_revision_info(self, revno, revision_id):
- """Simply write out the revision id, with no checks.
-
- Use set_last_revision_info to perform this safely.
-
- Does not update the revision_history cache.
- Intended to be called by set_last_revision_info and
- _write_revision_history.
- """
- revision_id = _mod_revision.ensure_null(revision_id)
- out_string = '%d %s\n' % (revno, revision_id)
- self._transport.put_bytes('last-revision', out_string,
- mode=self.bzrdir._get_file_mode())
-
- @needs_write_lock
- def set_last_revision_info(self, revno, revision_id):
- if not revision_id or not isinstance(revision_id, basestring):
- raise errors.InvalidRevisionId(revision_id=revision_id, branch=self)
- old_revno, old_revid = self.last_revision_info()
- if self._get_append_revisions_only():
- self._check_history_violation(revision_id)
- self._run_pre_change_branch_tip_hooks(revno, revision_id)
- self._write_last_revision_info(revno, revision_id)
- self._clear_cached_state()
- self._last_revision_info_cache = revno, revision_id
- self._run_post_change_branch_tip_hooks(old_revno, old_revid)
-
- def _synchronize_history(self, destination, revision_id):
- """Synchronize last revision and revision history between branches.
-
- :see: Branch._synchronize_history
- """
- # XXX: The base Branch has a fast implementation of this method based
- # on set_last_revision_info, but BzrBranch/BzrBranch5 have a slower one
- # that uses set_revision_history. This class inherits from BzrBranch5,
- # but wants the fast implementation, so it calls
- # Branch._synchronize_history directly.
- Branch._synchronize_history(self, destination, revision_id)
-
def _check_history_violation(self, revision_id):
last_revision = _mod_revision.ensure_null(self.last_revision())
if _mod_revision.is_null(last_revision):
@@ -2809,22 +2821,6 @@
self._extend_partial_history(stop_index=last_revno-1)
return list(reversed(self._partial_revision_history_cache))
- def _write_revision_history(self, history):
- """Factored out of set_revision_history.
-
- This performs the actual writing to disk, with format-specific checks.
- It is intended to be called by BzrBranch5.set_revision_history.
- """
- if len(history) == 0:
- last_revision = 'null:'
- else:
- if history != self._lefthand_history(history[-1]):
- raise errors.NotLefthandHistory(history)
- last_revision = history[-1]
- if self._get_append_revisions_only():
- self._check_history_violation(last_revision)
- self._write_last_revision_info(len(history), last_revision)
-
@needs_write_lock
def _set_parent_location(self, url):
"""Set the parent branch"""
@@ -2962,14 +2958,6 @@
return self.get_config(
).get_user_option_as_bool('append_revisions_only')
- @needs_write_lock
- def generate_revision_history(self, revision_id, last_rev=None,
- other_branch=None):
- """See BzrBranch5.generate_revision_history"""
- history = self._lefthand_history(revision_id, last_rev, other_branch)
- revno = len(history)
- self.set_last_revision_info(revno, revision_id)
-
@needs_read_lock
def get_rev_id(self, revno, history=None):
"""Find the revision id of the specified revno."""
=== modified file 'bzrlib/plugins/weave_fmt/branch.py'
--- a/bzrlib/plugins/weave_fmt/branch.py 2011-03-10 13:29:54 +0000
+++ b/bzrlib/plugins/weave_fmt/branch.py 2011-04-19 17:14:47 +0000
@@ -25,11 +25,12 @@
from bzrlib.branch import (
BranchFormat,
- BzrBranch,
+ FullHistoryBzrBranch,
)
-class PreSplitOutBzrBranch(BzrBranch):
+class BzrBranch4(FullHistoryBzrBranch):
+ """Branch format 4."""
def _get_checkout_format(self):
"""Return the most suitable metadir for a checkout of this branch.
@@ -40,6 +41,24 @@
format.repository_format = RepositoryFormat7()
return format
+ def unbind(self):
+ raise errors.UpgradeRequired(self.user_url)
+
+ def bind(self, other):
+ raise errors.UpgradeRequired(self.user_url)
+
+ def set_bound_location(self, location):
+ raise NotImplementedError(self.set_bound_location)
+
+ def get_bound_location(self):
+ return None
+
+ def update(self):
+ return None
+
+ def get_master_branch(self, possible_transports=None):
+ return None
+
class BzrBranchFormat4(BranchFormat):
"""Bzr branch format 4.
@@ -47,6 +66,8 @@
This format has:
- a revision-history file.
- a branch-lock lock file [ to be shared with the bzrdir ]
+
+ It does not support binding.
"""
def initialize(self, a_bzrdir, name=None, repository=None):
@@ -115,7 +136,7 @@
raise NotImplementedError
if found_repository is None:
found_repository = a_bzrdir.open_repository()
- return PreSplitOutBzrBranch(_format=self,
+ return BzrBranch4(_format=self,
_control_files=a_bzrdir._control_files,
a_bzrdir=a_bzrdir,
name=name,
=== modified file 'bzrlib/remote.py'
--- a/bzrlib/remote.py 2011-05-04 03:43:03 +0000
+++ b/bzrlib/remote.py 2011-05-09 07:24:22 +0000
@@ -2849,7 +2849,7 @@
missing_parent = parent_map[missing_parent]
raise errors.RevisionNotPresent(missing_parent, self.repository)
- def _last_revision_info(self):
+ def _read_last_revision_info(self):
response = self._call('Branch.last_revision_info', self._remote_path())
if response[0] != 'ok':
raise SmartProtocolError('unexpected response code %s' % (response,))
=== modified file 'bzrlib/tests/per_workingtree/test_workingtree.py'
--- a/bzrlib/tests/per_workingtree/test_workingtree.py 2011-05-06 15:15:44 +0000
+++ b/bzrlib/tests/per_workingtree/test_workingtree.py 2011-05-08 13:50:25 +0000
@@ -26,6 +26,7 @@
bzrdir,
errors,
osutils,
+ symbol_versioning,
tests,
urlutils,
)
@@ -326,7 +327,8 @@
# because some formats mutate the branch to set it on the tree
# we need to alter the branch to let this pass.
try:
- wt.branch._set_revision_history(['A', 'B'])
+ self.applyDeprecated(symbol_versioning.deprecated_in((2, 4, 0)),
+ wt.branch.set_revision_history, ['A', 'B'])
except errors.NoSuchRevision, e:
self.assertEqual('B', e.revision)
raise TestSkipped("Branch format does not permit arbitrary"
=== modified file 'bzrlib/tests/test_branch.py'
--- a/bzrlib/tests/test_branch.py 2011-04-19 14:19:50 +0000
+++ b/bzrlib/tests/test_branch.py 2011-05-01 21:02:50 +0000
@@ -74,7 +74,7 @@
url = self.get_url()
bdir = bzrdir.BzrDirMetaFormat1().initialize(url)
bdir.create_repository()
- branch = bdir.create_branch()
+ branch = _mod_branch.BzrBranchFormat5().initialize(bdir)
t = self.get_transport()
self.log("branch instance is %r" % branch)
self.assert_(isinstance(branch, _mod_branch.BzrBranch5))
=== modified file 'bzrlib/workingtree.py'
--- a/bzrlib/workingtree.py 2011-05-04 22:23:20 +0000
+++ b/bzrlib/workingtree.py 2011-05-08 13:50:25 +0000
@@ -1228,6 +1228,7 @@
if _mod_revision.is_null(new_revision):
self.branch.set_last_revision_info(0, new_revision)
return False
+ _mod_revision.check_not_reserved_id(new_revision)
try:
self.branch.generate_revision_history(new_revision)
except errors.NoSuchRevision:
=== modified file 'doc/en/release-notes/bzr-2.4.txt'
--- a/doc/en/release-notes/bzr-2.4.txt 2011-05-09 08:12:01 +0000
+++ b/doc/en/release-notes/bzr-2.4.txt 2011-05-09 10:05:41 +0000
@@ -70,6 +70,12 @@
compatible optimisers rather than an instance of the class it is called
on. (Jelmer Vernooij)
+* The default implementation of ``Branch`` is now oriented to
+ storing the branch tip. Branch implementations which store the full
+ history should now subclass ``FullHistoryBzrBranch``.
+ ``Branch._last_revision_info`` has been renamed to
+ ``Branch._read_last_revision_info`` (Jelmer Vernooij)
+
Internals
*********
More information about the bazaar-commits
mailing list