920
998
"""Return last revision id, or NULL_REVISION."""
921
999
return self.last_revision_info()[1]
924
1001
def last_revision_info(self):
925
1002
"""Return information about the last revision.
927
1004
:return: A tuple (revno, revision_id).
929
if self._last_revision_info_cache is None:
930
self._last_revision_info_cache = self._last_revision_info()
931
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):
1006
with self.lock_read():
1007
if self._last_revision_info_cache is None:
1008
self._last_revision_info_cache = self._read_last_revision_info()
1009
return self._last_revision_info_cache
1011
def _read_last_revision_info(self):
1012
raise NotImplementedError(self._read_last_revision_info)
1014
def import_last_revision_info_and_tags(self, source, revno, revid,
981
1016
"""Set the last revision info, importing from another repo if necessary.
983
1018
This is used by the bound branch code to upload a revision to
984
1019
the master branch first before updating the tip of the local branch.
1020
Revisions referenced by source's tags are also transferred.
986
:param source_repo: Source repository to optionally fetch from
1022
:param source: Source branch to optionally fetch from
987
1023
:param revno: Revision number of the new tip
988
1024
:param revid: Revision id of the new tip
1025
:param lossy: Whether to discard metadata that can not be
1026
natively represented
1027
:return: Tuple with the new revision number and revision id
1028
(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)
1030
if not self.repository.has_same_location(source.repository):
1031
self.fetch(source, revid)
992
1032
self.set_last_revision_info(revno, revid)
1033
return (revno, revid)
994
1035
def revision_id_to_revno(self, revision_id):
995
1036
"""Given a revision id, return its revno"""
996
1037
if _mod_revision.is_null(revision_id):
998
history = self.revision_history()
1039
history = self._revision_history()
1000
1041
return history.index(revision_id) + 1
1001
1042
except ValueError:
1002
1043
raise errors.NoSuchRevision(self, revision_id)
1005
1045
def get_rev_id(self, revno, history=None):
1006
1046
"""Find the revision id of the specified revno."""
1008
return _mod_revision.NULL_REVISION
1009
last_revno, last_revid = self.last_revision_info()
1010
if revno == last_revno:
1012
if revno <= 0 or revno > last_revno:
1013
raise errors.NoSuchRevision(self, revno)
1014
distance_from_last = last_revno - revno
1015
if len(self._partial_revision_history_cache) <= distance_from_last:
1016
self._extend_partial_history(distance_from_last)
1017
return self._partial_revision_history_cache[distance_from_last]
1047
with self.lock_read():
1049
return _mod_revision.NULL_REVISION
1050
last_revno, last_revid = self.last_revision_info()
1051
if revno == last_revno:
1053
if revno <= 0 or revno > last_revno:
1054
raise errors.NoSuchRevision(self, revno)
1055
distance_from_last = last_revno - revno
1056
if len(self._partial_revision_history_cache) <= distance_from_last:
1057
self._extend_partial_history(distance_from_last)
1058
return self._partial_revision_history_cache[distance_from_last]
1020
1060
def pull(self, source, overwrite=False, stop_revision=None,
1021
1061
possible_transports=None, *args, **kwargs):
1022
1062
"""Mirror source into this branch.
1502
1535
object will be created every time regardless.
1505
_default_format = None
1506
"""The default format used for new branches."""
1509
"""The known formats."""
1511
can_set_append_revisions_only = True
1513
1538
def __eq__(self, other):
1514
1539
return self.__class__ is other.__class__
1516
1541
def __ne__(self, other):
1517
1542
return not (self == other)
1520
def find_format(klass, a_bzrdir, name=None):
1521
"""Return the format for the branch object in a_bzrdir."""
1523
transport = a_bzrdir.get_branch_transport(None, name=name)
1524
format_string = transport.get_bytes("format")
1525
return klass._formats[format_string]
1526
except errors.NoSuchFile:
1527
raise errors.NotBranchError(path=transport.base, bzrdir=a_bzrdir)
1529
raise errors.UnknownFormatError(format=format_string, kind='branch')
1532
def get_default_format(klass):
1533
"""Return the current default format."""
1534
return klass._default_format
1536
def get_reference(self, a_bzrdir, name=None):
1537
"""Get the target reference of the branch in a_bzrdir.
1544
def get_reference(self, controldir, name=None):
1545
"""Get the target reference of the branch in controldir.
1539
1547
format probing must have been completed before calling
1540
1548
this method - it is assumed that the format of the branch
1541
in a_bzrdir is correct.
1549
in controldir is correct.
1543
:param a_bzrdir: The bzrdir to get the branch data from.
1551
:param controldir: The controldir to get the branch data from.
1544
1552
:param name: Name of the colocated branch to fetch
1545
1553
:return: None if the branch is not a reference branch.
1550
def set_reference(self, a_bzrdir, name, to_branch):
1551
"""Set the target reference of the branch in a_bzrdir.
1558
def set_reference(self, controldir, name, to_branch):
1559
"""Set the target reference of the branch in controldir.
1553
1561
format probing must have been completed before calling
1554
1562
this method - it is assumed that the format of the branch
1555
in a_bzrdir is correct.
1563
in controldir is correct.
1557
:param a_bzrdir: The bzrdir to set the branch reference for.
1565
:param controldir: The controldir to set the branch reference for.
1558
1566
:param name: Name of colocated branch to set, None for default
1559
1567
:param to_branch: branch that the checkout is to reference
1561
1569
raise NotImplementedError(self.set_reference)
1563
def get_format_string(self):
1564
"""Return the ASCII format string that identifies this format."""
1565
raise NotImplementedError(self.get_format_string)
1567
1571
def get_format_description(self):
1568
1572
"""Return the short format description for this format."""
1569
1573
raise NotImplementedError(self.get_format_description)
1571
def _run_post_branch_init_hooks(self, a_bzrdir, name, branch):
1575
def _run_post_branch_init_hooks(self, controldir, name, branch):
1572
1576
hooks = Branch.hooks['post_branch_init']
1575
params = BranchInitHookParams(self, a_bzrdir, name, branch)
1579
params = BranchInitHookParams(self, controldir, name, branch)
1576
1580
for hook in hooks:
1579
def _initialize_helper(self, a_bzrdir, utf8_files, name=None,
1580
lock_type='metadir', set_format=True):
1581
"""Initialize a branch in a bzrdir, with specified files
1583
:param a_bzrdir: The bzrdir to initialize the branch in
1584
:param utf8_files: The files to create as a list of
1585
(filename, content) tuples
1586
:param name: Name of colocated branch to create, if any
1587
:param set_format: If True, set the format with
1588
self.get_format_string. (BzrBranch4 has its format set
1590
:return: a branch in this format
1592
mutter('creating branch %r in %s', self, a_bzrdir.user_url)
1593
branch_transport = a_bzrdir.get_branch_transport(self, name=name)
1595
'metadir': ('lock', lockdir.LockDir),
1596
'branch4': ('branch-lock', lockable_files.TransportLock),
1598
lock_name, lock_class = lock_map[lock_type]
1599
control_files = lockable_files.LockableFiles(branch_transport,
1600
lock_name, lock_class)
1601
control_files.create_lock()
1603
control_files.lock_write()
1604
except errors.LockContention:
1605
if lock_type != 'branch4':
1611
utf8_files += [('format', self.get_format_string())]
1613
for (filename, content) in utf8_files:
1614
branch_transport.put_bytes(
1616
mode=a_bzrdir._get_file_mode())
1619
control_files.unlock()
1620
branch = self.open(a_bzrdir, name, _found=True)
1621
self._run_post_branch_init_hooks(a_bzrdir, name, branch)
1624
def initialize(self, a_bzrdir, name=None):
1625
"""Create a branch of this format in a_bzrdir.
1583
def initialize(self, controldir, name=None, repository=None,
1584
append_revisions_only=None):
1585
"""Create a branch of this format in controldir.
1627
1587
:param name: Name of the colocated branch to create.
1629
1589
raise NotImplementedError(self.initialize)
1918
1868
self.revision_id)
1921
class BzrBranchFormat4(BranchFormat):
1922
"""Bzr branch format 4.
1925
- a revision-history file.
1926
- a branch-lock lock file [ to be shared with the bzrdir ]
1929
def get_format_description(self):
1930
"""See BranchFormat.get_format_description()."""
1931
return "Branch format 4"
1933
def initialize(self, a_bzrdir, name=None):
1934
"""Create a branch of this format in a_bzrdir."""
1935
utf8_files = [('revision-history', ''),
1936
('branch-name', ''),
1938
return self._initialize_helper(a_bzrdir, utf8_files, name=name,
1939
lock_type='branch4', set_format=False)
1942
super(BzrBranchFormat4, self).__init__()
1943
self._matchingbzrdir = bzrdir.BzrDirFormat6()
1945
def network_name(self):
1946
"""The network name for this format is the control dirs disk label."""
1947
return self._matchingbzrdir.get_format_string()
1949
def open(self, a_bzrdir, name=None, _found=False, ignore_fallbacks=False):
1950
"""See BranchFormat.open()."""
1952
# we are being called directly and must probe.
1953
raise NotImplementedError
1954
return BzrBranch(_format=self,
1955
_control_files=a_bzrdir._control_files,
1958
_repository=a_bzrdir.open_repository())
1961
return "Bazaar-NG branch format 4"
1964
class BranchFormatMetadir(BranchFormat):
1965
"""Common logic for meta-dir based branch formats."""
1967
def _branch_class(self):
1968
"""What class to instantiate on open calls."""
1969
raise NotImplementedError(self._branch_class)
1971
def network_name(self):
1972
"""A simple byte string uniquely identifying this format for RPC calls.
1974
Metadir branch formats use their format string.
1976
return self.get_format_string()
1978
def open(self, a_bzrdir, name=None, _found=False, ignore_fallbacks=False):
1979
"""See BranchFormat.open()."""
1981
format = BranchFormat.find_format(a_bzrdir, name=name)
1982
if format.__class__ != self.__class__:
1983
raise AssertionError("wrong format %r found for %r" %
1985
transport = a_bzrdir.get_branch_transport(None, name=name)
1987
control_files = lockable_files.LockableFiles(transport, 'lock',
1989
return self._branch_class()(_format=self,
1990
_control_files=control_files,
1993
_repository=a_bzrdir.find_repository(),
1994
ignore_fallbacks=ignore_fallbacks)
1995
except errors.NoSuchFile:
1996
raise errors.NotBranchError(path=transport.base, bzrdir=a_bzrdir)
1999
super(BranchFormatMetadir, self).__init__()
2000
self._matchingbzrdir = bzrdir.BzrDirMetaFormat1()
2001
self._matchingbzrdir.set_branch_format(self)
2003
def supports_tags(self):
2007
class BzrBranchFormat5(BranchFormatMetadir):
2008
"""Bzr branch format 5.
2011
- a revision-history file.
2013
- a lock dir guarding the branch itself
2014
- all of this stored in a branch/ subdirectory
2015
- works with shared repositories.
2017
This format is new in bzr 0.8.
2020
def _branch_class(self):
2023
def get_format_string(self):
2024
"""See BranchFormat.get_format_string()."""
2025
return "Bazaar-NG branch format 5\n"
2027
def get_format_description(self):
2028
"""See BranchFormat.get_format_description()."""
2029
return "Branch format 5"
2031
def initialize(self, a_bzrdir, name=None):
2032
"""Create a branch of this format in a_bzrdir."""
2033
utf8_files = [('revision-history', ''),
2034
('branch-name', ''),
2036
return self._initialize_helper(a_bzrdir, utf8_files, name)
2038
def supports_tags(self):
2042
class BzrBranchFormat6(BranchFormatMetadir):
2043
"""Branch format with last-revision and tags.
2045
Unlike previous formats, this has no explicit revision history. Instead,
2046
this just stores the last-revision, and the left-hand history leading
2047
up to there is the history.
2049
This format was introduced in bzr 0.15
2050
and became the default in 0.91.
2053
def _branch_class(self):
2056
def get_format_string(self):
2057
"""See BranchFormat.get_format_string()."""
2058
return "Bazaar Branch Format 6 (bzr 0.15)\n"
2060
def get_format_description(self):
2061
"""See BranchFormat.get_format_description()."""
2062
return "Branch format 6"
2064
def initialize(self, a_bzrdir, name=None):
2065
"""Create a branch of this format in a_bzrdir."""
2066
utf8_files = [('last-revision', '0 null:\n'),
2067
('branch.conf', ''),
2070
return self._initialize_helper(a_bzrdir, utf8_files, name)
2072
def make_tags(self, branch):
2073
"""See bzrlib.branch.BranchFormat.make_tags()."""
2074
return BasicTags(branch)
2076
def supports_set_append_revisions_only(self):
2080
class BzrBranchFormat8(BranchFormatMetadir):
2081
"""Metadir format supporting storing locations of subtree branches."""
2083
def _branch_class(self):
2086
def get_format_string(self):
2087
"""See BranchFormat.get_format_string()."""
2088
return "Bazaar Branch Format 8 (needs bzr 1.15)\n"
2090
def get_format_description(self):
2091
"""See BranchFormat.get_format_description()."""
2092
return "Branch format 8"
2094
def initialize(self, a_bzrdir, name=None):
2095
"""Create a branch of this format in a_bzrdir."""
2096
utf8_files = [('last-revision', '0 null:\n'),
2097
('branch.conf', ''),
2101
return self._initialize_helper(a_bzrdir, utf8_files, name)
2104
super(BzrBranchFormat8, self).__init__()
2105
self._matchingbzrdir.repository_format = \
2106
RepositoryFormatKnitPack5RichRoot()
2108
def make_tags(self, branch):
2109
"""See bzrlib.branch.BranchFormat.make_tags()."""
2110
return BasicTags(branch)
2112
def supports_set_append_revisions_only(self):
2115
def supports_stacking(self):
2118
supports_reference_locations = True
2121
class BzrBranchFormat7(BzrBranchFormat8):
2122
"""Branch format with last-revision, tags, and a stacked location pointer.
2124
The stacked location pointer is passed down to the repository and requires
2125
a repository format with supports_external_lookups = True.
2127
This format was introduced in bzr 1.6.
2130
def initialize(self, a_bzrdir, name=None):
2131
"""Create a branch of this format in a_bzrdir."""
2132
utf8_files = [('last-revision', '0 null:\n'),
2133
('branch.conf', ''),
2136
return self._initialize_helper(a_bzrdir, utf8_files, name)
2138
def _branch_class(self):
2141
def get_format_string(self):
2142
"""See BranchFormat.get_format_string()."""
2143
return "Bazaar Branch Format 7 (needs bzr 1.6)\n"
2145
def get_format_description(self):
2146
"""See BranchFormat.get_format_description()."""
2147
return "Branch format 7"
2149
def supports_set_append_revisions_only(self):
2152
supports_reference_locations = False
2155
class BranchReferenceFormat(BranchFormat):
2156
"""Bzr branch reference format.
2158
Branch references are used in implementing checkouts, they
2159
act as an alias to the real branch which is at some other url.
2166
def get_format_string(self):
2167
"""See BranchFormat.get_format_string()."""
2168
return "Bazaar-NG Branch Reference Format 1\n"
2170
def get_format_description(self):
2171
"""See BranchFormat.get_format_description()."""
2172
return "Checkout reference format 1"
2174
def get_reference(self, a_bzrdir, name=None):
2175
"""See BranchFormat.get_reference()."""
2176
transport = a_bzrdir.get_branch_transport(None, name=name)
2177
return transport.get_bytes('location')
2179
def set_reference(self, a_bzrdir, name, to_branch):
2180
"""See BranchFormat.set_reference()."""
2181
transport = a_bzrdir.get_branch_transport(None, name=name)
2182
location = transport.put_bytes('location', to_branch.base)
2184
def initialize(self, a_bzrdir, name=None, target_branch=None):
2185
"""Create a branch of this format in a_bzrdir."""
2186
if target_branch is None:
2187
# this format does not implement branch itself, thus the implicit
2188
# creation contract must see it as uninitializable
2189
raise errors.UninitializableFormat(self)
2190
mutter('creating branch reference in %s', a_bzrdir.user_url)
2191
branch_transport = a_bzrdir.get_branch_transport(self, name=name)
2192
branch_transport.put_bytes('location',
2193
target_branch.bzrdir.user_url)
2194
branch_transport.put_bytes('format', self.get_format_string())
2196
a_bzrdir, name, _found=True,
2197
possible_transports=[target_branch.bzrdir.root_transport])
2198
self._run_post_branch_init_hooks(a_bzrdir, name, branch)
2202
super(BranchReferenceFormat, self).__init__()
2203
self._matchingbzrdir = bzrdir.BzrDirMetaFormat1()
2204
self._matchingbzrdir.set_branch_format(self)
2206
def _make_reference_clone_function(format, a_branch):
2207
"""Create a clone() routine for a branch dynamically."""
2208
def clone(to_bzrdir, revision_id=None,
2209
repository_policy=None):
2210
"""See Branch.clone()."""
2211
return format.initialize(to_bzrdir, target_branch=a_branch)
2212
# cannot obey revision_id limits when cloning a reference ...
2213
# FIXME RBC 20060210 either nuke revision_id for clone, or
2214
# emit some sort of warning/error to the caller ?!
2217
def open(self, a_bzrdir, name=None, _found=False, location=None,
2218
possible_transports=None, ignore_fallbacks=False):
2219
"""Return the branch that the branch reference in a_bzrdir points at.
2221
:param a_bzrdir: A BzrDir that contains a branch.
2222
:param name: Name of colocated branch to open, if any
2223
:param _found: a private parameter, do not use it. It is used to
2224
indicate if format probing has already be done.
2225
:param ignore_fallbacks: when set, no fallback branches will be opened
2226
(if there are any). Default is to open fallbacks.
2227
:param location: The location of the referenced branch. If
2228
unspecified, this will be determined from the branch reference in
2230
:param possible_transports: An optional reusable transports list.
2233
format = BranchFormat.find_format(a_bzrdir, name=name)
2234
if format.__class__ != self.__class__:
2235
raise AssertionError("wrong format %r found for %r" %
2237
if location is None:
2238
location = self.get_reference(a_bzrdir, name)
2239
real_bzrdir = bzrdir.BzrDir.open(
2240
location, possible_transports=possible_transports)
2241
result = real_bzrdir.open_branch(name=name,
2242
ignore_fallbacks=ignore_fallbacks)
2243
# this changes the behaviour of result.clone to create a new reference
2244
# rather than a copy of the content of the branch.
2245
# I did not use a proxy object because that needs much more extensive
2246
# testing, and we are only changing one behaviour at the moment.
2247
# If we decide to alter more behaviours - i.e. the implicit nickname
2248
# then this should be refactored to introduce a tested proxy branch
2249
# and a subclass of that for use in overriding clone() and ....
2251
result.clone = self._make_reference_clone_function(result)
1871
class BranchFormatRegistry(controldir.ControlComponentFormatRegistry):
1872
"""Branch format registry."""
1874
def __init__(self, other_registry=None):
1875
super(BranchFormatRegistry, self).__init__(other_registry)
1876
self._default_format = None
1877
self._default_format_key = None
1879
def get_default(self):
1880
"""Return the current default format."""
1881
if (self._default_format_key is not None and
1882
self._default_format is None):
1883
self._default_format = self.get(self._default_format_key)
1884
return self._default_format
1886
def set_default(self, format):
1887
"""Set the default format."""
1888
self._default_format = format
1889
self._default_format_key = None
1891
def set_default_key(self, format_string):
1892
"""Set the default format by its format string."""
1893
self._default_format_key = format_string
1894
self._default_format = None
2255
1897
network_format_registry = registry.FormatRegistry()
2260
1902
BranchFormat.network_name() for more detail.
1905
format_registry = BranchFormatRegistry(network_format_registry)
2264
1908
# formats which have no format string are not discoverable
2265
1909
# and not independently creatable, so are not registered.
2266
__format5 = BzrBranchFormat5()
2267
__format6 = BzrBranchFormat6()
2268
__format7 = BzrBranchFormat7()
2269
__format8 = BzrBranchFormat8()
2270
BranchFormat.register_format(__format5)
2271
BranchFormat.register_format(BranchReferenceFormat())
2272
BranchFormat.register_format(__format6)
2273
BranchFormat.register_format(__format7)
2274
BranchFormat.register_format(__format8)
2275
BranchFormat.set_default_format(__format7)
2276
_legacy_formats = [BzrBranchFormat4(),
2278
network_format_registry.register(
2279
_legacy_formats[0].network_name(), _legacy_formats[0].__class__)
1910
format_registry.register_lazy(
1911
"Bazaar-NG branch format 5\n", "breezy.bzr.fullhistory",
1913
format_registry.register_lazy(
1914
"Bazaar Branch Format 6 (bzr 0.15)\n",
1915
"breezy.bzr.branch", "BzrBranchFormat6")
1916
format_registry.register_lazy(
1917
"Bazaar Branch Format 7 (needs bzr 1.6)\n",
1918
"breezy.bzr.branch", "BzrBranchFormat7")
1919
format_registry.register_lazy(
1920
"Bazaar Branch Format 8 (needs bzr 1.15)\n",
1921
"breezy.bzr.branch", "BzrBranchFormat8")
1922
format_registry.register_lazy(
1923
"Bazaar-NG Branch Reference Format 1\n",
1924
"breezy.bzr.branch", "BranchReferenceFormat")
1926
format_registry.set_default_key("Bazaar Branch Format 7 (needs bzr 1.6)\n")
2282
1929
class BranchWriteLockResult(LogicalLockResult):
2283
1930
"""The result of write locking a branch.
2285
:ivar branch_token: The token obtained from the underlying branch lock, or
1932
:ivar token: The token obtained from the underlying branch lock, or
2287
1934
:ivar unlock: A callable which will unlock the lock.
2290
def __init__(self, unlock, branch_token):
2291
LogicalLockResult.__init__(self, unlock)
2292
self.branch_token = branch_token
2294
1937
def __repr__(self):
2295
return "BranchWriteLockResult(%s, %s)" % (self.branch_token,
2299
class BzrBranch(Branch, _RelockDebugMixin):
2300
"""A branch stored in the actual filesystem.
2302
Note that it's "local" in the context of the filesystem; it doesn't
2303
really matter if it's on an nfs/smb/afs/coda/... share, as long as
2304
it's writable, and can be accessed via the normal filesystem API.
2306
:ivar _transport: Transport for file operations on this branch's
2307
control files, typically pointing to the .bzr/branch directory.
2308
:ivar repository: Repository for this branch.
2309
:ivar base: The url of the base directory for this branch; the one
2310
containing the .bzr directory.
2311
:ivar name: Optional colocated branch name as it exists in the control
2315
def __init__(self, _format=None,
2316
_control_files=None, a_bzrdir=None, name=None,
2317
_repository=None, ignore_fallbacks=False):
2318
"""Create new branch object at a particular location."""
2319
if a_bzrdir is None:
2320
raise ValueError('a_bzrdir must be supplied')
2322
self.bzrdir = a_bzrdir
2323
self._base = self.bzrdir.transport.clone('..').base
2325
# XXX: We should be able to just do
2326
# self.base = self.bzrdir.root_transport.base
2327
# but this does not quite work yet -- mbp 20080522
2328
self._format = _format
2329
if _control_files is None:
2330
raise ValueError('BzrBranch _control_files is None')
2331
self.control_files = _control_files
2332
self._transport = _control_files._transport
2333
self.repository = _repository
2334
Branch.__init__(self)
2337
if self.name is None:
2338
return '%s(%s)' % (self.__class__.__name__, self.user_url)
2340
return '%s(%s,%s)' % (self.__class__.__name__, self.user_url,
2345
def _get_base(self):
2346
"""Returns the directory containing the control directory."""
2349
base = property(_get_base, doc="The URL for the root of this branch.")
2351
def _get_config(self):
2352
return TransportConfig(self._transport, 'branch.conf')
2354
def is_locked(self):
2355
return self.control_files.is_locked()
2357
def lock_write(self, token=None):
2358
"""Lock the branch for write operations.
2360
:param token: A token to permit reacquiring a previously held and
2362
:return: A BranchWriteLockResult.
2364
if not self.is_locked():
2365
self._note_lock('w')
2366
# All-in-one needs to always unlock/lock.
2367
repo_control = getattr(self.repository, 'control_files', None)
2368
if self.control_files == repo_control or not self.is_locked():
2369
self.repository._warn_if_deprecated(self)
2370
self.repository.lock_write()
2375
return BranchWriteLockResult(self.unlock,
2376
self.control_files.lock_write(token=token))
2379
self.repository.unlock()
2382
def lock_read(self):
2383
"""Lock the branch for read operations.
2385
:return: A bzrlib.lock.LogicalLockResult.
2387
if not self.is_locked():
2388
self._note_lock('r')
2389
# All-in-one needs to always unlock/lock.
2390
repo_control = getattr(self.repository, 'control_files', None)
2391
if self.control_files == repo_control or not self.is_locked():
2392
self.repository._warn_if_deprecated(self)
2393
self.repository.lock_read()
2398
self.control_files.lock_read()
2399
return LogicalLockResult(self.unlock)
2402
self.repository.unlock()
2405
@only_raises(errors.LockNotHeld, errors.LockBroken)
2408
self.control_files.unlock()
2410
# All-in-one needs to always unlock/lock.
2411
repo_control = getattr(self.repository, 'control_files', None)
2412
if (self.control_files == repo_control or
2413
not self.control_files.is_locked()):
2414
self.repository.unlock()
2415
if not self.control_files.is_locked():
2416
# we just released the lock
2417
self._clear_cached_state()
2419
def peek_lock_mode(self):
2420
if self.control_files._lock_count == 0:
2423
return self.control_files._lock_mode
2425
def get_physical_lock_status(self):
2426
return self.control_files.get_physical_lock_status()
2429
def print_file(self, file, revision_id):
2430
"""See Branch.print_file."""
2431
return self.repository.print_file(file, revision_id)
2433
def _write_revision_history(self, history):
2434
"""Factored out of set_revision_history.
2436
This performs the actual writing to disk.
2437
It is intended to be called by BzrBranch5.set_revision_history."""
2438
self._transport.put_bytes(
2439
'revision-history', '\n'.join(history),
2440
mode=self.bzrdir._get_file_mode())
2443
def set_revision_history(self, rev_history):
2444
"""See Branch.set_revision_history."""
2445
if 'evil' in debug.debug_flags:
2446
mutter_callsite(3, "set_revision_history scales with history.")
2447
check_not_reserved_id = _mod_revision.check_not_reserved_id
2448
for rev_id in rev_history:
2449
check_not_reserved_id(rev_id)
2450
if Branch.hooks['post_change_branch_tip']:
2451
# Don't calculate the last_revision_info() if there are no hooks
2453
old_revno, old_revid = self.last_revision_info()
2454
if len(rev_history) == 0:
2455
revid = _mod_revision.NULL_REVISION
2457
revid = rev_history[-1]
2458
self._run_pre_change_branch_tip_hooks(len(rev_history), revid)
2459
self._write_revision_history(rev_history)
2460
self._clear_cached_state()
2461
self._cache_revision_history(rev_history)
2462
for hook in Branch.hooks['set_rh']:
2463
hook(self, rev_history)
2464
if Branch.hooks['post_change_branch_tip']:
2465
self._run_post_change_branch_tip_hooks(old_revno, old_revid)
2467
def _synchronize_history(self, destination, revision_id):
2468
"""Synchronize last revision and revision history between branches.
2470
This version is most efficient when the destination is also a
2471
BzrBranch5, but works for BzrBranch6 as long as the revision
2472
history is the true lefthand parent history, and all of the revisions
2473
are in the destination's repository. If not, set_revision_history
2476
:param destination: The branch to copy the history into
2477
:param revision_id: The revision-id to truncate history at. May
2478
be None to copy complete history.
2480
if not isinstance(destination._format, BzrBranchFormat5):
2481
super(BzrBranch, self)._synchronize_history(
2482
destination, revision_id)
2484
if revision_id == _mod_revision.NULL_REVISION:
2487
new_history = self.revision_history()
2488
if revision_id is not None and new_history != []:
2490
new_history = new_history[:new_history.index(revision_id) + 1]
2492
rev = self.repository.get_revision(revision_id)
2493
new_history = rev.get_history(self.repository)[1:]
2494
destination.set_revision_history(new_history)
2497
def set_last_revision_info(self, revno, revision_id):
2498
"""Set the last revision of this branch.
2500
The caller is responsible for checking that the revno is correct
2501
for this revision id.
2503
It may be possible to set the branch last revision to an id not
2504
present in the repository. However, branches can also be
2505
configured to check constraints on history, in which case this may not
2508
revision_id = _mod_revision.ensure_null(revision_id)
2509
# this old format stores the full history, but this api doesn't
2510
# provide it, so we must generate, and might as well check it's
2512
history = self._lefthand_history(revision_id)
2513
if len(history) != revno:
2514
raise AssertionError('%d != %d' % (len(history), revno))
2515
self.set_revision_history(history)
2517
def _gen_revision_history(self):
2518
history = self._transport.get_bytes('revision-history').split('\n')
2519
if history[-1:] == ['']:
2520
# There shouldn't be a trailing newline, but just in case.
2525
def generate_revision_history(self, revision_id, last_rev=None,
2527
"""Create a new revision history that will finish with revision_id.
2529
:param revision_id: the new tip to use.
2530
:param last_rev: The previous last_revision. If not None, then this
2531
must be a ancestory of revision_id, or DivergedBranches is raised.
2532
:param other_branch: The other branch that DivergedBranches should
2533
raise with respect to.
2535
self.set_revision_history(self._lefthand_history(revision_id,
2536
last_rev, other_branch))
2538
def basis_tree(self):
2539
"""See Branch.basis_tree."""
2540
return self.repository.revision_tree(self.last_revision())
2542
def _get_parent_location(self):
2543
_locs = ['parent', 'pull', 'x-pull']
2546
return self._transport.get_bytes(l).strip('\n')
2547
except errors.NoSuchFile:
2551
def _basic_push(self, target, overwrite, stop_revision):
2552
"""Basic implementation of push without bound branches or hooks.
2554
Must be called with source read locked and target write locked.
2556
result = BranchPushResult()
2557
result.source_branch = self
2558
result.target_branch = target
2559
result.old_revno, result.old_revid = target.last_revision_info()
2560
self.update_references(target)
2561
if result.old_revid != self.last_revision():
2562
# We assume that during 'push' this repository is closer than
2564
graph = self.repository.get_graph(target.repository)
2565
target.update_revisions(self, stop_revision,
2566
overwrite=overwrite, graph=graph)
2567
if self._push_should_merge_tags():
2568
result.tag_conflicts = self.tags.merge_to(target.tags,
2570
result.new_revno, result.new_revid = target.last_revision_info()
2573
def get_stacked_on_url(self):
2574
raise errors.UnstackableBranchFormat(self._format, self.user_url)
2576
def set_push_location(self, location):
2577
"""See Branch.set_push_location."""
2578
self.get_config().set_user_option(
2579
'push_location', location,
2580
store=_mod_config.STORE_LOCATION_NORECURSE)
2582
def _set_parent_location(self, url):
2584
self._transport.delete('parent')
2586
self._transport.put_bytes('parent', url + '\n',
2587
mode=self.bzrdir._get_file_mode())
2590
class BzrBranch5(BzrBranch):
2591
"""A format 5 branch. This supports new features over plain branches.
2593
It has support for a master_branch which is the data for bound branches.
2596
def get_bound_location(self):
2598
return self._transport.get_bytes('bound')[:-1]
2599
except errors.NoSuchFile:
2603
def get_master_branch(self, possible_transports=None):
2604
"""Return the branch we are bound to.
2606
:return: Either a Branch, or None
2608
This could memoise the branch, but if thats done
2609
it must be revalidated on each new lock.
2610
So for now we just don't memoise it.
2611
# RBC 20060304 review this decision.
2613
bound_loc = self.get_bound_location()
2617
return Branch.open(bound_loc,
2618
possible_transports=possible_transports)
2619
except (errors.NotBranchError, errors.ConnectionError), e:
2620
raise errors.BoundBranchConnectionFailure(
2624
def set_bound_location(self, location):
2625
"""Set the target where this branch is bound to.
2627
:param location: URL to the target branch
2630
self._transport.put_bytes('bound', location+'\n',
2631
mode=self.bzrdir._get_file_mode())
2634
self._transport.delete('bound')
2635
except errors.NoSuchFile:
2640
def bind(self, other):
2641
"""Bind this branch to the branch other.
2643
This does not push or pull data between the branches, though it does
2644
check for divergence to raise an error when the branches are not
2645
either the same, or one a prefix of the other. That behaviour may not
2646
be useful, so that check may be removed in future.
2648
:param other: The branch to bind to
2651
# TODO: jam 20051230 Consider checking if the target is bound
2652
# It is debatable whether you should be able to bind to
2653
# a branch which is itself bound.
2654
# Committing is obviously forbidden,
2655
# but binding itself may not be.
2656
# Since we *have* to check at commit time, we don't
2657
# *need* to check here
2659
# we want to raise diverged if:
2660
# last_rev is not in the other_last_rev history, AND
2661
# other_last_rev is not in our history, and do it without pulling
2663
self.set_bound_location(other.base)
2667
"""If bound, unbind"""
2668
return self.set_bound_location(None)
2671
def update(self, possible_transports=None):
2672
"""Synchronise this branch with the master branch if any.
2674
:return: None or the last_revision that was pivoted out during the
2677
master = self.get_master_branch(possible_transports)
2678
if master is not None:
2679
old_tip = _mod_revision.ensure_null(self.last_revision())
2680
self.pull(master, overwrite=True)
2681
if self.repository.get_graph().is_ancestor(old_tip,
2682
_mod_revision.ensure_null(self.last_revision())):
2688
class BzrBranch8(BzrBranch5):
2689
"""A branch that stores tree-reference locations."""
2691
def _open_hook(self):
2692
if self._ignore_fallbacks:
2695
url = self.get_stacked_on_url()
2696
except (errors.UnstackableRepositoryFormat, errors.NotStacked,
2697
errors.UnstackableBranchFormat):
2700
for hook in Branch.hooks['transform_fallback_location']:
2701
url = hook(self, url)
2703
hook_name = Branch.hooks.get_hook_name(hook)
2704
raise AssertionError(
2705
"'transform_fallback_location' hook %s returned "
2706
"None, not a URL." % hook_name)
2707
self._activate_fallback_location(url)
2709
def __init__(self, *args, **kwargs):
2710
self._ignore_fallbacks = kwargs.get('ignore_fallbacks', False)
2711
super(BzrBranch8, self).__init__(*args, **kwargs)
2712
self._last_revision_info_cache = None
2713
self._reference_info = None
2715
def _clear_cached_state(self):
2716
super(BzrBranch8, self)._clear_cached_state()
2717
self._last_revision_info_cache = None
2718
self._reference_info = None
2720
def _last_revision_info(self):
2721
revision_string = self._transport.get_bytes('last-revision')
2722
revno, revision_id = revision_string.rstrip('\n').split(' ', 1)
2723
revision_id = cache_utf8.get_cached_utf8(revision_id)
2725
return revno, revision_id
2727
def _write_last_revision_info(self, revno, revision_id):
2728
"""Simply write out the revision id, with no checks.
2730
Use set_last_revision_info to perform this safely.
2732
Does not update the revision_history cache.
2733
Intended to be called by set_last_revision_info and
2734
_write_revision_history.
2736
revision_id = _mod_revision.ensure_null(revision_id)
2737
out_string = '%d %s\n' % (revno, revision_id)
2738
self._transport.put_bytes('last-revision', out_string,
2739
mode=self.bzrdir._get_file_mode())
2742
def set_last_revision_info(self, revno, revision_id):
2743
revision_id = _mod_revision.ensure_null(revision_id)
2744
old_revno, old_revid = self.last_revision_info()
2745
if self._get_append_revisions_only():
2746
self._check_history_violation(revision_id)
2747
self._run_pre_change_branch_tip_hooks(revno, revision_id)
2748
self._write_last_revision_info(revno, revision_id)
2749
self._clear_cached_state()
2750
self._last_revision_info_cache = revno, revision_id
2751
self._run_post_change_branch_tip_hooks(old_revno, old_revid)
2753
def _synchronize_history(self, destination, revision_id):
2754
"""Synchronize last revision and revision history between branches.
2756
:see: Branch._synchronize_history
2758
# XXX: The base Branch has a fast implementation of this method based
2759
# on set_last_revision_info, but BzrBranch/BzrBranch5 have a slower one
2760
# that uses set_revision_history. This class inherits from BzrBranch5,
2761
# but wants the fast implementation, so it calls
2762
# Branch._synchronize_history directly.
2763
Branch._synchronize_history(self, destination, revision_id)
2765
def _check_history_violation(self, revision_id):
2766
last_revision = _mod_revision.ensure_null(self.last_revision())
2767
if _mod_revision.is_null(last_revision):
2769
if last_revision not in self._lefthand_history(revision_id):
2770
raise errors.AppendRevisionsOnlyViolation(self.user_url)
2772
def _gen_revision_history(self):
2773
"""Generate the revision history from last revision
2775
last_revno, last_revision = self.last_revision_info()
2776
self._extend_partial_history(stop_index=last_revno-1)
2777
return list(reversed(self._partial_revision_history_cache))
2779
def _write_revision_history(self, history):
2780
"""Factored out of set_revision_history.
2782
This performs the actual writing to disk, with format-specific checks.
2783
It is intended to be called by BzrBranch5.set_revision_history.
2785
if len(history) == 0:
2786
last_revision = 'null:'
2788
if history != self._lefthand_history(history[-1]):
2789
raise errors.NotLefthandHistory(history)
2790
last_revision = history[-1]
2791
if self._get_append_revisions_only():
2792
self._check_history_violation(last_revision)
2793
self._write_last_revision_info(len(history), last_revision)
2796
def _set_parent_location(self, url):
2797
"""Set the parent branch"""
2798
self._set_config_location('parent_location', url, make_relative=True)
2801
def _get_parent_location(self):
2802
"""Set the parent branch"""
2803
return self._get_config_location('parent_location')
2806
def _set_all_reference_info(self, info_dict):
2807
"""Replace all reference info stored in a branch.
2809
:param info_dict: A dict of {file_id: (tree_path, branch_location)}
2812
writer = rio.RioWriter(s)
2813
for key, (tree_path, branch_location) in info_dict.iteritems():
2814
stanza = rio.Stanza(file_id=key, tree_path=tree_path,
2815
branch_location=branch_location)
2816
writer.write_stanza(stanza)
2817
self._transport.put_bytes('references', s.getvalue())
2818
self._reference_info = info_dict
2821
def _get_all_reference_info(self):
2822
"""Return all the reference info stored in a branch.
2824
:return: A dict of {file_id: (tree_path, branch_location)}
2826
if self._reference_info is not None:
2827
return self._reference_info
2828
rio_file = self._transport.get('references')
2830
stanzas = rio.read_stanzas(rio_file)
2831
info_dict = dict((s['file_id'], (s['tree_path'],
2832
s['branch_location'])) for s in stanzas)
2835
self._reference_info = info_dict
2838
def set_reference_info(self, file_id, tree_path, branch_location):
2839
"""Set the branch location to use for a tree reference.
2841
:param file_id: The file-id of the tree reference.
2842
:param tree_path: The path of the tree reference in the tree.
2843
:param branch_location: The location of the branch to retrieve tree
2846
info_dict = self._get_all_reference_info()
2847
info_dict[file_id] = (tree_path, branch_location)
2848
if None in (tree_path, branch_location):
2849
if tree_path is not None:
2850
raise ValueError('tree_path must be None when branch_location'
2852
if branch_location is not None:
2853
raise ValueError('branch_location must be None when tree_path'
2855
del info_dict[file_id]
2856
self._set_all_reference_info(info_dict)
2858
def get_reference_info(self, file_id):
2859
"""Get the tree_path and branch_location for a tree reference.
2861
:return: a tuple of (tree_path, branch_location)
2863
return self._get_all_reference_info().get(file_id, (None, None))
2865
def reference_parent(self, file_id, path, possible_transports=None):
2866
"""Return the parent branch for a tree-reference file_id.
2868
:param file_id: The file_id of the tree reference
2869
:param path: The path of the file_id in the tree
2870
:return: A branch associated with the file_id
2872
branch_location = self.get_reference_info(file_id)[1]
2873
if branch_location is None:
2874
return Branch.reference_parent(self, file_id, path,
2875
possible_transports)
2876
branch_location = urlutils.join(self.user_url, branch_location)
2877
return Branch.open(branch_location,
2878
possible_transports=possible_transports)
2880
def set_push_location(self, location):
2881
"""See Branch.set_push_location."""
2882
self._set_config_location('push_location', location)
2884
def set_bound_location(self, location):
2885
"""See Branch.set_push_location."""
2887
config = self.get_config()
2888
if location is None:
2889
if config.get_user_option('bound') != 'True':
2892
config.set_user_option('bound', 'False', warn_masked=True)
2895
self._set_config_location('bound_location', location,
2897
config.set_user_option('bound', 'True', warn_masked=True)
2900
def _get_bound_location(self, bound):
2901
"""Return the bound location in the config file.
2903
Return None if the bound parameter does not match"""
2904
config = self.get_config()
2905
config_bound = (config.get_user_option('bound') == 'True')
2906
if config_bound != bound:
2908
return self._get_config_location('bound_location', config=config)
2910
def get_bound_location(self):
2911
"""See Branch.set_push_location."""
2912
return self._get_bound_location(True)
2914
def get_old_bound_location(self):
2915
"""See Branch.get_old_bound_location"""
2916
return self._get_bound_location(False)
2918
def get_stacked_on_url(self):
2919
# you can always ask for the URL; but you might not be able to use it
2920
# if the repo can't support stacking.
2921
## self._check_stackable_repo()
2922
stacked_url = self._get_config_location('stacked_on_location')
2923
if stacked_url is None:
2924
raise errors.NotStacked(self)
2927
def _get_append_revisions_only(self):
2928
return self.get_config(
2929
).get_user_option_as_bool('append_revisions_only')
2932
def generate_revision_history(self, revision_id, last_rev=None,
2934
"""See BzrBranch5.generate_revision_history"""
2935
history = self._lefthand_history(revision_id, last_rev, other_branch)
2936
revno = len(history)
2937
self.set_last_revision_info(revno, revision_id)
2940
def get_rev_id(self, revno, history=None):
2941
"""Find the revision id of the specified revno."""
2943
return _mod_revision.NULL_REVISION
2945
last_revno, last_revision_id = self.last_revision_info()
2946
if revno <= 0 or revno > last_revno:
2947
raise errors.NoSuchRevision(self, revno)
2949
if history is not None:
2950
return history[revno - 1]
2952
index = last_revno - revno
2953
if len(self._partial_revision_history_cache) <= index:
2954
self._extend_partial_history(stop_index=index)
2955
if len(self._partial_revision_history_cache) > index:
2956
return self._partial_revision_history_cache[index]
2958
raise errors.NoSuchRevision(self, revno)
2961
def revision_id_to_revno(self, revision_id):
2962
"""Given a revision id, return its revno"""
2963
if _mod_revision.is_null(revision_id):
2966
index = self._partial_revision_history_cache.index(revision_id)
2968
self._extend_partial_history(stop_revision=revision_id)
2969
index = len(self._partial_revision_history_cache) - 1
2970
if self._partial_revision_history_cache[index] != revision_id:
2971
raise errors.NoSuchRevision(self, revision_id)
2972
return self.revno() - index
2975
class BzrBranch7(BzrBranch8):
2976
"""A branch with support for a fallback repository."""
2978
def set_reference_info(self, file_id, tree_path, branch_location):
2979
Branch.set_reference_info(self, file_id, tree_path, branch_location)
2981
def get_reference_info(self, file_id):
2982
Branch.get_reference_info(self, file_id)
2984
def reference_parent(self, file_id, path, possible_transports=None):
2985
return Branch.reference_parent(self, file_id, path,
2986
possible_transports)
2989
class BzrBranch6(BzrBranch7):
2990
"""See BzrBranchFormat6 for the capabilities of this branch.
2992
This subclass of BzrBranch7 disables the new features BzrBranch7 added,
2996
def get_stacked_on_url(self):
2997
raise errors.UnstackableBranchFormat(self._format, self.user_url)
1938
return "BranchWriteLockResult(%r, %r)" % (self.unlock, self.token)
3000
1941
######################################################################
3273
2202
[(other_last_revision, other_revno),
3274
2203
(this_last_revision, this_revno)])
3275
2204
self.target.set_last_revision_info(stop_revno, stop_revision)
3277
self.source.unlock()
3279
2206
def pull(self, overwrite=False, stop_revision=None,
2207
possible_transports=None, run_hooks=True,
2208
_override_hook_target=None, local=False):
2209
"""Pull from source into self, updating my master if any.
2211
:param run_hooks: Private parameter - if false, this branch
2212
is being called because it's the master of the primary branch,
2213
so it should not run its hooks.
2215
with self.target.lock_write():
2216
bound_location = self.target.get_bound_location()
2217
if local and not bound_location:
2218
raise errors.LocalRequiresBoundBranch()
2219
master_branch = None
2220
source_is_master = False
2222
# bound_location comes from a config file, some care has to be
2223
# taken to relate it to source.user_url
2224
normalized = urlutils.normalize_url(bound_location)
2226
relpath = self.source.user_transport.relpath(normalized)
2227
source_is_master = (relpath == '')
2228
except (errors.PathNotChild, urlutils.InvalidURL):
2229
source_is_master = False
2230
if not local and bound_location and not source_is_master:
2231
# not pulling from master, so we need to update master.
2232
master_branch = self.target.get_master_branch(possible_transports)
2233
master_branch.lock_write()
2236
# pull from source into master.
2237
master_branch.pull(self.source, overwrite, stop_revision,
2239
return self._pull(overwrite,
2240
stop_revision, _hook_master=master_branch,
2241
run_hooks=run_hooks,
2242
_override_hook_target=_override_hook_target,
2243
merge_tags_to_master=not source_is_master)
2246
master_branch.unlock()
2248
def push(self, overwrite=False, stop_revision=None, lossy=False,
2249
_override_hook_source_branch=None):
2250
"""See InterBranch.push.
2252
This is the basic concrete implementation of push()
2254
:param _override_hook_source_branch: If specified, run the hooks
2255
passing this Branch as the source, rather than self. This is for
2256
use of RemoteBranch, where push is delegated to the underlying
2260
raise errors.LossyPushToSameVCS(self.source, self.target)
2261
# TODO: Public option to disable running hooks - should be trivial but
2264
op = cleanup.OperationWithCleanups(self._push_with_bound_branches)
2265
op.add_cleanup(self.source.lock_read().unlock)
2266
op.add_cleanup(self.target.lock_write().unlock)
2267
return op.run(overwrite, stop_revision,
2268
_override_hook_source_branch=_override_hook_source_branch)
2270
def _basic_push(self, overwrite, stop_revision):
2271
"""Basic implementation of push without bound branches or hooks.
2273
Must be called with source read locked and target write locked.
2275
result = BranchPushResult()
2276
result.source_branch = self.source
2277
result.target_branch = self.target
2278
result.old_revno, result.old_revid = self.target.last_revision_info()
2279
self.source.update_references(self.target)
2280
overwrite = _fix_overwrite_type(overwrite)
2281
if result.old_revid != stop_revision:
2282
# We assume that during 'push' this repository is closer than
2284
graph = self.source.repository.get_graph(self.target.repository)
2285
self._update_revisions(stop_revision,
2286
overwrite=("history" in overwrite),
2288
if self.source._push_should_merge_tags():
2289
result.tag_updates, result.tag_conflicts = (
2290
self.source.tags.merge_to(
2291
self.target.tags, "tags" in overwrite))
2292
result.new_revno, result.new_revid = self.target.last_revision_info()
2295
def _push_with_bound_branches(self, operation, overwrite, stop_revision,
2296
_override_hook_source_branch=None):
2297
"""Push from source into target, and into target's master if any.
2300
if _override_hook_source_branch:
2301
result.source_branch = _override_hook_source_branch
2302
for hook in Branch.hooks['post_push']:
2305
bound_location = self.target.get_bound_location()
2306
if bound_location and self.target.base != bound_location:
2307
# there is a master branch.
2309
# XXX: Why the second check? Is it even supported for a branch to
2310
# be bound to itself? -- mbp 20070507
2311
master_branch = self.target.get_master_branch()
2312
master_branch.lock_write()
2313
operation.add_cleanup(master_branch.unlock)
2314
# push into the master from the source branch.
2315
master_inter = InterBranch.get(self.source, master_branch)
2316
master_inter._basic_push(overwrite, stop_revision)
2317
# and push into the target branch from the source. Note that
2318
# we push from the source branch again, because it's considered
2319
# the highest bandwidth repository.
2320
result = self._basic_push(overwrite, stop_revision)
2321
result.master_branch = master_branch
2322
result.local_branch = self.target
2324
master_branch = None
2326
result = self._basic_push(overwrite, stop_revision)
2327
# TODO: Why set master_branch and local_branch if there's no
2328
# binding? Maybe cleaner to just leave them unset? -- mbp
2330
result.master_branch = self.target
2331
result.local_branch = None
2335
def _pull(self, overwrite=False, stop_revision=None,
3280
2336
possible_transports=None, _hook_master=None, run_hooks=True,
3281
_override_hook_target=None, local=False):
2337
_override_hook_target=None, local=False,
2338
merge_tags_to_master=True):
3282
2339
"""See Branch.pull.
2341
This function is the core worker, used by GenericInterBranch.pull to
2342
avoid duplication when pulling source->master and source->local.
3284
2344
:param _hook_master: Private parameter - set the branch to
3285
2345
be supplied as the master to pull hooks.
3286
2346
:param run_hooks: Private parameter - if false, this branch
3287
2347
is being called because it's the master of the primary branch,
3288
2348
so it should not run its hooks.
2349
is being called because it's the master of the primary branch,
2350
so it should not run its hooks.
3289
2351
:param _override_hook_target: Private parameter - set the branch to be
3290
2352
supplied as the target_branch to pull hooks.
3291
2353
:param local: Only update the local branch, and not the bound branch.