668
669
raise errors.UnsupportedOperation(self.get_reference_info, self)
670
671
@needs_write_lock
671
def fetch(self, from_branch, last_revision=None, fetch_spec=None):
672
def fetch(self, from_branch, last_revision=None):
672
673
"""Copy revisions from from_branch into this branch.
674
675
:param from_branch: Where to copy from.
675
676
:param last_revision: What revision to stop at (None for at the end
677
:param fetch_spec: If specified, a SearchResult or
678
PendingAncestryResult that describes which revisions to copy. This
679
allows copying multiple heads at once. Mutually exclusive with
683
if fetch_spec is not None and last_revision is not None:
684
raise AssertionError(
685
"fetch_spec and last_revision are mutually exclusive.")
686
if self.base == from_branch.base:
688
from_branch.lock_read()
690
if last_revision is None and fetch_spec is None:
691
last_revision = from_branch.last_revision()
692
last_revision = _mod_revision.ensure_null(last_revision)
693
return self.repository.fetch(from_branch.repository,
694
revision_id=last_revision,
695
fetch_spec=fetch_spec)
680
return InterBranch.get(from_branch, self).fetch(last_revision)
699
682
def get_bound_location(self):
700
683
"""Return the URL of the branch we are bound to.
721
704
:param committer: Optional committer to set for commit.
722
705
:param revprops: Optional dictionary of revision properties.
723
706
: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
726
711
if config is None:
727
712
config = self.get_config()
729
714
return self.repository.get_commit_builder(self, parents, config,
730
timestamp, timezone, committer, revprops, revision_id)
715
timestamp, timezone, committer, revprops, revision_id,
732
718
def get_master_branch(self, possible_transports=None):
733
719
"""Return the branch we are bound to.
1017
1004
to see if it is a proper descendant.
1018
1005
:param graph: A Graph object that can be used to query history
1019
1006
information. This can be None.
1020
:param fetch_tags: Flag that specifies if tags from other should be
1024
1009
return InterBranch.get(other, self).update_revisions(stop_revision,
1025
overwrite, graph, fetch_tags=fetch_tags)
1027
1012
@deprecated_method(deprecated_in((2, 4, 0)))
1028
1013
def import_last_revision_info(self, source_repo, revno, revid):
1036
1021
self.repository.fetch(source_repo, revision_id=revid)
1037
1022
self.set_last_revision_info(revno, revid)
1039
def import_last_revision_info_and_tags(self, source, revno, revid):
1024
def import_last_revision_info_and_tags(self, source, revno, revid,
1040
1026
"""Set the last revision info, importing from another repo if necessary.
1042
1028
This is used by the bound branch code to upload a revision to
1046
1032
:param source: Source branch to optionally fetch from
1047
1033
:param revno: Revision number of the new tip
1048
1034
:param revid: Revision id of the new tip
1035
:param lossy: Whether to discard metadata that can not be
1036
natively represented
1037
:return: Tuple with the new revision number and revision id
1038
(should only be different from the arguments when lossy=True)
1050
1040
if not self.repository.has_same_location(source.repository):
1052
tags_to_fetch = set(source.tags.get_reverse_tag_dict())
1053
except errors.TagsNotSupported:
1054
tags_to_fetch = set()
1055
fetch_spec = _mod_graph.NotInOtherForRevs(self.repository,
1056
source.repository, [revid],
1057
if_present_ids=tags_to_fetch).execute()
1058
self.repository.fetch(source.repository, fetch_spec=fetch_spec)
1041
self.fetch(source, revid)
1059
1042
self.set_last_revision_info(revno, revid)
1043
return (revno, revid)
1061
1045
def revision_id_to_revno(self, revision_id):
1062
1046
"""Given a revision id, return its revno"""
1655
1639
for hook in hooks:
1658
def _initialize_helper(self, a_bzrdir, utf8_files, name=None,
1660
"""Initialize a branch in a bzrdir, with specified files
1662
:param a_bzrdir: The bzrdir to initialize the branch in
1663
:param utf8_files: The files to create as a list of
1664
(filename, content) tuples
1665
:param name: Name of colocated branch to create, if any
1666
:return: a branch in this format
1668
mutter('creating branch %r in %s', self, a_bzrdir.user_url)
1669
branch_transport = a_bzrdir.get_branch_transport(self, name=name)
1670
control_files = lockable_files.LockableFiles(branch_transport,
1671
'lock', lockdir.LockDir)
1672
control_files.create_lock()
1673
control_files.lock_write()
1675
utf8_files += [('format', self.get_format_string())]
1676
for (filename, content) in utf8_files:
1677
branch_transport.put_bytes(
1679
mode=a_bzrdir._get_file_mode())
1681
control_files.unlock()
1682
branch = self.open(a_bzrdir, name, _found=True,
1683
found_repository=repository)
1684
self._run_post_branch_init_hooks(a_bzrdir, name, branch)
1687
1642
def initialize(self, a_bzrdir, name=None, repository=None):
1688
1643
"""Create a branch of this format in a_bzrdir.
1818
1773
These are all empty initially, because by default nothing should get
1821
Hooks.__init__(self)
1822
self.create_hook(HookPoint('set_rh',
1776
Hooks.__init__(self, "bzrlib.branch", "Branch.hooks")
1777
self.add_hook('set_rh',
1823
1778
"Invoked whenever the revision history has been set via "
1824
1779
"set_revision_history. The api signature is (branch, "
1825
1780
"revision_history), and the branch will be write-locked. "
1826
1781
"The set_rh hook can be expensive for bzr to trigger, a better "
1827
"hook to use is Branch.post_change_branch_tip.", (0, 15), None))
1828
self.create_hook(HookPoint('open',
1782
"hook to use is Branch.post_change_branch_tip.", (0, 15))
1783
self.add_hook('open',
1829
1784
"Called with the Branch object that has been opened after a "
1830
"branch is opened.", (1, 8), None))
1831
self.create_hook(HookPoint('post_push',
1785
"branch is opened.", (1, 8))
1786
self.add_hook('post_push',
1832
1787
"Called after a push operation completes. post_push is called "
1833
1788
"with a bzrlib.branch.BranchPushResult object and only runs in the "
1834
"bzr client.", (0, 15), None))
1835
self.create_hook(HookPoint('post_pull',
1789
"bzr client.", (0, 15))
1790
self.add_hook('post_pull',
1836
1791
"Called after a pull operation completes. post_pull is called "
1837
1792
"with a bzrlib.branch.PullResult object and only runs in the "
1838
"bzr client.", (0, 15), None))
1839
self.create_hook(HookPoint('pre_commit',
1793
"bzr client.", (0, 15))
1794
self.add_hook('pre_commit',
1840
1795
"Called after a commit is calculated but before it is "
1841
1796
"completed. pre_commit is called with (local, master, old_revno, "
1842
1797
"old_revid, future_revno, future_revid, tree_delta, future_tree"
1845
1800
"basis revision. hooks MUST NOT modify this delta. "
1846
1801
" future_tree is an in-memory tree obtained from "
1847
1802
"CommitBuilder.revision_tree() and hooks MUST NOT modify this "
1848
"tree.", (0,91), None))
1849
self.create_hook(HookPoint('post_commit',
1804
self.add_hook('post_commit',
1850
1805
"Called in the bzr client after a commit has completed. "
1851
1806
"post_commit is called with (local, master, old_revno, old_revid, "
1852
1807
"new_revno, new_revid). old_revid is NULL_REVISION for the first "
1853
"commit to a branch.", (0, 15), None))
1854
self.create_hook(HookPoint('post_uncommit',
1808
"commit to a branch.", (0, 15))
1809
self.add_hook('post_uncommit',
1855
1810
"Called in the bzr client after an uncommit completes. "
1856
1811
"post_uncommit is called with (local, master, old_revno, "
1857
1812
"old_revid, new_revno, new_revid) where local is the local branch "
1858
1813
"or None, master is the target branch, and an empty branch "
1859
"receives new_revno of 0, new_revid of None.", (0, 15), None))
1860
self.create_hook(HookPoint('pre_change_branch_tip',
1814
"receives new_revno of 0, new_revid of None.", (0, 15))
1815
self.add_hook('pre_change_branch_tip',
1861
1816
"Called in bzr client and server before a change to the tip of a "
1862
1817
"branch is made. pre_change_branch_tip is called with a "
1863
1818
"bzrlib.branch.ChangeBranchTipParams. Note that push, pull, "
1864
"commit, uncommit will all trigger this hook.", (1, 6), None))
1865
self.create_hook(HookPoint('post_change_branch_tip',
1819
"commit, uncommit will all trigger this hook.", (1, 6))
1820
self.add_hook('post_change_branch_tip',
1866
1821
"Called in bzr client and server after a change to the tip of a "
1867
1822
"branch is made. post_change_branch_tip is called with a "
1868
1823
"bzrlib.branch.ChangeBranchTipParams. Note that push, pull, "
1869
"commit, uncommit will all trigger this hook.", (1, 4), None))
1870
self.create_hook(HookPoint('transform_fallback_location',
1824
"commit, uncommit will all trigger this hook.", (1, 4))
1825
self.add_hook('transform_fallback_location',
1871
1826
"Called when a stacked branch is activating its fallback "
1872
1827
"locations. transform_fallback_location is called with (branch, "
1873
1828
"url), and should return a new url. Returning the same url "
1878
1833
"fallback locations have not been activated. When there are "
1879
1834
"multiple hooks installed for transform_fallback_location, "
1880
1835
"all are called with the url returned from the previous hook."
1881
"The order is however undefined.", (1, 9), None))
1882
self.create_hook(HookPoint('automatic_tag_name',
1836
"The order is however undefined.", (1, 9))
1837
self.add_hook('automatic_tag_name',
1883
1838
"Called to determine an automatic tag name for a revision. "
1884
1839
"automatic_tag_name is called with (branch, revision_id) and "
1885
1840
"should return a tag name or None if no tag name could be "
1886
1841
"determined. The first non-None tag name returned will be used.",
1888
self.create_hook(HookPoint('post_branch_init',
1843
self.add_hook('post_branch_init',
1889
1844
"Called after new branch initialization completes. "
1890
1845
"post_branch_init is called with a "
1891
1846
"bzrlib.branch.BranchInitHookParams. "
1892
1847
"Note that init, branch and checkout (both heavyweight and "
1893
"lightweight) will all trigger this hook.", (2, 2), None))
1894
self.create_hook(HookPoint('post_switch',
1848
"lightweight) will all trigger this hook.", (2, 2))
1849
self.add_hook('post_switch',
1895
1850
"Called after a checkout switches branch. "
1896
1851
"post_switch is called with a "
1897
"bzrlib.branch.SwitchHookParams.", (2, 2), None))
1852
"bzrlib.branch.SwitchHookParams.", (2, 2))
2020
1975
"""What class to instantiate on open calls."""
2021
1976
raise NotImplementedError(self._branch_class)
1978
def _initialize_helper(self, a_bzrdir, utf8_files, name=None,
1980
"""Initialize a branch in a bzrdir, with specified files
1982
:param a_bzrdir: The bzrdir to initialize the branch in
1983
:param utf8_files: The files to create as a list of
1984
(filename, content) tuples
1985
:param name: Name of colocated branch to create, if any
1986
:return: a branch in this format
1988
mutter('creating branch %r in %s', self, a_bzrdir.user_url)
1989
branch_transport = a_bzrdir.get_branch_transport(self, name=name)
1990
control_files = lockable_files.LockableFiles(branch_transport,
1991
'lock', lockdir.LockDir)
1992
control_files.create_lock()
1993
control_files.lock_write()
1995
utf8_files += [('format', self.get_format_string())]
1996
for (filename, content) in utf8_files:
1997
branch_transport.put_bytes(
1999
mode=a_bzrdir._get_file_mode())
2001
control_files.unlock()
2002
branch = self.open(a_bzrdir, name, _found=True,
2003
found_repository=repository)
2004
self._run_post_branch_init_hooks(a_bzrdir, name, branch)
2023
2007
def network_name(self):
2024
2008
"""A simple byte string uniquely identifying this format for RPC calls.
2511
2497
'revision-history', '\n'.join(history),
2512
2498
mode=self.bzrdir._get_file_mode())
2500
@deprecated_method(deprecated_in((2, 4, 0)))
2515
2501
def set_revision_history(self, rev_history):
2516
2502
"""See Branch.set_revision_history."""
2503
self._set_revision_history(rev_history)
2506
def _set_revision_history(self, rev_history):
2517
2507
if 'evil' in debug.debug_flags:
2518
2508
mutter_callsite(3, "set_revision_history scales with history.")
2519
2509
check_not_reserved_id = _mod_revision.check_not_reserved_id
2577
2567
configured to check constraints on history, in which case this may not
2580
revision_id = _mod_revision.ensure_null(revision_id)
2570
if not revision_id or not isinstance(revision_id, basestring):
2571
raise errors.InvalidRevisionId(revision_id=revision_id, branch=self)
2581
2572
# this old format stores the full history, but this api doesn't
2582
2573
# provide it, so we must generate, and might as well check it's
2584
2575
history = self._lefthand_history(revision_id)
2585
2576
if len(history) != revno:
2586
2577
raise AssertionError('%d != %d' % (len(history), revno))
2587
self.set_revision_history(history)
2578
self._set_revision_history(history)
2589
2580
def _gen_revision_history(self):
2590
2581
history = self._transport.get_bytes('revision-history').split('\n')
2676
2666
"""Return the branch we are bound to.
2678
2668
:return: Either a Branch, or None
2680
This could memoise the branch, but if thats done
2681
it must be revalidated on each new lock.
2682
So for now we just don't memoise it.
2683
# RBC 20060304 review this decision.
2670
if self._master_branch_cache is None:
2671
self._master_branch_cache = self._get_master_branch(
2672
possible_transports)
2673
return self._master_branch_cache
2675
def _get_master_branch(self, possible_transports):
2685
2676
bound_loc = self.get_bound_location()
2686
2677
if not bound_loc:
2813
2805
@needs_write_lock
2814
2806
def set_last_revision_info(self, revno, revision_id):
2815
revision_id = _mod_revision.ensure_null(revision_id)
2807
if not revision_id or not isinstance(revision_id, basestring):
2808
raise errors.InvalidRevisionId(revision_id=revision_id, branch=self)
2816
2809
old_revno, old_revid = self.last_revision_info()
2817
2810
if self._get_append_revisions_only():
2818
2811
self._check_history_violation(revision_id)
3366
3366
self.source.tags.merge_to(self.target.tags)
3368
3368
@needs_write_lock
3369
def fetch(self, stop_revision=None):
3370
if self.target.base == self.source.base:
3372
self.source.lock_read()
3374
fetch_spec_factory = fetch.FetchSpecFactory()
3375
fetch_spec_factory.source_branch = self.source
3376
fetch_spec_factory.source_branch_stop_revision_id = stop_revision
3377
fetch_spec_factory.source_repo = self.source.repository
3378
fetch_spec_factory.target_repo = self.target.repository
3379
fetch_spec_factory.target_repo_kind = fetch.TargetRepoKinds.PREEXISTING
3380
fetch_spec = fetch_spec_factory.make_fetch_spec()
3381
return self.target.repository.fetch(self.source.repository,
3382
fetch_spec=fetch_spec)
3384
self.source.unlock()
3369
3387
def update_revisions(self, stop_revision=None, overwrite=False,
3370
graph=None, fetch_tags=True):
3371
3389
"""See InterBranch.update_revisions()."""
3372
3390
other_revno, other_last_revision = self.source.last_revision_info()
3373
3391
stop_revno = None # unknown
3385
3403
# case of having something to pull, and so that the check for
3386
3404
# already merged can operate on the just fetched graph, which will
3387
3405
# be cached in memory.
3389
fetch_spec_factory = fetch.FetchSpecFactory()
3390
fetch_spec_factory.source_branch = self.source
3391
fetch_spec_factory.source_branch_stop_revision_id = stop_revision
3392
fetch_spec_factory.source_repo = self.source.repository
3393
fetch_spec_factory.target_repo = self.target.repository
3394
fetch_spec_factory.target_repo_kind = fetch.TargetRepoKinds.PREEXISTING
3395
fetch_spec = fetch_spec_factory.make_fetch_spec()
3397
fetch_spec = _mod_graph.NotInOtherForRevs(self.target.repository,
3398
self.source.repository, revision_ids=[stop_revision]).execute()
3399
self.target.fetch(self.source, fetch_spec=fetch_spec)
3406
self.fetch(stop_revision=stop_revision)
3400
3407
# Check to see if one is an ancestor of the other
3401
3408
if not overwrite:
3402
3409
if graph is None: