14
14
# along with this program; if not, write to the Free Software
15
15
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
17
from __future__ import absolute_import
18
21
from cStringIO import StringIO
21
from bzrlib.lazy_import import lazy_import
23
from brzlib.lazy_import import lazy_import
22
24
lazy_import(globals(), """
23
from itertools import chain
27
config as _mod_config,
33
revision as _mod_revision,
41
from bzrlib.config import BranchConfig, TransportConfig
42
from bzrlib.repofmt.pack_repo import RepositoryFormatKnitPack5RichRoot
43
from bzrlib.tag import (
31
config as _mod_config,
40
revision as _mod_revision,
49
from brzlib.i18n import gettext, ngettext
49
from bzrlib.decorators import needs_read_lock, needs_write_lock, only_raises
50
from bzrlib.hooks import HookPoint, Hooks
51
from bzrlib.inter import InterObject
52
from bzrlib.lock import _RelockDebugMixin, LogicalLockResult
53
from bzrlib import registry
54
from bzrlib.symbol_versioning import (
52
# Explicitly import brzlib.bzrdir so that the BzrProber
53
# is guaranteed to be registered.
60
from brzlib.decorators import (
65
from brzlib.hooks import Hooks
66
from brzlib.inter import InterObject
67
from brzlib.lock import _RelockDebugMixin, LogicalLockResult
68
from brzlib import registry
69
from brzlib.symbol_versioning import (
58
from bzrlib.trace import mutter, mutter_callsite, note, is_quiet
61
BZR_BRANCH_FORMAT_4 = "Bazaar-NG branch, format 0.0.4\n"
62
BZR_BRANCH_FORMAT_5 = "Bazaar-NG branch, format 5\n"
63
BZR_BRANCH_FORMAT_6 = "Bazaar Branch Format 6 (bzr 0.15)\n"
66
class Branch(bzrdir.ControlComponent):
73
from brzlib.trace import mutter, mutter_callsite, note, is_quiet
76
class Branch(controldir.ControlComponent):
67
77
"""Branch holding a history of revisions.
70
80
Base directory/url of the branch; using control_url and
71
81
control_transport is more standardized.
73
hooks: An instance of BranchHooks.
82
:ivar hooks: An instance of BranchHooks.
83
:ivar _master_branch_cache: cached result of get_master_branch, see
75
86
# this is really an instance variable - FIXME move it there
792
879
old_repository = self.repository
793
880
if len(old_repository._fallback_repositories) != 1:
794
881
raise AssertionError("can't cope with fallback repositories "
795
"of %r" % (self.repository,))
796
# unlock it, including unlocking the fallback
882
"of %r (fallbacks: %r)" % (old_repository,
883
old_repository._fallback_repositories))
884
# Open the new repository object.
885
# Repositories don't offer an interface to remove fallback
886
# repositories today; take the conceptually simpler option and just
887
# reopen it. We reopen it starting from the URL so that we
888
# get a separate connection for RemoteRepositories and can
889
# stream from one of them to the other. This does mean doing
890
# separate SSH connection setup, but unstacking is not a
891
# common operation so it's tolerable.
892
new_bzrdir = controldir.ControlDir.open(
893
self.bzrdir.root_transport.base)
894
new_repository = new_bzrdir.find_repository()
895
if new_repository._fallback_repositories:
896
raise AssertionError("didn't expect %r to have "
897
"fallback_repositories"
898
% (self.repository,))
899
# Replace self.repository with the new repository.
900
# Do our best to transfer the lock state (i.e. lock-tokens and
901
# lock count) of self.repository to the new repository.
902
lock_token = old_repository.lock_write().repository_token
903
self.repository = new_repository
904
if isinstance(self, remote.RemoteBranch):
905
# Remote branches can have a second reference to the old
906
# repository that need to be replaced.
907
if self._real_branch is not None:
908
self._real_branch.repository = new_repository
909
self.repository.lock_write(token=lock_token)
910
if lock_token is not None:
911
old_repository.leave_lock_in_place()
797
912
old_repository.unlock()
913
if lock_token is not None:
914
# XXX: self.repository.leave_lock_in_place() before this
915
# function will not be preserved. Fortunately that doesn't
916
# affect the current default format (2a), and would be a
917
# corner-case anyway.
918
# - Andrew Bennetts, 2010/06/30
919
self.repository.dont_leave_lock_in_place()
923
old_repository.unlock()
924
except errors.LockNotHeld:
927
if old_lock_count == 0:
928
raise AssertionError(
929
'old_repository should have been locked at least once.')
930
for i in range(old_lock_count-1):
931
self.repository.lock_write()
932
# Fetch from the old repository into the new.
798
933
old_repository.lock_read()
800
# Repositories don't offer an interface to remove fallback
801
# repositories today; take the conceptually simpler option and just
802
# reopen it. We reopen it starting from the URL so that we
803
# get a separate connection for RemoteRepositories and can
804
# stream from one of them to the other. This does mean doing
805
# separate SSH connection setup, but unstacking is not a
806
# common operation so it's tolerable.
807
new_bzrdir = bzrdir.BzrDir.open(self.bzrdir.root_transport.base)
808
new_repository = new_bzrdir.find_repository()
809
self.repository = new_repository
810
if self.repository._fallback_repositories:
811
raise AssertionError("didn't expect %r to have "
812
"fallback_repositories"
813
% (self.repository,))
814
# this is not paired with an unlock because it's just restoring
815
# the previous state; the lock's released when set_stacked_on_url
817
self.repository.lock_write()
818
935
# XXX: If you unstack a branch while it has a working tree
819
936
# with a pending merge, the pending-merged revisions will no
820
937
# longer be present. You can (probably) revert and remerge.
822
# XXX: This only fetches up to the tip of the repository; it
823
# doesn't bring across any tags. That's fairly consistent
824
# with how branch works, but perhaps not ideal.
825
self.repository.fetch(old_repository,
826
revision_id=self.last_revision(),
939
tags_to_fetch = set(self.tags.get_reverse_tag_dict())
940
except errors.TagsNotSupported:
941
tags_to_fetch = set()
942
fetch_spec = vf_search.NotInOtherForRevs(self.repository,
943
old_repository, required_ids=[self.last_revision()],
944
if_present_ids=tags_to_fetch, find_ghosts=True).execute()
945
self.repository.fetch(old_repository, fetch_spec=fetch_spec)
829
947
old_repository.unlock()
927
1046
:return: A tuple (revno, revision_id).
929
1048
if self._last_revision_info_cache is None:
930
self._last_revision_info_cache = self._last_revision_info()
1049
self._last_revision_info_cache = self._read_last_revision_info()
931
1050
return self._last_revision_info_cache
933
def _last_revision_info(self):
934
rh = self.revision_history()
937
return (revno, rh[-1])
939
return (0, _mod_revision.NULL_REVISION)
941
@deprecated_method(deprecated_in((1, 6, 0)))
942
def missing_revisions(self, other, stop_revision=None):
943
"""Return a list of new revisions that would perfectly fit.
945
If self and other have not diverged, return a list of the revisions
946
present in other, but missing from self.
948
self_history = self.revision_history()
949
self_len = len(self_history)
950
other_history = other.revision_history()
951
other_len = len(other_history)
952
common_index = min(self_len, other_len) -1
953
if common_index >= 0 and \
954
self_history[common_index] != other_history[common_index]:
955
raise errors.DivergedBranches(self, other)
957
if stop_revision is None:
958
stop_revision = other_len
960
if stop_revision > other_len:
961
raise errors.NoSuchRevision(self, stop_revision)
962
return other_history[self_len:stop_revision]
965
def update_revisions(self, other, stop_revision=None, overwrite=False,
967
"""Pull in new perfect-fit revisions.
969
:param other: Another Branch to pull from
970
:param stop_revision: Updated until the given revision
971
:param overwrite: Always set the branch pointer, rather than checking
972
to see if it is a proper descendant.
973
:param graph: A Graph object that can be used to query history
974
information. This can be None.
977
return InterBranch.get(other, self).update_revisions(stop_revision,
980
def import_last_revision_info(self, source_repo, revno, revid):
1052
def _read_last_revision_info(self):
1053
raise NotImplementedError(self._read_last_revision_info)
1055
def import_last_revision_info_and_tags(self, source, revno, revid,
981
1057
"""Set the last revision info, importing from another repo if necessary.
983
1059
This is used by the bound branch code to upload a revision to
984
1060
the master branch first before updating the tip of the local branch.
1061
Revisions referenced by source's tags are also transferred.
986
:param source_repo: Source repository to optionally fetch from
1063
:param source: Source branch to optionally fetch from
987
1064
:param revno: Revision number of the new tip
988
1065
:param revid: Revision id of the new tip
1066
:param lossy: Whether to discard metadata that can not be
1067
natively represented
1068
:return: Tuple with the new revision number and revision id
1069
(should only be different from the arguments when lossy=True)
990
if not self.repository.has_same_location(source_repo):
991
self.repository.fetch(source_repo, revision_id=revid)
1071
if not self.repository.has_same_location(source.repository):
1072
self.fetch(source, revid)
992
1073
self.set_last_revision_info(revno, revid)
1074
return (revno, revid)
994
1076
def revision_id_to_revno(self, revision_id):
995
1077
"""Given a revision id, return its revno"""
996
1078
if _mod_revision.is_null(revision_id):
998
history = self.revision_history()
1080
history = self._revision_history()
1000
1082
return history.index(revision_id) + 1
1001
1083
except ValueError:
1500
1589
object will be created every time regardless.
1503
_default_format = None
1504
"""The default format used for new branches."""
1507
"""The known formats."""
1509
can_set_append_revisions_only = True
1511
1592
def __eq__(self, other):
1512
1593
return self.__class__ is other.__class__
1514
1595
def __ne__(self, other):
1515
1596
return not (self == other)
1518
def find_format(klass, a_bzrdir, name=None):
1519
"""Return the format for the branch object in a_bzrdir."""
1521
transport = a_bzrdir.get_branch_transport(None, name=name)
1522
format_string = transport.get_bytes("format")
1523
return klass._formats[format_string]
1524
except errors.NoSuchFile:
1525
raise errors.NotBranchError(path=transport.base, bzrdir=a_bzrdir)
1527
raise errors.UnknownFormatError(format=format_string, kind='branch')
1530
def get_default_format(klass):
1531
"""Return the current default format."""
1532
return klass._default_format
1534
def get_reference(self, a_bzrdir):
1535
"""Get the target reference of the branch in a_bzrdir.
1598
def get_reference(self, controldir, name=None):
1599
"""Get the target reference of the branch in controldir.
1537
1601
format probing must have been completed before calling
1538
1602
this method - it is assumed that the format of the branch
1539
in a_bzrdir is correct.
1603
in controldir is correct.
1541
:param a_bzrdir: The bzrdir to get the branch data from.
1605
:param controldir: The controldir to get the branch data from.
1606
:param name: Name of the colocated branch to fetch
1542
1607
:return: None if the branch is not a reference branch.
1547
def set_reference(self, a_bzrdir, to_branch):
1548
"""Set the target reference of the branch in a_bzrdir.
1612
def set_reference(self, controldir, name, to_branch):
1613
"""Set the target reference of the branch in controldir.
1550
1615
format probing must have been completed before calling
1551
1616
this method - it is assumed that the format of the branch
1552
in a_bzrdir is correct.
1617
in controldir is correct.
1554
:param a_bzrdir: The bzrdir to set the branch reference for.
1619
:param controldir: The controldir to set the branch reference for.
1620
:param name: Name of colocated branch to set, None for default
1555
1621
:param to_branch: branch that the checkout is to reference
1557
1623
raise NotImplementedError(self.set_reference)
1559
def get_format_string(self):
1560
"""Return the ASCII format string that identifies this format."""
1561
raise NotImplementedError(self.get_format_string)
1563
1625
def get_format_description(self):
1564
1626
"""Return the short format description for this format."""
1565
1627
raise NotImplementedError(self.get_format_description)
1567
def _run_post_branch_init_hooks(self, a_bzrdir, name, branch):
1629
def _run_post_branch_init_hooks(self, controldir, name, branch):
1568
1630
hooks = Branch.hooks['post_branch_init']
1571
params = BranchInitHookParams(self, a_bzrdir, name, branch)
1633
params = BranchInitHookParams(self, controldir, name, branch)
1572
1634
for hook in hooks:
1575
def _initialize_helper(self, a_bzrdir, utf8_files, name=None,
1576
lock_type='metadir', set_format=True):
1577
"""Initialize a branch in a bzrdir, with specified files
1579
:param a_bzrdir: The bzrdir to initialize the branch in
1580
:param utf8_files: The files to create as a list of
1581
(filename, content) tuples
1582
:param name: Name of colocated branch to create, if any
1583
:param set_format: If True, set the format with
1584
self.get_format_string. (BzrBranch4 has its format set
1586
:return: a branch in this format
1588
mutter('creating branch %r in %s', self, a_bzrdir.user_url)
1589
branch_transport = a_bzrdir.get_branch_transport(self, name=name)
1591
'metadir': ('lock', lockdir.LockDir),
1592
'branch4': ('branch-lock', lockable_files.TransportLock),
1594
lock_name, lock_class = lock_map[lock_type]
1595
control_files = lockable_files.LockableFiles(branch_transport,
1596
lock_name, lock_class)
1597
control_files.create_lock()
1599
control_files.lock_write()
1600
except errors.LockContention:
1601
if lock_type != 'branch4':
1607
utf8_files += [('format', self.get_format_string())]
1609
for (filename, content) in utf8_files:
1610
branch_transport.put_bytes(
1612
mode=a_bzrdir._get_file_mode())
1615
control_files.unlock()
1616
branch = self.open(a_bzrdir, name, _found=True)
1617
self._run_post_branch_init_hooks(a_bzrdir, name, branch)
1620
def initialize(self, a_bzrdir, name=None):
1621
"""Create a branch of this format in a_bzrdir.
1637
def initialize(self, controldir, name=None, repository=None,
1638
append_revisions_only=None):
1639
"""Create a branch of this format in controldir.
1623
1641
:param name: Name of the colocated branch to create.
1625
1643
raise NotImplementedError(self.initialize)
1741
1778
"basis revision. hooks MUST NOT modify this delta. "
1742
1779
" future_tree is an in-memory tree obtained from "
1743
1780
"CommitBuilder.revision_tree() and hooks MUST NOT modify this "
1744
"tree.", (0,91), None))
1745
self.create_hook(HookPoint('post_commit',
1782
self.add_hook('post_commit',
1746
1783
"Called in the bzr client after a commit has completed. "
1747
1784
"post_commit is called with (local, master, old_revno, old_revid, "
1748
1785
"new_revno, new_revid). old_revid is NULL_REVISION for the first "
1749
"commit to a branch.", (0, 15), None))
1750
self.create_hook(HookPoint('post_uncommit',
1786
"commit to a branch.", (0, 15))
1787
self.add_hook('post_uncommit',
1751
1788
"Called in the bzr client after an uncommit completes. "
1752
1789
"post_uncommit is called with (local, master, old_revno, "
1753
1790
"old_revid, new_revno, new_revid) where local is the local branch "
1754
1791
"or None, master is the target branch, and an empty branch "
1755
"receives new_revno of 0, new_revid of None.", (0, 15), None))
1756
self.create_hook(HookPoint('pre_change_branch_tip',
1792
"receives new_revno of 0, new_revid of None.", (0, 15))
1793
self.add_hook('pre_change_branch_tip',
1757
1794
"Called in bzr client and server before a change to the tip of a "
1758
1795
"branch is made. pre_change_branch_tip is called with a "
1759
"bzrlib.branch.ChangeBranchTipParams. Note that push, pull, "
1760
"commit, uncommit will all trigger this hook.", (1, 6), None))
1761
self.create_hook(HookPoint('post_change_branch_tip',
1796
"brzlib.branch.ChangeBranchTipParams. Note that push, pull, "
1797
"commit, uncommit will all trigger this hook.", (1, 6))
1798
self.add_hook('post_change_branch_tip',
1762
1799
"Called in bzr client and server after a change to the tip of a "
1763
1800
"branch is made. post_change_branch_tip is called with a "
1764
"bzrlib.branch.ChangeBranchTipParams. Note that push, pull, "
1765
"commit, uncommit will all trigger this hook.", (1, 4), None))
1766
self.create_hook(HookPoint('transform_fallback_location',
1801
"brzlib.branch.ChangeBranchTipParams. Note that push, pull, "
1802
"commit, uncommit will all trigger this hook.", (1, 4))
1803
self.add_hook('transform_fallback_location',
1767
1804
"Called when a stacked branch is activating its fallback "
1768
1805
"locations. transform_fallback_location is called with (branch, "
1769
1806
"url), and should return a new url. Returning the same url "
1914
1946
self.revision_id)
1917
class BzrBranchFormat4(BranchFormat):
1918
"""Bzr branch format 4.
1921
- a revision-history file.
1922
- a branch-lock lock file [ to be shared with the bzrdir ]
1949
class BranchFormatMetadir(bzrdir.BzrFormat, BranchFormat):
1950
"""Base class for branch formats that live in meta directories.
1925
def get_format_description(self):
1926
"""See BranchFormat.get_format_description()."""
1927
return "Branch format 4"
1929
def initialize(self, a_bzrdir, name=None):
1930
"""Create a branch of this format in a_bzrdir."""
1931
utf8_files = [('revision-history', ''),
1932
('branch-name', ''),
1934
return self._initialize_helper(a_bzrdir, utf8_files, name=name,
1935
lock_type='branch4', set_format=False)
1937
1953
def __init__(self):
1938
super(BzrBranchFormat4, self).__init__()
1939
self._matchingbzrdir = bzrdir.BzrDirFormat6()
1941
def network_name(self):
1942
"""The network name for this format is the control dirs disk label."""
1943
return self._matchingbzrdir.get_format_string()
1945
def open(self, a_bzrdir, name=None, _found=False, ignore_fallbacks=False):
1946
"""See BranchFormat.open()."""
1948
# we are being called directly and must probe.
1949
raise NotImplementedError
1950
return BzrBranch(_format=self,
1951
_control_files=a_bzrdir._control_files,
1954
_repository=a_bzrdir.open_repository())
1957
return "Bazaar-NG branch format 4"
1960
class BranchFormatMetadir(BranchFormat):
1961
"""Common logic for meta-dir based branch formats."""
1954
BranchFormat.__init__(self)
1955
bzrdir.BzrFormat.__init__(self)
1958
def find_format(klass, controldir, name=None):
1959
"""Return the format for the branch object in controldir."""
1961
transport = controldir.get_branch_transport(None, name=name)
1962
except errors.NoSuchFile:
1963
raise errors.NotBranchError(path=name, bzrdir=controldir)
1965
format_string = transport.get_bytes("format")
1966
except errors.NoSuchFile:
1967
raise errors.NotBranchError(path=transport.base, bzrdir=controldir)
1968
return klass._find_format(format_registry, 'branch', format_string)
1963
1970
def _branch_class(self):
1964
1971
"""What class to instantiate on open calls."""
1965
1972
raise NotImplementedError(self._branch_class)
1967
def network_name(self):
1968
"""A simple byte string uniquely identifying this format for RPC calls.
1970
Metadir branch formats use their format string.
1974
def _get_initial_config(self, append_revisions_only=None):
1975
if append_revisions_only:
1976
return "append_revisions_only = True\n"
1978
# Avoid writing anything if append_revisions_only is disabled,
1979
# as that is the default.
1982
def _initialize_helper(self, a_bzrdir, utf8_files, name=None,
1984
"""Initialize a branch in a control dir, with specified files
1986
:param a_bzrdir: The bzrdir to initialize the branch in
1987
:param utf8_files: The files to create as a list of
1988
(filename, content) tuples
1989
:param name: Name of colocated branch to create, if any
1990
:return: a branch in this format
1972
return self.get_format_string()
1993
name = a_bzrdir._get_selected_branch()
1994
mutter('creating branch %r in %s', self, a_bzrdir.user_url)
1995
branch_transport = a_bzrdir.get_branch_transport(self, name=name)
1996
control_files = lockable_files.LockableFiles(branch_transport,
1997
'lock', lockdir.LockDir)
1998
control_files.create_lock()
1999
control_files.lock_write()
2001
utf8_files += [('format', self.as_string())]
2002
for (filename, content) in utf8_files:
2003
branch_transport.put_bytes(
2005
mode=a_bzrdir._get_file_mode())
2007
control_files.unlock()
2008
branch = self.open(a_bzrdir, name, _found=True,
2009
found_repository=repository)
2010
self._run_post_branch_init_hooks(a_bzrdir, name, branch)
1974
def open(self, a_bzrdir, name=None, _found=False, ignore_fallbacks=False):
2013
def open(self, a_bzrdir, name=None, _found=False, ignore_fallbacks=False,
2014
found_repository=None, possible_transports=None):
1975
2015
"""See BranchFormat.open()."""
2017
name = a_bzrdir._get_selected_branch()
1977
format = BranchFormat.find_format(a_bzrdir, name=name)
2019
format = BranchFormatMetadir.find_format(a_bzrdir, name=name)
1978
2020
if format.__class__ != self.__class__:
1979
2021
raise AssertionError("wrong format %r found for %r" %
1980
2022
(format, self))
1983
2025
control_files = lockable_files.LockableFiles(transport, 'lock',
1984
2026
lockdir.LockDir)
2027
if found_repository is None:
2028
found_repository = a_bzrdir.find_repository()
1985
2029
return self._branch_class()(_format=self,
1986
2030
_control_files=control_files,
1988
2032
a_bzrdir=a_bzrdir,
1989
_repository=a_bzrdir.find_repository(),
1990
ignore_fallbacks=ignore_fallbacks)
2033
_repository=found_repository,
2034
ignore_fallbacks=ignore_fallbacks,
2035
possible_transports=possible_transports)
1991
2036
except errors.NoSuchFile:
1992
2037
raise errors.NotBranchError(path=transport.base, bzrdir=a_bzrdir)
1995
super(BranchFormatMetadir, self).__init__()
1996
self._matchingbzrdir = bzrdir.BzrDirMetaFormat1()
1997
self._matchingbzrdir.set_branch_format(self)
1999
def supports_tags(self):
2003
class BzrBranchFormat5(BranchFormatMetadir):
2004
"""Bzr branch format 5.
2007
- a revision-history file.
2009
- a lock dir guarding the branch itself
2010
- all of this stored in a branch/ subdirectory
2011
- works with shared repositories.
2013
This format is new in bzr 0.8.
2016
def _branch_class(self):
2019
def get_format_string(self):
2020
"""See BranchFormat.get_format_string()."""
2021
return "Bazaar-NG branch format 5\n"
2023
def get_format_description(self):
2024
"""See BranchFormat.get_format_description()."""
2025
return "Branch format 5"
2027
def initialize(self, a_bzrdir, name=None):
2028
"""Create a branch of this format in a_bzrdir."""
2029
utf8_files = [('revision-history', ''),
2030
('branch-name', ''),
2032
return self._initialize_helper(a_bzrdir, utf8_files, name)
2034
def supports_tags(self):
2040
def _matchingbzrdir(self):
2041
ret = bzrdir.BzrDirMetaFormat1()
2042
ret.set_branch_format(self)
2045
def supports_tags(self):
2048
def supports_leaving_lock(self):
2051
def check_support_status(self, allow_unsupported, recommend_upgrade=True,
2053
BranchFormat.check_support_status(self,
2054
allow_unsupported=allow_unsupported, recommend_upgrade=recommend_upgrade,
2056
bzrdir.BzrFormat.check_support_status(self, allow_unsupported=allow_unsupported,
2057
recommend_upgrade=recommend_upgrade, basedir=basedir)
2038
2060
class BzrBranchFormat6(BranchFormatMetadir):
2167
2201
"""See BranchFormat.get_format_description()."""
2168
2202
return "Checkout reference format 1"
2170
def get_reference(self, a_bzrdir):
2204
def get_reference(self, a_bzrdir, name=None):
2171
2205
"""See BranchFormat.get_reference()."""
2172
transport = a_bzrdir.get_branch_transport(None)
2206
transport = a_bzrdir.get_branch_transport(None, name=name)
2173
2207
return transport.get_bytes('location')
2175
def set_reference(self, a_bzrdir, to_branch):
2209
def set_reference(self, a_bzrdir, name, to_branch):
2176
2210
"""See BranchFormat.set_reference()."""
2177
transport = a_bzrdir.get_branch_transport(None)
2211
transport = a_bzrdir.get_branch_transport(None, name=name)
2178
2212
location = transport.put_bytes('location', to_branch.base)
2180
def initialize(self, a_bzrdir, name=None, target_branch=None):
2214
def initialize(self, a_bzrdir, name=None, target_branch=None,
2215
repository=None, append_revisions_only=None):
2181
2216
"""Create a branch of this format in a_bzrdir."""
2182
2217
if target_branch is None:
2183
2218
# this format does not implement branch itself, thus the implicit
2184
2219
# creation contract must see it as uninitializable
2185
2220
raise errors.UninitializableFormat(self)
2186
2221
mutter('creating branch reference in %s', a_bzrdir.user_url)
2222
if a_bzrdir._format.fixed_components:
2223
raise errors.IncompatibleFormat(self, a_bzrdir._format)
2225
name = a_bzrdir._get_selected_branch()
2187
2226
branch_transport = a_bzrdir.get_branch_transport(self, name=name)
2188
2227
branch_transport.put_bytes('location',
2189
target_branch.bzrdir.user_url)
2190
branch_transport.put_bytes('format', self.get_format_string())
2192
a_bzrdir, name, _found=True,
2228
target_branch.user_url)
2229
branch_transport.put_bytes('format', self.as_string())
2230
branch = self.open(a_bzrdir, name, _found=True,
2193
2231
possible_transports=[target_branch.bzrdir.root_transport])
2194
2232
self._run_post_branch_init_hooks(a_bzrdir, name, branch)
2198
super(BranchReferenceFormat, self).__init__()
2199
self._matchingbzrdir = bzrdir.BzrDirMetaFormat1()
2200
self._matchingbzrdir.set_branch_format(self)
2202
2235
def _make_reference_clone_function(format, a_branch):
2203
2236
"""Create a clone() routine for a branch dynamically."""
2204
2237
def clone(to_bzrdir, revision_id=None,
2426
2514
"""See Branch.print_file."""
2427
2515
return self.repository.print_file(file, revision_id)
2429
def _write_revision_history(self, history):
2430
"""Factored out of set_revision_history.
2432
This performs the actual writing to disk.
2433
It is intended to be called by BzrBranch5.set_revision_history."""
2434
self._transport.put_bytes(
2435
'revision-history', '\n'.join(history),
2436
mode=self.bzrdir._get_file_mode())
2439
def set_revision_history(self, rev_history):
2440
"""See Branch.set_revision_history."""
2441
if 'evil' in debug.debug_flags:
2442
mutter_callsite(3, "set_revision_history scales with history.")
2443
check_not_reserved_id = _mod_revision.check_not_reserved_id
2444
for rev_id in rev_history:
2445
check_not_reserved_id(rev_id)
2446
if Branch.hooks['post_change_branch_tip']:
2447
# Don't calculate the last_revision_info() if there are no hooks
2449
old_revno, old_revid = self.last_revision_info()
2450
if len(rev_history) == 0:
2451
revid = _mod_revision.NULL_REVISION
2453
revid = rev_history[-1]
2454
self._run_pre_change_branch_tip_hooks(len(rev_history), revid)
2455
self._write_revision_history(rev_history)
2456
self._clear_cached_state()
2457
self._cache_revision_history(rev_history)
2458
for hook in Branch.hooks['set_rh']:
2459
hook(self, rev_history)
2460
if Branch.hooks['post_change_branch_tip']:
2461
self._run_post_change_branch_tip_hooks(old_revno, old_revid)
2463
def _synchronize_history(self, destination, revision_id):
2464
"""Synchronize last revision and revision history between branches.
2466
This version is most efficient when the destination is also a
2467
BzrBranch5, but works for BzrBranch6 as long as the revision
2468
history is the true lefthand parent history, and all of the revisions
2469
are in the destination's repository. If not, set_revision_history
2472
:param destination: The branch to copy the history into
2473
:param revision_id: The revision-id to truncate history at. May
2474
be None to copy complete history.
2476
if not isinstance(destination._format, BzrBranchFormat5):
2477
super(BzrBranch, self)._synchronize_history(
2478
destination, revision_id)
2480
if revision_id == _mod_revision.NULL_REVISION:
2483
new_history = self.revision_history()
2484
if revision_id is not None and new_history != []:
2486
new_history = new_history[:new_history.index(revision_id) + 1]
2488
rev = self.repository.get_revision(revision_id)
2489
new_history = rev.get_history(self.repository)[1:]
2490
destination.set_revision_history(new_history)
2492
2517
@needs_write_lock
2493
2518
def set_last_revision_info(self, revno, revision_id):
2494
"""Set the last revision of this branch.
2496
The caller is responsible for checking that the revno is correct
2497
for this revision id.
2499
It may be possible to set the branch last revision to an id not
2500
present in the repository. However, branches can also be
2501
configured to check constraints on history, in which case this may not
2519
if not revision_id or not isinstance(revision_id, basestring):
2520
raise errors.InvalidRevisionId(revision_id=revision_id, branch=self)
2504
2521
revision_id = _mod_revision.ensure_null(revision_id)
2505
# this old format stores the full history, but this api doesn't
2506
# provide it, so we must generate, and might as well check it's
2508
history = self._lefthand_history(revision_id)
2509
if len(history) != revno:
2510
raise AssertionError('%d != %d' % (len(history), revno))
2511
self.set_revision_history(history)
2513
def _gen_revision_history(self):
2514
history = self._transport.get_bytes('revision-history').split('\n')
2515
if history[-1:] == ['']:
2516
# There shouldn't be a trailing newline, but just in case.
2521
def generate_revision_history(self, revision_id, last_rev=None,
2523
"""Create a new revision history that will finish with revision_id.
2525
:param revision_id: the new tip to use.
2526
:param last_rev: The previous last_revision. If not None, then this
2527
must be a ancestory of revision_id, or DivergedBranches is raised.
2528
:param other_branch: The other branch that DivergedBranches should
2529
raise with respect to.
2531
self.set_revision_history(self._lefthand_history(revision_id,
2532
last_rev, other_branch))
2522
old_revno, old_revid = self.last_revision_info()
2523
if self.get_append_revisions_only():
2524
self._check_history_violation(revision_id)
2525
self._run_pre_change_branch_tip_hooks(revno, revision_id)
2526
self._write_last_revision_info(revno, revision_id)
2527
self._clear_cached_state()
2528
self._last_revision_info_cache = revno, revision_id
2529
self._run_post_change_branch_tip_hooks(old_revno, old_revid)
2534
2531
def basis_tree(self):
2535
2532
"""See Branch.basis_tree."""
2713
2715
self._last_revision_info_cache = None
2714
2716
self._reference_info = None
2716
def _last_revision_info(self):
2717
revision_string = self._transport.get_bytes('last-revision')
2718
revno, revision_id = revision_string.rstrip('\n').split(' ', 1)
2719
revision_id = cache_utf8.get_cached_utf8(revision_id)
2721
return revno, revision_id
2723
def _write_last_revision_info(self, revno, revision_id):
2724
"""Simply write out the revision id, with no checks.
2726
Use set_last_revision_info to perform this safely.
2728
Does not update the revision_history cache.
2729
Intended to be called by set_last_revision_info and
2730
_write_revision_history.
2732
revision_id = _mod_revision.ensure_null(revision_id)
2733
out_string = '%d %s\n' % (revno, revision_id)
2734
self._transport.put_bytes('last-revision', out_string,
2735
mode=self.bzrdir._get_file_mode())
2738
def set_last_revision_info(self, revno, revision_id):
2739
revision_id = _mod_revision.ensure_null(revision_id)
2740
old_revno, old_revid = self.last_revision_info()
2741
if self._get_append_revisions_only():
2742
self._check_history_violation(revision_id)
2743
self._run_pre_change_branch_tip_hooks(revno, revision_id)
2744
self._write_last_revision_info(revno, revision_id)
2745
self._clear_cached_state()
2746
self._last_revision_info_cache = revno, revision_id
2747
self._run_post_change_branch_tip_hooks(old_revno, old_revid)
2749
def _synchronize_history(self, destination, revision_id):
2750
"""Synchronize last revision and revision history between branches.
2752
:see: Branch._synchronize_history
2754
# XXX: The base Branch has a fast implementation of this method based
2755
# on set_last_revision_info, but BzrBranch/BzrBranch5 have a slower one
2756
# that uses set_revision_history. This class inherits from BzrBranch5,
2757
# but wants the fast implementation, so it calls
2758
# Branch._synchronize_history directly.
2759
Branch._synchronize_history(self, destination, revision_id)
2761
2718
def _check_history_violation(self, revision_id):
2762
last_revision = _mod_revision.ensure_null(self.last_revision())
2719
current_revid = self.last_revision()
2720
last_revision = _mod_revision.ensure_null(current_revid)
2763
2721
if _mod_revision.is_null(last_revision):
2765
if last_revision not in self._lefthand_history(revision_id):
2766
raise errors.AppendRevisionsOnlyViolation(self.user_url)
2723
graph = self.repository.get_graph()
2724
for lh_ancestor in graph.iter_lefthand_ancestry(revision_id):
2725
if lh_ancestor == current_revid:
2727
raise errors.AppendRevisionsOnlyViolation(self.user_url)
2768
2729
def _gen_revision_history(self):
2769
2730
"""Generate the revision history from last revision
3221
3143
raise NotImplementedError(self.push)
3146
def copy_content_into(self, revision_id=None):
3147
"""Copy the content of source into target
3149
revision_id: if not None, the revision history in the new branch will
3150
be truncated to end with revision_id.
3152
raise NotImplementedError(self.copy_content_into)
3155
def fetch(self, stop_revision=None, limit=None):
3158
:param stop_revision: Last revision to fetch
3159
:param limit: Optional rough limit of revisions to fetch
3161
raise NotImplementedError(self.fetch)
3164
def _fix_overwrite_type(overwrite):
3165
if isinstance(overwrite, bool):
3167
return ["history", "tags"]
3224
3173
class GenericInterBranch(InterBranch):
3225
"""InterBranch implementation that uses public Branch functions.
3229
def _get_branch_formats_to_test():
3230
return BranchFormat._default_format, BranchFormat._default_format
3232
def update_revisions(self, stop_revision=None, overwrite=False,
3234
"""See InterBranch.update_revisions()."""
3174
"""InterBranch implementation that uses public Branch functions."""
3177
def is_compatible(klass, source, target):
3178
# GenericBranch uses the public API, so always compatible
3182
def _get_branch_formats_to_test(klass):
3183
return [(format_registry.get_default(), format_registry.get_default())]
3186
def unwrap_format(klass, format):
3187
if isinstance(format, remote.RemoteBranchFormat):
3188
format._ensure_real()
3189
return format._custom_format
3193
def copy_content_into(self, revision_id=None):
3194
"""Copy the content of source into target
3196
revision_id: if not None, the revision history in the new branch will
3197
be truncated to end with revision_id.
3199
self.source.update_references(self.target)
3200
self.source._synchronize_history(self.target, revision_id)
3202
parent = self.source.get_parent()
3203
except errors.InaccessibleParent, e:
3204
mutter('parent was not accessible to copy: %s', e)
3207
self.target.set_parent(parent)
3208
if self.source._push_should_merge_tags():
3209
self.source.tags.merge_to(self.target.tags)
3212
def fetch(self, stop_revision=None, limit=None):
3213
if self.target.base == self.source.base:
3235
3215
self.source.lock_read()
3237
other_revno, other_last_revision = self.source.last_revision_info()
3238
stop_revno = None # unknown
3239
if stop_revision is None:
3240
stop_revision = other_last_revision
3241
if _mod_revision.is_null(stop_revision):
3242
# if there are no commits, we're done.
3244
stop_revno = other_revno
3246
# what's the current last revision, before we fetch [and change it
3248
last_rev = _mod_revision.ensure_null(self.target.last_revision())
3249
# we fetch here so that we don't process data twice in the common
3250
# case of having something to pull, and so that the check for
3251
# already merged can operate on the just fetched graph, which will
3252
# be cached in memory.
3253
self.target.fetch(self.source, stop_revision)
3254
# Check to see if one is an ancestor of the other
3257
graph = self.target.repository.get_graph()
3258
if self.target._check_if_descendant_or_diverged(
3259
stop_revision, last_rev, graph, self.source):
3260
# stop_revision is a descendant of last_rev, but we aren't
3261
# overwriting, so we're done.
3263
if stop_revno is None:
3265
graph = self.target.repository.get_graph()
3266
this_revno, this_last_revision = \
3267
self.target.last_revision_info()
3268
stop_revno = graph.find_distance_to_null(stop_revision,
3269
[(other_last_revision, other_revno),
3270
(this_last_revision, this_revno)])
3271
self.target.set_last_revision_info(stop_revno, stop_revision)
3217
fetch_spec_factory = fetch.FetchSpecFactory()
3218
fetch_spec_factory.source_branch = self.source
3219
fetch_spec_factory.source_branch_stop_revision_id = stop_revision
3220
fetch_spec_factory.source_repo = self.source.repository
3221
fetch_spec_factory.target_repo = self.target.repository
3222
fetch_spec_factory.target_repo_kind = fetch.TargetRepoKinds.PREEXISTING
3223
fetch_spec_factory.limit = limit
3224
fetch_spec = fetch_spec_factory.make_fetch_spec()
3225
return self.target.repository.fetch(self.source.repository,
3226
fetch_spec=fetch_spec)
3273
3228
self.source.unlock()
3231
def _update_revisions(self, stop_revision=None, overwrite=False,
3233
other_revno, other_last_revision = self.source.last_revision_info()
3234
stop_revno = None # unknown
3235
if stop_revision is None:
3236
stop_revision = other_last_revision
3237
if _mod_revision.is_null(stop_revision):
3238
# if there are no commits, we're done.
3240
stop_revno = other_revno
3242
# what's the current last revision, before we fetch [and change it
3244
last_rev = _mod_revision.ensure_null(self.target.last_revision())
3245
# we fetch here so that we don't process data twice in the common
3246
# case of having something to pull, and so that the check for
3247
# already merged can operate on the just fetched graph, which will
3248
# be cached in memory.
3249
self.fetch(stop_revision=stop_revision)
3250
# Check to see if one is an ancestor of the other
3253
graph = self.target.repository.get_graph()
3254
if self.target._check_if_descendant_or_diverged(
3255
stop_revision, last_rev, graph, self.source):
3256
# stop_revision is a descendant of last_rev, but we aren't
3257
# overwriting, so we're done.
3259
if stop_revno is None:
3261
graph = self.target.repository.get_graph()
3262
this_revno, this_last_revision = \
3263
self.target.last_revision_info()
3264
stop_revno = graph.find_distance_to_null(stop_revision,
3265
[(other_last_revision, other_revno),
3266
(this_last_revision, this_revno)])
3267
self.target.set_last_revision_info(stop_revno, stop_revision)
3275
3270
def pull(self, overwrite=False, stop_revision=None,
3271
possible_transports=None, run_hooks=True,
3272
_override_hook_target=None, local=False):
3273
"""Pull from source into self, updating my master if any.
3275
:param run_hooks: Private parameter - if false, this branch
3276
is being called because it's the master of the primary branch,
3277
so it should not run its hooks.
3279
bound_location = self.target.get_bound_location()
3280
if local and not bound_location:
3281
raise errors.LocalRequiresBoundBranch()
3282
master_branch = None
3283
source_is_master = False
3285
# bound_location comes from a config file, some care has to be
3286
# taken to relate it to source.user_url
3287
normalized = urlutils.normalize_url(bound_location)
3289
relpath = self.source.user_transport.relpath(normalized)
3290
source_is_master = (relpath == '')
3291
except (errors.PathNotChild, errors.InvalidURL):
3292
source_is_master = False
3293
if not local and bound_location and not source_is_master:
3294
# not pulling from master, so we need to update master.
3295
master_branch = self.target.get_master_branch(possible_transports)
3296
master_branch.lock_write()
3299
# pull from source into master.
3300
master_branch.pull(self.source, overwrite, stop_revision,
3302
return self._pull(overwrite,
3303
stop_revision, _hook_master=master_branch,
3304
run_hooks=run_hooks,
3305
_override_hook_target=_override_hook_target,
3306
merge_tags_to_master=not source_is_master)
3309
master_branch.unlock()
3311
def push(self, overwrite=False, stop_revision=None, lossy=False,
3312
_override_hook_source_branch=None):
3313
"""See InterBranch.push.
3315
This is the basic concrete implementation of push()
3317
:param _override_hook_source_branch: If specified, run the hooks
3318
passing this Branch as the source, rather than self. This is for
3319
use of RemoteBranch, where push is delegated to the underlying
3323
raise errors.LossyPushToSameVCS(self.source, self.target)
3324
# TODO: Public option to disable running hooks - should be trivial but
3327
op = cleanup.OperationWithCleanups(self._push_with_bound_branches)
3328
op.add_cleanup(self.source.lock_read().unlock)
3329
op.add_cleanup(self.target.lock_write().unlock)
3330
return op.run(overwrite, stop_revision,
3331
_override_hook_source_branch=_override_hook_source_branch)
3333
def _basic_push(self, overwrite, stop_revision):
3334
"""Basic implementation of push without bound branches or hooks.
3336
Must be called with source read locked and target write locked.
3338
result = BranchPushResult()
3339
result.source_branch = self.source
3340
result.target_branch = self.target
3341
result.old_revno, result.old_revid = self.target.last_revision_info()
3342
self.source.update_references(self.target)
3343
overwrite = _fix_overwrite_type(overwrite)
3344
if result.old_revid != stop_revision:
3345
# We assume that during 'push' this repository is closer than
3347
graph = self.source.repository.get_graph(self.target.repository)
3348
self._update_revisions(stop_revision,
3349
overwrite=("history" in overwrite),
3351
if self.source._push_should_merge_tags():
3352
result.tag_updates, result.tag_conflicts = (
3353
self.source.tags.merge_to(
3354
self.target.tags, "tags" in overwrite))
3355
result.new_revno, result.new_revid = self.target.last_revision_info()
3358
def _push_with_bound_branches(self, operation, overwrite, stop_revision,
3359
_override_hook_source_branch=None):
3360
"""Push from source into target, and into target's master if any.
3363
if _override_hook_source_branch:
3364
result.source_branch = _override_hook_source_branch
3365
for hook in Branch.hooks['post_push']:
3368
bound_location = self.target.get_bound_location()
3369
if bound_location and self.target.base != bound_location:
3370
# there is a master branch.
3372
# XXX: Why the second check? Is it even supported for a branch to
3373
# be bound to itself? -- mbp 20070507
3374
master_branch = self.target.get_master_branch()
3375
master_branch.lock_write()
3376
operation.add_cleanup(master_branch.unlock)
3377
# push into the master from the source branch.
3378
master_inter = InterBranch.get(self.source, master_branch)
3379
master_inter._basic_push(overwrite, stop_revision)
3380
# and push into the target branch from the source. Note that
3381
# we push from the source branch again, because it's considered
3382
# the highest bandwidth repository.
3383
result = self._basic_push(overwrite, stop_revision)
3384
result.master_branch = master_branch
3385
result.local_branch = self.target
3387
master_branch = None
3389
result = self._basic_push(overwrite, stop_revision)
3390
# TODO: Why set master_branch and local_branch if there's no
3391
# binding? Maybe cleaner to just leave them unset? -- mbp
3393
result.master_branch = self.target
3394
result.local_branch = None
3398
def _pull(self, overwrite=False, stop_revision=None,
3276
3399
possible_transports=None, _hook_master=None, run_hooks=True,
3277
_override_hook_target=None, local=False):
3400
_override_hook_target=None, local=False,
3401
merge_tags_to_master=True):
3278
3402
"""See Branch.pull.
3404
This function is the core worker, used by GenericInterBranch.pull to
3405
avoid duplication when pulling source->master and source->local.
3280
3407
:param _hook_master: Private parameter - set the branch to
3281
3408
be supplied as the master to pull hooks.
3282
3409
:param run_hooks: Private parameter - if false, this branch
3283
3410
is being called because it's the master of the primary branch,
3284
3411
so it should not run its hooks.
3412
is being called because it's the master of the primary branch,
3413
so it should not run its hooks.
3285
3414
:param _override_hook_target: Private parameter - set the branch to be
3286
3415
supplied as the target_branch to pull hooks.
3287
3416
:param local: Only update the local branch, and not the bound branch.
3327
3460
self.source.unlock()
3330
def push(self, overwrite=False, stop_revision=None,
3331
_override_hook_source_branch=None):
3332
"""See InterBranch.push.
3334
This is the basic concrete implementation of push()
3336
:param _override_hook_source_branch: If specified, run
3337
the hooks passing this Branch as the source, rather than self.
3338
This is for use of RemoteBranch, where push is delegated to the
3339
underlying vfs-based Branch.
3341
# TODO: Public option to disable running hooks - should be trivial but
3343
self.source.lock_read()
3345
return _run_with_write_locked_target(
3346
self.target, self._push_with_bound_branches, overwrite,
3348
_override_hook_source_branch=_override_hook_source_branch)
3350
self.source.unlock()
3352
def _push_with_bound_branches(self, overwrite, stop_revision,
3353
_override_hook_source_branch=None):
3354
"""Push from source into target, and into target's master if any.
3357
if _override_hook_source_branch:
3358
result.source_branch = _override_hook_source_branch
3359
for hook in Branch.hooks['post_push']:
3362
bound_location = self.target.get_bound_location()
3363
if bound_location and self.target.base != bound_location:
3364
# there is a master branch.
3366
# XXX: Why the second check? Is it even supported for a branch to
3367
# be bound to itself? -- mbp 20070507
3368
master_branch = self.target.get_master_branch()
3369
master_branch.lock_write()
3371
# push into the master from the source branch.
3372
self.source._basic_push(master_branch, overwrite, stop_revision)
3373
# and push into the target branch from the source. Note that we
3374
# push from the source branch again, because its considered the
3375
# highest bandwidth repository.
3376
result = self.source._basic_push(self.target, overwrite,
3378
result.master_branch = master_branch
3379
result.local_branch = self.target
3383
master_branch.unlock()
3386
result = self.source._basic_push(self.target, overwrite,
3388
# TODO: Why set master_branch and local_branch if there's no
3389
# binding? Maybe cleaner to just leave them unset? -- mbp
3391
result.master_branch = self.target
3392
result.local_branch = None
3397
def is_compatible(self, source, target):
3398
# GenericBranch uses the public API, so always compatible
3402
class InterToBranch5(GenericInterBranch):
3405
def _get_branch_formats_to_test():
3406
return BranchFormat._default_format, BzrBranchFormat5()
3408
def pull(self, overwrite=False, stop_revision=None,
3409
possible_transports=None, run_hooks=True,
3410
_override_hook_target=None, local=False):
3411
"""Pull from source into self, updating my master if any.
3413
:param run_hooks: Private parameter - if false, this branch
3414
is being called because it's the master of the primary branch,
3415
so it should not run its hooks.
3417
bound_location = self.target.get_bound_location()
3418
if local and not bound_location:
3419
raise errors.LocalRequiresBoundBranch()
3420
master_branch = None
3421
if not local and bound_location and self.source.user_url != bound_location:
3422
# not pulling from master, so we need to update master.
3423
master_branch = self.target.get_master_branch(possible_transports)
3424
master_branch.lock_write()
3427
# pull from source into master.
3428
master_branch.pull(self.source, overwrite, stop_revision,
3430
return super(InterToBranch5, self).pull(overwrite,
3431
stop_revision, _hook_master=master_branch,
3432
run_hooks=run_hooks,
3433
_override_hook_target=_override_hook_target)
3436
master_branch.unlock()
3439
3464
InterBranch.register_optimiser(GenericInterBranch)
3440
InterBranch.register_optimiser(InterToBranch5)