44
42
from bzrlib.config import BranchConfig, TransportConfig
43
from bzrlib.repofmt.pack_repo import RepositoryFormatKnitPack5RichRoot
45
44
from bzrlib.tag import (
54
from bzrlib.decorators import (
59
from bzrlib.hooks import Hooks
50
from bzrlib.decorators import needs_read_lock, needs_write_lock, only_raises
51
from bzrlib.hooks import HookPoint, Hooks
60
52
from bzrlib.inter import InterObject
61
53
from bzrlib.lock import _RelockDebugMixin, LogicalLockResult
62
54
from bzrlib import registry
72
64
BZR_BRANCH_FORMAT_6 = "Bazaar Branch Format 6 (bzr 0.15)\n"
75
class Branch(controldir.ControlComponent):
67
class Branch(bzrdir.ControlComponent):
76
68
"""Branch holding a history of revisions.
79
71
Base directory/url of the branch; using control_url and
80
72
control_transport is more standardized.
81
:ivar hooks: An instance of BranchHooks.
82
:ivar _master_branch_cache: cached result of get_master_branch, see
74
hooks: An instance of BranchHooks.
85
76
# this is really an instance variable - FIXME move it there
115
104
def _activate_fallback_location(self, url):
116
105
"""Activate the branch/repository from url as a fallback repository."""
117
for existing_fallback_repo in self.repository._fallback_repositories:
118
if existing_fallback_repo.user_url == url:
119
# This fallback is already configured. This probably only
120
# happens because BzrDir.sprout is a horrible mess. To avoid
121
# confusing _unstack we don't add this a second time.
122
mutter('duplicate activation of fallback %r on %r', url, self)
124
106
repo = self._get_fallback_repository(url)
125
107
if repo.has_same_location(self.repository):
126
108
raise errors.UnstackableLocationError(self.user_url, url)
669
644
raise errors.UnsupportedOperation(self.get_reference_info, self)
671
646
@needs_write_lock
672
def fetch(self, from_branch, last_revision=None):
647
def fetch(self, from_branch, last_revision=None, pb=None):
673
648
"""Copy revisions from from_branch into this branch.
675
650
:param from_branch: Where to copy from.
676
651
:param last_revision: What revision to stop at (None for at the end
653
:param pb: An optional progress bar to use.
680
return InterBranch.get(from_branch, self).fetch(last_revision)
656
if self.base == from_branch.base:
659
symbol_versioning.warn(
660
symbol_versioning.deprecated_in((1, 14, 0))
661
% "pb parameter to fetch()")
662
from_branch.lock_read()
664
if last_revision is None:
665
last_revision = from_branch.last_revision()
666
last_revision = _mod_revision.ensure_null(last_revision)
667
return self.repository.fetch(from_branch.repository,
668
revision_id=last_revision,
682
673
def get_bound_location(self):
683
674
"""Return the URL of the branch we are bound to.
704
695
:param committer: Optional committer to set for commit.
705
696
:param revprops: Optional dictionary of revision properties.
706
697
:param revision_id: Optional revision id.
707
:param lossy: Whether to discard data that can not be natively
708
represented, when pushing to a foreign VCS
711
700
if config is None:
712
701
config = self.get_config()
714
703
return self.repository.get_commit_builder(self, parents, config,
715
timestamp, timezone, committer, revprops, revision_id,
704
timestamp, timezone, committer, revprops, revision_id)
718
706
def get_master_branch(self, possible_transports=None):
719
707
"""Return the branch we are bound to.
812
800
old_repository = self.repository
813
801
if len(old_repository._fallback_repositories) != 1:
814
802
raise AssertionError("can't cope with fallback repositories "
815
"of %r (fallbacks: %r)" % (old_repository,
816
old_repository._fallback_repositories))
803
"of %r" % (self.repository,))
817
804
# Open the new repository object.
818
805
# Repositories don't offer an interface to remove fallback
819
806
# repositories today; take the conceptually simpler option and just
867
854
# XXX: If you unstack a branch while it has a working tree
868
855
# with a pending merge, the pending-merged revisions will no
869
856
# longer be present. You can (probably) revert and remerge.
871
tags_to_fetch = set(self.tags.get_reverse_tag_dict())
872
except errors.TagsNotSupported:
873
tags_to_fetch = set()
874
fetch_spec = _mod_graph.NotInOtherForRevs(self.repository,
875
old_repository, required_ids=[self.last_revision()],
876
if_present_ids=tags_to_fetch, find_ghosts=True).execute()
877
self.repository.fetch(old_repository, fetch_spec=fetch_spec)
858
# XXX: This only fetches up to the tip of the repository; it
859
# doesn't bring across any tags. That's fairly consistent
860
# with how branch works, but perhaps not ideal.
861
self.repository.fetch(old_repository,
862
revision_id=self.last_revision(),
879
865
old_repository.unlock()
886
872
:seealso: Branch._get_tags_bytes.
888
return _run_with_write_locked_target(self, self._set_tags_bytes_locked,
891
def _set_tags_bytes_locked(self, bytes):
892
self._tags_bytes = bytes
893
return self._transport.put_bytes('tags', bytes)
874
return _run_with_write_locked_target(self, self._transport.put_bytes,
895
877
def _cache_revision_history(self, rev_history):
896
878
"""Set the cached revision history to rev_history.
995
975
return (0, _mod_revision.NULL_REVISION)
997
@deprecated_method(deprecated_in((2, 4, 0)))
977
@deprecated_method(deprecated_in((1, 6, 0)))
978
def missing_revisions(self, other, stop_revision=None):
979
"""Return a list of new revisions that would perfectly fit.
981
If self and other have not diverged, return a list of the revisions
982
present in other, but missing from self.
984
self_history = self.revision_history()
985
self_len = len(self_history)
986
other_history = other.revision_history()
987
other_len = len(other_history)
988
common_index = min(self_len, other_len) -1
989
if common_index >= 0 and \
990
self_history[common_index] != other_history[common_index]:
991
raise errors.DivergedBranches(self, other)
993
if stop_revision is None:
994
stop_revision = other_len
996
if stop_revision > other_len:
997
raise errors.NoSuchRevision(self, stop_revision)
998
return other_history[self_len:stop_revision]
1000
def update_revisions(self, other, stop_revision=None, overwrite=False,
1002
"""Pull in new perfect-fit revisions.
1004
:param other: Another Branch to pull from
1005
:param stop_revision: Updated until the given revision
1006
:param overwrite: Always set the branch pointer, rather than checking
1007
to see if it is a proper descendant.
1008
:param graph: A Graph object that can be used to query history
1009
information. This can be None.
1012
return InterBranch.get(other, self).update_revisions(stop_revision,
998
1015
def import_last_revision_info(self, source_repo, revno, revid):
999
1016
"""Set the last revision info, importing from another repo if necessary.
1018
This is used by the bound branch code to upload a revision to
1019
the master branch first before updating the tip of the local branch.
1001
1021
:param source_repo: Source repository to optionally fetch from
1002
1022
:param revno: Revision number of the new tip
1003
1023
:param revid: Revision id of the new tip
1006
1026
self.repository.fetch(source_repo, revision_id=revid)
1007
1027
self.set_last_revision_info(revno, revid)
1009
def import_last_revision_info_and_tags(self, source, revno, revid,
1011
"""Set the last revision info, importing from another repo if necessary.
1013
This is used by the bound branch code to upload a revision to
1014
the master branch first before updating the tip of the local branch.
1015
Revisions referenced by source's tags are also transferred.
1017
:param source: Source branch to optionally fetch from
1018
:param revno: Revision number of the new tip
1019
:param revid: Revision id of the new tip
1020
:param lossy: Whether to discard metadata that can not be
1021
natively represented
1022
:return: Tuple with the new revision number and revision id
1023
(should only be different from the arguments when lossy=True)
1025
if not self.repository.has_same_location(source.repository):
1026
self.fetch(source, revid)
1027
self.set_last_revision_info(revno, revid)
1028
return (revno, revid)
1030
1029
def revision_id_to_revno(self, revision_id):
1031
1030
"""Given a revision id, return its revno"""
1032
1031
if _mod_revision.is_null(revision_id):
1359
1357
"""Return the most suitable metadir for a checkout of this branch.
1360
1358
Weaves are used if this branch's repository uses weaves.
1362
format = self.repository.bzrdir.checkout_metadir()
1363
format.set_branch_format(self._format)
1360
if isinstance(self.bzrdir, bzrdir.BzrDirPreSplitOut):
1361
from bzrlib.repofmt import weaverepo
1362
format = bzrdir.BzrDirMetaFormat1()
1363
format.repository_format = weaverepo.RepositoryFormat7()
1365
format = self.repository.bzrdir.checkout_metadir()
1366
format.set_branch_format(self._format)
1366
1369
def create_clone_on_transport(self, to_transport, revision_id=None,
1367
stacked_on=None, create_prefix=False, use_existing_dir=False,
1370
stacked_on=None, create_prefix=False, use_existing_dir=False):
1369
1371
"""Create a clone of this branch and its bzrdir.
1371
1373
:param to_transport: The transport to clone onto.
1384
1386
revision_id = self.last_revision()
1385
1387
dir_to = self.bzrdir.clone_on_transport(to_transport,
1386
1388
revision_id=revision_id, stacked_on=stacked_on,
1387
create_prefix=create_prefix, use_existing_dir=use_existing_dir,
1389
create_prefix=create_prefix, use_existing_dir=use_existing_dir)
1389
1390
return dir_to.open_branch()
1391
1392
def create_checkout(self, to_location, revision_id=None,
1507
1508
raise AssertionError("invalid heads: %r" % (heads,))
1509
def heads_to_fetch(self):
1510
"""Return the heads that must and that should be fetched to copy this
1511
branch into another repo.
1513
:returns: a 2-tuple of (must_fetch, if_present_fetch). must_fetch is a
1514
set of heads that must be fetched. if_present_fetch is a set of
1515
heads that must be fetched if present, but no error is necessary if
1516
they are not present.
1518
# For bzr native formats must_fetch is just the tip, and if_present_fetch
1520
must_fetch = set([self.last_revision()])
1522
if_present_fetch = set(self.tags.get_reverse_tag_dict())
1523
except errors.TagsNotSupported:
1524
if_present_fetch = set()
1525
must_fetch.discard(_mod_revision.NULL_REVISION)
1526
if_present_fetch.discard(_mod_revision.NULL_REVISION)
1527
return must_fetch, if_present_fetch
1530
class BranchFormat(controldir.ControlComponentFormat):
1511
class BranchFormat(object):
1531
1512
"""An encapsulation of the initialization and open routines for a format.
1533
1514
Formats provide three things:
1560
1547
transport = a_bzrdir.get_branch_transport(None, name=name)
1561
1548
format_string = transport.get_bytes("format")
1562
return format_registry.get(format_string)
1549
format = klass._formats[format_string]
1550
if isinstance(format, MetaDirBranchFormatFactory):
1563
1553
except errors.NoSuchFile:
1564
1554
raise errors.NotBranchError(path=transport.base, bzrdir=a_bzrdir)
1565
1555
except KeyError:
1566
1556
raise errors.UnknownFormatError(format=format_string, kind='branch')
1569
@deprecated_method(deprecated_in((2, 4, 0)))
1570
1559
def get_default_format(klass):
1571
1560
"""Return the current default format."""
1572
return format_registry.get_default()
1561
return klass._default_format
1575
@deprecated_method(deprecated_in((2, 4, 0)))
1576
1564
def get_formats(klass):
1577
1565
"""Get all the known formats.
1579
1567
Warning: This triggers a load of all lazy registered formats: do not
1580
1568
use except when that is desireed.
1582
return format_registry._get_all()
1571
for fmt in klass._formats.values():
1572
if isinstance(fmt, MetaDirBranchFormatFactory):
1584
1577
def get_reference(self, a_bzrdir, name=None):
1585
1578
"""Get the target reference of the branch in a_bzrdir.
1624
1617
for hook in hooks:
1627
def initialize(self, a_bzrdir, name=None, repository=None):
1620
def _initialize_helper(self, a_bzrdir, utf8_files, name=None,
1621
lock_type='metadir', set_format=True):
1622
"""Initialize a branch in a bzrdir, with specified files
1624
:param a_bzrdir: The bzrdir to initialize the branch in
1625
:param utf8_files: The files to create as a list of
1626
(filename, content) tuples
1627
:param name: Name of colocated branch to create, if any
1628
:param set_format: If True, set the format with
1629
self.get_format_string. (BzrBranch4 has its format set
1631
:return: a branch in this format
1633
mutter('creating branch %r in %s', self, a_bzrdir.user_url)
1634
branch_transport = a_bzrdir.get_branch_transport(self, name=name)
1636
'metadir': ('lock', lockdir.LockDir),
1637
'branch4': ('branch-lock', lockable_files.TransportLock),
1639
lock_name, lock_class = lock_map[lock_type]
1640
control_files = lockable_files.LockableFiles(branch_transport,
1641
lock_name, lock_class)
1642
control_files.create_lock()
1644
control_files.lock_write()
1645
except errors.LockContention:
1646
if lock_type != 'branch4':
1652
utf8_files += [('format', self.get_format_string())]
1654
for (filename, content) in utf8_files:
1655
branch_transport.put_bytes(
1657
mode=a_bzrdir._get_file_mode())
1660
control_files.unlock()
1661
branch = self.open(a_bzrdir, name, _found=True)
1662
self._run_post_branch_init_hooks(a_bzrdir, name, branch)
1665
def initialize(self, a_bzrdir, name=None):
1628
1666
"""Create a branch of this format in a_bzrdir.
1630
1668
:param name: Name of the colocated branch to create.
1665
1703
raise NotImplementedError(self.network_name)
1667
def open(self, a_bzrdir, name=None, _found=False, ignore_fallbacks=False,
1668
found_repository=None):
1705
def open(self, a_bzrdir, name=None, _found=False, ignore_fallbacks=False):
1669
1706
"""Return the branch object for a_bzrdir
1671
1708
:param a_bzrdir: A BzrDir that contains a branch.
1678
1715
raise NotImplementedError(self.open)
1681
@deprecated_method(deprecated_in((2, 4, 0)))
1682
1718
def register_format(klass, format):
1683
1719
"""Register a metadir format.
1685
1721
See MetaDirBranchFormatFactory for the ability to register a format
1686
1722
without loading the code the format needs until it is actually used.
1688
format_registry.register(format)
1724
klass._formats[format.get_format_string()] = format
1725
# Metadir formats have a network name of their format string, and get
1726
# registered as factories.
1727
if isinstance(format, MetaDirBranchFormatFactory):
1728
network_format_registry.register(format.get_format_string(), format)
1730
network_format_registry.register(format.get_format_string(),
1691
@deprecated_method(deprecated_in((2, 4, 0)))
1692
1734
def set_default_format(klass, format):
1693
format_registry.set_default(format)
1735
klass._default_format = format
1695
1737
def supports_set_append_revisions_only(self):
1696
1738
"""True if this format supports set_append_revisions_only."""
1700
1742
"""True if this format records a stacked-on branch."""
1703
def supports_leaving_lock(self):
1704
"""True if this format supports leaving locks in place."""
1705
return False # by default
1708
@deprecated_method(deprecated_in((2, 4, 0)))
1709
1746
def unregister_format(klass, format):
1710
format_registry.remove(format)
1747
del klass._formats[format.get_format_string()]
1712
1749
def __str__(self):
1713
1750
return self.get_format_description().rstrip()
1758
1795
These are all empty initially, because by default nothing should get
1761
Hooks.__init__(self, "bzrlib.branch", "Branch.hooks")
1762
self.add_hook('set_rh',
1798
Hooks.__init__(self)
1799
self.create_hook(HookPoint('set_rh',
1763
1800
"Invoked whenever the revision history has been set via "
1764
1801
"set_revision_history. The api signature is (branch, "
1765
1802
"revision_history), and the branch will be write-locked. "
1766
1803
"The set_rh hook can be expensive for bzr to trigger, a better "
1767
"hook to use is Branch.post_change_branch_tip.", (0, 15))
1768
self.add_hook('open',
1804
"hook to use is Branch.post_change_branch_tip.", (0, 15), None))
1805
self.create_hook(HookPoint('open',
1769
1806
"Called with the Branch object that has been opened after a "
1770
"branch is opened.", (1, 8))
1771
self.add_hook('post_push',
1807
"branch is opened.", (1, 8), None))
1808
self.create_hook(HookPoint('post_push',
1772
1809
"Called after a push operation completes. post_push is called "
1773
1810
"with a bzrlib.branch.BranchPushResult object and only runs in the "
1774
"bzr client.", (0, 15))
1775
self.add_hook('post_pull',
1811
"bzr client.", (0, 15), None))
1812
self.create_hook(HookPoint('post_pull',
1776
1813
"Called after a pull operation completes. post_pull is called "
1777
1814
"with a bzrlib.branch.PullResult object and only runs in the "
1778
"bzr client.", (0, 15))
1779
self.add_hook('pre_commit',
1780
"Called after a commit is calculated but before it is "
1815
"bzr client.", (0, 15), None))
1816
self.create_hook(HookPoint('pre_commit',
1817
"Called after a commit is calculated but before it is is "
1781
1818
"completed. pre_commit is called with (local, master, old_revno, "
1782
1819
"old_revid, future_revno, future_revid, tree_delta, future_tree"
1783
1820
"). old_revid is NULL_REVISION for the first commit to a branch, "
1785
1822
"basis revision. hooks MUST NOT modify this delta. "
1786
1823
" future_tree is an in-memory tree obtained from "
1787
1824
"CommitBuilder.revision_tree() and hooks MUST NOT modify this "
1789
self.add_hook('post_commit',
1825
"tree.", (0,91), None))
1826
self.create_hook(HookPoint('post_commit',
1790
1827
"Called in the bzr client after a commit has completed. "
1791
1828
"post_commit is called with (local, master, old_revno, old_revid, "
1792
1829
"new_revno, new_revid). old_revid is NULL_REVISION for the first "
1793
"commit to a branch.", (0, 15))
1794
self.add_hook('post_uncommit',
1830
"commit to a branch.", (0, 15), None))
1831
self.create_hook(HookPoint('post_uncommit',
1795
1832
"Called in the bzr client after an uncommit completes. "
1796
1833
"post_uncommit is called with (local, master, old_revno, "
1797
1834
"old_revid, new_revno, new_revid) where local is the local branch "
1798
1835
"or None, master is the target branch, and an empty branch "
1799
"receives new_revno of 0, new_revid of None.", (0, 15))
1800
self.add_hook('pre_change_branch_tip',
1836
"receives new_revno of 0, new_revid of None.", (0, 15), None))
1837
self.create_hook(HookPoint('pre_change_branch_tip',
1801
1838
"Called in bzr client and server before a change to the tip of a "
1802
1839
"branch is made. pre_change_branch_tip is called with a "
1803
1840
"bzrlib.branch.ChangeBranchTipParams. Note that push, pull, "
1804
"commit, uncommit will all trigger this hook.", (1, 6))
1805
self.add_hook('post_change_branch_tip',
1841
"commit, uncommit will all trigger this hook.", (1, 6), None))
1842
self.create_hook(HookPoint('post_change_branch_tip',
1806
1843
"Called in bzr client and server after a change to the tip of a "
1807
1844
"branch is made. post_change_branch_tip is called with a "
1808
1845
"bzrlib.branch.ChangeBranchTipParams. Note that push, pull, "
1809
"commit, uncommit will all trigger this hook.", (1, 4))
1810
self.add_hook('transform_fallback_location',
1846
"commit, uncommit will all trigger this hook.", (1, 4), None))
1847
self.create_hook(HookPoint('transform_fallback_location',
1811
1848
"Called when a stacked branch is activating its fallback "
1812
1849
"locations. transform_fallback_location is called with (branch, "
1813
1850
"url), and should return a new url. Returning the same url "
1818
1855
"fallback locations have not been activated. When there are "
1819
1856
"multiple hooks installed for transform_fallback_location, "
1820
1857
"all are called with the url returned from the previous hook."
1821
"The order is however undefined.", (1, 9))
1822
self.add_hook('automatic_tag_name',
1823
"Called to determine an automatic tag name for a revision. "
1858
"The order is however undefined.", (1, 9), None))
1859
self.create_hook(HookPoint('automatic_tag_name',
1860
"Called to determine an automatic tag name for a revision."
1824
1861
"automatic_tag_name is called with (branch, revision_id) and "
1825
1862
"should return a tag name or None if no tag name could be "
1826
1863
"determined. The first non-None tag name returned will be used.",
1828
self.add_hook('post_branch_init',
1865
self.create_hook(HookPoint('post_branch_init',
1829
1866
"Called after new branch initialization completes. "
1830
1867
"post_branch_init is called with a "
1831
1868
"bzrlib.branch.BranchInitHookParams. "
1832
1869
"Note that init, branch and checkout (both heavyweight and "
1833
"lightweight) will all trigger this hook.", (2, 2))
1834
self.add_hook('post_switch',
1870
"lightweight) will all trigger this hook.", (2, 2), None))
1871
self.create_hook(HookPoint('post_switch',
1835
1872
"Called after a checkout switches branch. "
1836
1873
"post_switch is called with a "
1837
"bzrlib.branch.SwitchHookParams.", (2, 2))
1874
"bzrlib.branch.SwitchHookParams.", (2, 2), None))
1917
1954
return self.__dict__ == other.__dict__
1919
1956
def __repr__(self):
1920
return "<%s of %s>" % (self.__class__.__name__, self.branch)
1958
return "<%s of %s>" % (self.__class__.__name__, self.branch)
1960
return "<%s of format:%s bzrdir:%s>" % (
1961
self.__class__.__name__, self.branch,
1962
self.format, self.bzrdir)
1923
1965
class SwitchHookParams(object):
1953
1995
self.revision_id)
1998
class BzrBranchFormat4(BranchFormat):
1999
"""Bzr branch format 4.
2002
- a revision-history file.
2003
- a branch-lock lock file [ to be shared with the bzrdir ]
2006
def get_format_description(self):
2007
"""See BranchFormat.get_format_description()."""
2008
return "Branch format 4"
2010
def initialize(self, a_bzrdir, name=None):
2011
"""Create a branch of this format in a_bzrdir."""
2012
utf8_files = [('revision-history', ''),
2013
('branch-name', ''),
2015
return self._initialize_helper(a_bzrdir, utf8_files, name=name,
2016
lock_type='branch4', set_format=False)
2019
super(BzrBranchFormat4, self).__init__()
2020
self._matchingbzrdir = bzrdir.BzrDirFormat6()
2022
def network_name(self):
2023
"""The network name for this format is the control dirs disk label."""
2024
return self._matchingbzrdir.get_format_string()
2026
def open(self, a_bzrdir, name=None, _found=False, ignore_fallbacks=False):
2027
"""See BranchFormat.open()."""
2029
# we are being called directly and must probe.
2030
raise NotImplementedError
2031
return BzrBranch(_format=self,
2032
_control_files=a_bzrdir._control_files,
2035
_repository=a_bzrdir.open_repository())
2038
return "Bazaar-NG branch format 4"
1956
2041
class BranchFormatMetadir(BranchFormat):
1957
2042
"""Common logic for meta-dir based branch formats."""
1960
2045
"""What class to instantiate on open calls."""
1961
2046
raise NotImplementedError(self._branch_class)
1963
def _initialize_helper(self, a_bzrdir, utf8_files, name=None,
1965
"""Initialize a branch in a bzrdir, with specified files
1967
:param a_bzrdir: The bzrdir to initialize the branch in
1968
:param utf8_files: The files to create as a list of
1969
(filename, content) tuples
1970
:param name: Name of colocated branch to create, if any
1971
:return: a branch in this format
1973
mutter('creating branch %r in %s', self, a_bzrdir.user_url)
1974
branch_transport = a_bzrdir.get_branch_transport(self, name=name)
1975
control_files = lockable_files.LockableFiles(branch_transport,
1976
'lock', lockdir.LockDir)
1977
control_files.create_lock()
1978
control_files.lock_write()
1980
utf8_files += [('format', self.get_format_string())]
1981
for (filename, content) in utf8_files:
1982
branch_transport.put_bytes(
1984
mode=a_bzrdir._get_file_mode())
1986
control_files.unlock()
1987
branch = self.open(a_bzrdir, name, _found=True,
1988
found_repository=repository)
1989
self._run_post_branch_init_hooks(a_bzrdir, name, branch)
1992
2048
def network_name(self):
1993
2049
"""A simple byte string uniquely identifying this format for RPC calls.
1997
2053
return self.get_format_string()
1999
def open(self, a_bzrdir, name=None, _found=False, ignore_fallbacks=False,
2000
found_repository=None):
2055
def open(self, a_bzrdir, name=None, _found=False, ignore_fallbacks=False):
2001
2056
"""See BranchFormat.open()."""
2003
2058
format = BranchFormat.find_format(a_bzrdir, name=name)
2009
2064
control_files = lockable_files.LockableFiles(transport, 'lock',
2010
2065
lockdir.LockDir)
2011
if found_repository is None:
2012
found_repository = a_bzrdir.find_repository()
2013
2066
return self._branch_class()(_format=self,
2014
2067
_control_files=control_files,
2016
2069
a_bzrdir=a_bzrdir,
2017
_repository=found_repository,
2070
_repository=a_bzrdir.find_repository(),
2018
2071
ignore_fallbacks=ignore_fallbacks)
2019
2072
except errors.NoSuchFile:
2020
2073
raise errors.NotBranchError(path=transport.base, bzrdir=a_bzrdir)
2055
2105
"""See BranchFormat.get_format_description()."""
2056
2106
return "Branch format 5"
2058
def initialize(self, a_bzrdir, name=None, repository=None):
2108
def initialize(self, a_bzrdir, name=None):
2059
2109
"""Create a branch of this format in a_bzrdir."""
2060
2110
utf8_files = [('revision-history', ''),
2061
2111
('branch-name', ''),
2063
return self._initialize_helper(a_bzrdir, utf8_files, name, repository)
2113
return self._initialize_helper(a_bzrdir, utf8_files, name)
2065
2115
def supports_tags(self):
2088
2138
"""See BranchFormat.get_format_description()."""
2089
2139
return "Branch format 6"
2091
def initialize(self, a_bzrdir, name=None, repository=None):
2141
def initialize(self, a_bzrdir, name=None):
2092
2142
"""Create a branch of this format in a_bzrdir."""
2093
2143
utf8_files = [('last-revision', '0 null:\n'),
2094
2144
('branch.conf', ''),
2097
return self._initialize_helper(a_bzrdir, utf8_files, name, repository)
2147
return self._initialize_helper(a_bzrdir, utf8_files, name)
2099
2149
def make_tags(self, branch):
2100
2150
"""See bzrlib.branch.BranchFormat.make_tags()."""
2118
2168
"""See BranchFormat.get_format_description()."""
2119
2169
return "Branch format 8"
2121
def initialize(self, a_bzrdir, name=None, repository=None):
2171
def initialize(self, a_bzrdir, name=None):
2122
2172
"""Create a branch of this format in a_bzrdir."""
2123
2173
utf8_files = [('last-revision', '0 null:\n'),
2124
2174
('branch.conf', ''),
2126
2176
('references', '')
2128
return self._initialize_helper(a_bzrdir, utf8_files, name, repository)
2178
return self._initialize_helper(a_bzrdir, utf8_files, name)
2181
super(BzrBranchFormat8, self).__init__()
2182
self._matchingbzrdir.repository_format = \
2183
RepositoryFormatKnitPack5RichRoot()
2130
2185
def make_tags(self, branch):
2131
2186
"""See bzrlib.branch.BranchFormat.make_tags()."""
2149
2204
This format was introduced in bzr 1.6.
2152
def initialize(self, a_bzrdir, name=None, repository=None):
2207
def initialize(self, a_bzrdir, name=None):
2153
2208
"""Create a branch of this format in a_bzrdir."""
2154
2209
utf8_files = [('last-revision', '0 null:\n'),
2155
2210
('branch.conf', ''),
2158
return self._initialize_helper(a_bzrdir, utf8_files, name, repository)
2213
return self._initialize_helper(a_bzrdir, utf8_files, name)
2160
2215
def _branch_class(self):
2161
2216
return BzrBranch7
2210
2258
transport = a_bzrdir.get_branch_transport(None, name=name)
2211
2259
location = transport.put_bytes('location', to_branch.base)
2213
def initialize(self, a_bzrdir, name=None, target_branch=None,
2261
def initialize(self, a_bzrdir, name=None, target_branch=None):
2215
2262
"""Create a branch of this format in a_bzrdir."""
2216
2263
if target_branch is None:
2217
2264
# this format does not implement branch itself, thus the implicit
2286
class BranchFormatRegistry(controldir.ControlComponentFormatRegistry):
2287
"""Branch format registry."""
2289
def __init__(self, other_registry=None):
2290
super(BranchFormatRegistry, self).__init__(other_registry)
2291
self._default_format = None
2293
def set_default(self, format):
2294
self._default_format = format
2296
def get_default(self):
2297
return self._default_format
2300
2332
network_format_registry = registry.FormatRegistry()
2301
2333
"""Registry of formats indexed by their network name.
2314
2344
__format6 = BzrBranchFormat6()
2315
2345
__format7 = BzrBranchFormat7()
2316
2346
__format8 = BzrBranchFormat8()
2317
format_registry.register(__format5)
2318
format_registry.register(BranchReferenceFormat())
2319
format_registry.register(__format6)
2320
format_registry.register(__format7)
2321
format_registry.register(__format8)
2322
format_registry.set_default(__format7)
2347
BranchFormat.register_format(__format5)
2348
BranchFormat.register_format(BranchReferenceFormat())
2349
BranchFormat.register_format(__format6)
2350
BranchFormat.register_format(__format7)
2351
BranchFormat.register_format(__format8)
2352
BranchFormat.set_default_format(__format7)
2353
_legacy_formats = [BzrBranchFormat4(),
2355
network_format_registry.register(
2356
_legacy_formats[0].network_name(), _legacy_formats[0].__class__)
2325
2359
class BranchWriteLockResult(LogicalLockResult):
2482
2516
'revision-history', '\n'.join(history),
2483
2517
mode=self.bzrdir._get_file_mode())
2485
@deprecated_method(deprecated_in((2, 4, 0)))
2486
2520
def set_revision_history(self, rev_history):
2487
2521
"""See Branch.set_revision_history."""
2488
self._set_revision_history(rev_history)
2491
def _set_revision_history(self, rev_history):
2492
2522
if 'evil' in debug.debug_flags:
2493
2523
mutter_callsite(3, "set_revision_history scales with history.")
2494
2524
check_not_reserved_id = _mod_revision.check_not_reserved_id
2552
2582
configured to check constraints on history, in which case this may not
2555
if not revision_id or not isinstance(revision_id, basestring):
2556
raise errors.InvalidRevisionId(revision_id=revision_id, branch=self)
2585
revision_id = _mod_revision.ensure_null(revision_id)
2557
2586
# this old format stores the full history, but this api doesn't
2558
2587
# provide it, so we must generate, and might as well check it's
2560
2589
history = self._lefthand_history(revision_id)
2561
2590
if len(history) != revno:
2562
2591
raise AssertionError('%d != %d' % (len(history), revno))
2563
self._set_revision_history(history)
2592
self.set_revision_history(history)
2565
2594
def _gen_revision_history(self):
2566
2595
history = self._transport.get_bytes('revision-history').split('\n')
2628
def _basic_push(self, target, overwrite, stop_revision):
2629
"""Basic implementation of push without bound branches or hooks.
2631
Must be called with source read locked and target write locked.
2633
result = BranchPushResult()
2634
result.source_branch = self
2635
result.target_branch = target
2636
result.old_revno, result.old_revid = target.last_revision_info()
2637
self.update_references(target)
2638
if result.old_revid != self.last_revision():
2639
# We assume that during 'push' this repository is closer than
2641
graph = self.repository.get_graph(target.repository)
2642
target.update_revisions(self, stop_revision,
2643
overwrite=overwrite, graph=graph)
2644
if self._push_should_merge_tags():
2645
result.tag_conflicts = self.tags.merge_to(target.tags,
2647
result.new_revno, result.new_revid = target.last_revision_info()
2599
2650
def get_stacked_on_url(self):
2600
2651
raise errors.UnstackableBranchFormat(self._format, self.user_url)
2630
2681
"""Return the branch we are bound to.
2632
2683
:return: Either a Branch, or None
2685
This could memoise the branch, but if thats done
2686
it must be revalidated on each new lock.
2687
So for now we just don't memoise it.
2688
# RBC 20060304 review this decision.
2634
if self._master_branch_cache is None:
2635
self._master_branch_cache = self._get_master_branch(
2636
possible_transports)
2637
return self._master_branch_cache
2639
def _get_master_branch(self, possible_transports):
2640
2690
bound_loc = self.get_bound_location()
2641
2691
if not bound_loc:
2769
2818
@needs_write_lock
2770
2819
def set_last_revision_info(self, revno, revision_id):
2771
if not revision_id or not isinstance(revision_id, basestring):
2772
raise errors.InvalidRevisionId(revision_id=revision_id, branch=self)
2820
revision_id = _mod_revision.ensure_null(revision_id)
2773
2821
old_revno, old_revid = self.last_revision_info()
2774
2822
if self._get_append_revisions_only():
2775
2823
self._check_history_violation(revision_id)
2996
3043
index = self._partial_revision_history_cache.index(revision_id)
2997
3044
except ValueError:
2999
self._extend_partial_history(stop_revision=revision_id)
3000
except errors.RevisionNotPresent, e:
3001
raise errors.GhostRevisionsHaveNoRevno(revision_id, e.revision_id)
3045
self._extend_partial_history(stop_revision=revision_id)
3002
3046
index = len(self._partial_revision_history_cache) - 1
3003
3047
if self._partial_revision_history_cache[index] != revision_id:
3004
3048
raise errors.NoSuchRevision(self, revision_id)
3251
3287
raise NotImplementedError(self.pull)
3253
3289
@needs_write_lock
3290
def update_revisions(self, stop_revision=None, overwrite=False,
3292
"""Pull in new perfect-fit revisions.
3294
:param stop_revision: Updated until the given revision
3295
:param overwrite: Always set the branch pointer, rather than checking
3296
to see if it is a proper descendant.
3297
:param graph: A Graph object that can be used to query history
3298
information. This can be None.
3301
raise NotImplementedError(self.update_revisions)
3254
3304
def push(self, overwrite=False, stop_revision=None,
3255
3305
_override_hook_source_branch=None):
3256
3306
"""Mirror the source branch into the target branch.
3260
3310
raise NotImplementedError(self.push)
3263
def copy_content_into(self, revision_id=None):
3264
"""Copy the content of source into target
3266
revision_id: if not None, the revision history in the new branch will
3267
be truncated to end with revision_id.
3269
raise NotImplementedError(self.copy_content_into)
3272
def fetch(self, stop_revision=None):
3275
:param stop_revision: Last revision to fetch
3277
raise NotImplementedError(self.fetch)
3280
3313
class GenericInterBranch(InterBranch):
3281
3314
"""InterBranch implementation that uses public Branch functions."""
3289
3322
def _get_branch_formats_to_test(klass):
3290
return [(format_registry.get_default(), format_registry.get_default())]
3323
return [(BranchFormat._default_format, BranchFormat._default_format)]
3293
3326
def unwrap_format(klass, format):
3294
3327
if isinstance(format, remote.RemoteBranchFormat):
3295
3328
format._ensure_real()
3296
3329
return format._custom_format
3299
3332
@needs_write_lock
3300
3333
def copy_content_into(self, revision_id=None):
3316
3349
self.source.tags.merge_to(self.target.tags)
3318
3351
@needs_write_lock
3319
def fetch(self, stop_revision=None):
3320
if self.target.base == self.source.base:
3322
self.source.lock_read()
3324
fetch_spec_factory = fetch.FetchSpecFactory()
3325
fetch_spec_factory.source_branch = self.source
3326
fetch_spec_factory.source_branch_stop_revision_id = stop_revision
3327
fetch_spec_factory.source_repo = self.source.repository
3328
fetch_spec_factory.target_repo = self.target.repository
3329
fetch_spec_factory.target_repo_kind = fetch.TargetRepoKinds.PREEXISTING
3330
fetch_spec = fetch_spec_factory.make_fetch_spec()
3331
return self.target.repository.fetch(self.source.repository,
3332
fetch_spec=fetch_spec)
3334
self.source.unlock()
3337
def _update_revisions(self, stop_revision=None, overwrite=False,
3352
def update_revisions(self, stop_revision=None, overwrite=False,
3354
"""See InterBranch.update_revisions()."""
3339
3355
other_revno, other_last_revision = self.source.last_revision_info()
3340
3356
stop_revno = None # unknown
3341
3357
if stop_revision is None:
3428
3442
self.source.unlock()
3430
def _basic_push(self, overwrite, stop_revision):
3431
"""Basic implementation of push without bound branches or hooks.
3433
Must be called with source read locked and target write locked.
3435
result = BranchPushResult()
3436
result.source_branch = self.source
3437
result.target_branch = self.target
3438
result.old_revno, result.old_revid = self.target.last_revision_info()
3439
self.source.update_references(self.target)
3440
if result.old_revid != stop_revision:
3441
# We assume that during 'push' this repository is closer than
3443
graph = self.source.repository.get_graph(self.target.repository)
3444
self._update_revisions(stop_revision, overwrite=overwrite,
3446
if self.source._push_should_merge_tags():
3447
result.tag_conflicts = self.source.tags.merge_to(self.target.tags,
3449
result.new_revno, result.new_revid = self.target.last_revision_info()
3452
3444
def _push_with_bound_branches(self, overwrite, stop_revision,
3453
3445
_override_hook_source_branch=None):
3454
3446
"""Push from source into target, and into target's master if any.
3469
3461
master_branch.lock_write()
3471
3463
# push into the master from the source branch.
3472
master_inter = InterBranch.get(self.source, master_branch)
3473
master_inter._basic_push(overwrite, stop_revision)
3474
# and push into the target branch from the source. Note that
3475
# we push from the source branch again, because it's considered
3476
# the highest bandwidth repository.
3477
result = self._basic_push(overwrite, stop_revision)
3464
self.source._basic_push(master_branch, overwrite, stop_revision)
3465
# and push into the target branch from the source. Note that we
3466
# push from the source branch again, because its considered the
3467
# highest bandwidth repository.
3468
result = self.source._basic_push(self.target, overwrite,
3478
3470
result.master_branch = master_branch
3479
3471
result.local_branch = self.target
3495
3488
def _pull(self, overwrite=False, stop_revision=None,
3496
3489
possible_transports=None, _hook_master=None, run_hooks=True,
3497
_override_hook_target=None, local=False,
3498
merge_tags_to_master=True):
3490
_override_hook_target=None, local=False):
3499
3491
"""See Branch.pull.
3501
3493
This function is the core worker, used by GenericInterBranch.pull to
3506
3498
:param run_hooks: Private parameter - if false, this branch
3507
3499
is being called because it's the master of the primary branch,
3508
3500
so it should not run its hooks.
3509
is being called because it's the master of the primary branch,
3510
so it should not run its hooks.
3511
3501
:param _override_hook_target: Private parameter - set the branch to be
3512
3502
supplied as the target_branch to pull hooks.
3513
3503
:param local: Only update the local branch, and not the bound branch.
3532
3522
# -- JRV20090506
3533
3523
result.old_revno, result.old_revid = \
3534
3524
self.target.last_revision_info()
3535
self._update_revisions(stop_revision, overwrite=overwrite,
3525
self.target.update_revisions(self.source, stop_revision,
3526
overwrite=overwrite, graph=graph)
3537
3527
# TODO: The old revid should be specified when merging tags,
3538
3528
# so a tags implementation that versions tags can only
3539
3529
# pull in the most recent changes. -- JRV20090506
3540
3530
result.tag_conflicts = self.source.tags.merge_to(self.target.tags,
3541
overwrite, ignore_master=not merge_tags_to_master)
3542
3532
result.new_revno, result.new_revid = self.target.last_revision_info()
3543
3533
if _hook_master:
3544
3534
result.master_branch = _hook_master