670
644
raise errors.UnsupportedOperation(self.get_reference_info, self)
672
646
@needs_write_lock
673
def fetch(self, from_branch, last_revision=None, limit=None):
647
def fetch(self, from_branch, last_revision=None, pb=None):
674
648
"""Copy revisions from from_branch into this branch.
676
650
:param from_branch: Where to copy from.
677
651
:param last_revision: What revision to stop at (None for at the end
679
:param limit: Optional rough limit of revisions to fetch
653
:param pb: An optional progress bar to use.
682
return InterBranch.get(from_branch, self).fetch(last_revision, limit=limit)
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,
684
673
def get_bound_location(self):
685
674
"""Return the URL of the branch we are bound to.
748
734
"""Print `file` to stdout."""
749
735
raise NotImplementedError(self.print_file)
751
@deprecated_method(deprecated_in((2, 4, 0)))
752
737
def set_revision_history(self, rev_history):
753
"""See Branch.set_revision_history."""
754
self._set_revision_history(rev_history)
757
def _set_revision_history(self, rev_history):
758
if len(rev_history) == 0:
759
revid = _mod_revision.NULL_REVISION
761
revid = rev_history[-1]
762
if rev_history != self._lefthand_history(revid):
763
raise errors.NotLefthandHistory(rev_history)
764
self.set_last_revision_info(len(rev_history), revid)
765
self._cache_revision_history(rev_history)
766
for hook in Branch.hooks['set_rh']:
767
hook(self, rev_history)
770
def set_last_revision_info(self, revno, revision_id):
771
"""Set the last revision of this branch.
773
The caller is responsible for checking that the revno is correct
774
for this revision id.
776
It may be possible to set the branch last revision to an id not
777
present in the repository. However, branches can also be
778
configured to check constraints on history, in which case this may not
781
raise NotImplementedError(self.set_last_revision_info)
784
def generate_revision_history(self, revision_id, last_rev=None,
786
"""See Branch.generate_revision_history"""
787
graph = self.repository.get_graph()
788
known_revision_ids = [
789
self.last_revision_info(),
790
(_mod_revision.NULL_REVISION, 0),
792
if last_rev is not None:
793
if not graph.is_ancestor(last_rev, revision_id):
794
# our previous tip is not merged into stop_revision
795
raise errors.DivergedBranches(self, other_branch)
796
revno = graph.find_distance_to_null(revision_id, known_revision_ids)
797
self.set_last_revision_info(revno, revision_id)
738
raise NotImplementedError(self.set_revision_history)
799
740
@needs_write_lock
800
741
def set_parent(self, url):
859
800
old_repository = self.repository
860
801
if len(old_repository._fallback_repositories) != 1:
861
802
raise AssertionError("can't cope with fallback repositories "
862
"of %r (fallbacks: %r)" % (old_repository,
863
old_repository._fallback_repositories))
864
# Open the new repository object.
865
# Repositories don't offer an interface to remove fallback
866
# repositories today; take the conceptually simpler option and just
867
# reopen it. We reopen it starting from the URL so that we
868
# get a separate connection for RemoteRepositories and can
869
# stream from one of them to the other. This does mean doing
870
# separate SSH connection setup, but unstacking is not a
871
# common operation so it's tolerable.
872
new_bzrdir = bzrdir.BzrDir.open(self.bzrdir.root_transport.base)
873
new_repository = new_bzrdir.find_repository()
874
if new_repository._fallback_repositories:
875
raise AssertionError("didn't expect %r to have "
876
"fallback_repositories"
877
% (self.repository,))
878
# Replace self.repository with the new repository.
879
# Do our best to transfer the lock state (i.e. lock-tokens and
880
# lock count) of self.repository to the new repository.
881
lock_token = old_repository.lock_write().repository_token
882
self.repository = new_repository
883
if isinstance(self, remote.RemoteBranch):
884
# Remote branches can have a second reference to the old
885
# repository that need to be replaced.
886
if self._real_branch is not None:
887
self._real_branch.repository = new_repository
888
self.repository.lock_write(token=lock_token)
889
if lock_token is not None:
890
old_repository.leave_lock_in_place()
803
"of %r" % (self.repository,))
804
# unlock it, including unlocking the fallback
891
805
old_repository.unlock()
892
if lock_token is not None:
893
# XXX: self.repository.leave_lock_in_place() before this
894
# function will not be preserved. Fortunately that doesn't
895
# affect the current default format (2a), and would be a
896
# corner-case anyway.
897
# - Andrew Bennetts, 2010/06/30
898
self.repository.dont_leave_lock_in_place()
902
old_repository.unlock()
903
except errors.LockNotHeld:
906
if old_lock_count == 0:
907
raise AssertionError(
908
'old_repository should have been locked at least once.')
909
for i in range(old_lock_count-1):
806
old_repository.lock_read()
808
# Repositories don't offer an interface to remove fallback
809
# repositories today; take the conceptually simpler option and just
810
# reopen it. We reopen it starting from the URL so that we
811
# get a separate connection for RemoteRepositories and can
812
# stream from one of them to the other. This does mean doing
813
# separate SSH connection setup, but unstacking is not a
814
# common operation so it's tolerable.
815
new_bzrdir = bzrdir.BzrDir.open(self.bzrdir.root_transport.base)
816
new_repository = new_bzrdir.find_repository()
817
self.repository = new_repository
818
if self.repository._fallback_repositories:
819
raise AssertionError("didn't expect %r to have "
820
"fallback_repositories"
821
% (self.repository,))
822
# this is not paired with an unlock because it's just restoring
823
# the previous state; the lock's released when set_stacked_on_url
910
825
self.repository.lock_write()
911
# Fetch from the old repository into the new.
912
old_repository.lock_read()
914
826
# XXX: If you unstack a branch while it has a working tree
915
827
# with a pending merge, the pending-merged revisions will no
916
828
# longer be present. You can (probably) revert and remerge.
918
tags_to_fetch = set(self.tags.get_reverse_tag_dict())
919
except errors.TagsNotSupported:
920
tags_to_fetch = set()
921
fetch_spec = _mod_graph.NotInOtherForRevs(self.repository,
922
old_repository, required_ids=[self.last_revision()],
923
if_present_ids=tags_to_fetch, find_ghosts=True).execute()
924
self.repository.fetch(old_repository, fetch_spec=fetch_spec)
830
# XXX: This only fetches up to the tip of the repository; it
831
# doesn't bring across any tags. That's fairly consistent
832
# with how branch works, but perhaps not ideal.
833
self.repository.fetch(old_repository,
834
revision_id=self.last_revision(),
926
837
old_repository.unlock()
1031
935
:return: A tuple (revno, revision_id).
1033
937
if self._last_revision_info_cache is None:
1034
self._last_revision_info_cache = self._read_last_revision_info()
938
self._last_revision_info_cache = self._last_revision_info()
1035
939
return self._last_revision_info_cache
1037
def _read_last_revision_info(self):
1038
raise NotImplementedError(self._read_last_revision_info)
1040
@deprecated_method(deprecated_in((2, 4, 0)))
941
def _last_revision_info(self):
942
rh = self.revision_history()
945
return (revno, rh[-1])
947
return (0, _mod_revision.NULL_REVISION)
949
@deprecated_method(deprecated_in((1, 6, 0)))
950
def missing_revisions(self, other, stop_revision=None):
951
"""Return a list of new revisions that would perfectly fit.
953
If self and other have not diverged, return a list of the revisions
954
present in other, but missing from self.
956
self_history = self.revision_history()
957
self_len = len(self_history)
958
other_history = other.revision_history()
959
other_len = len(other_history)
960
common_index = min(self_len, other_len) -1
961
if common_index >= 0 and \
962
self_history[common_index] != other_history[common_index]:
963
raise errors.DivergedBranches(self, other)
965
if stop_revision is None:
966
stop_revision = other_len
968
if stop_revision > other_len:
969
raise errors.NoSuchRevision(self, stop_revision)
970
return other_history[self_len:stop_revision]
972
def update_revisions(self, other, stop_revision=None, overwrite=False,
974
"""Pull in new perfect-fit revisions.
976
:param other: Another Branch to pull from
977
:param stop_revision: Updated until the given revision
978
:param overwrite: Always set the branch pointer, rather than checking
979
to see if it is a proper descendant.
980
:param graph: A Graph object that can be used to query history
981
information. This can be None.
984
return InterBranch.get(other, self).update_revisions(stop_revision,
1041
987
def import_last_revision_info(self, source_repo, revno, revid):
1042
988
"""Set the last revision info, importing from another repo if necessary.
990
This is used by the bound branch code to upload a revision to
991
the master branch first before updating the tip of the local branch.
1044
993
:param source_repo: Source repository to optionally fetch from
1045
994
:param revno: Revision number of the new tip
1046
995
:param revid: Revision id of the new tip
1049
998
self.repository.fetch(source_repo, revision_id=revid)
1050
999
self.set_last_revision_info(revno, revid)
1052
def import_last_revision_info_and_tags(self, source, revno, revid,
1054
"""Set the last revision info, importing from another repo if necessary.
1056
This is used by the bound branch code to upload a revision to
1057
the master branch first before updating the tip of the local branch.
1058
Revisions referenced by source's tags are also transferred.
1060
:param source: Source branch to optionally fetch from
1061
:param revno: Revision number of the new tip
1062
:param revid: Revision id of the new tip
1063
:param lossy: Whether to discard metadata that can not be
1064
natively represented
1065
:return: Tuple with the new revision number and revision id
1066
(should only be different from the arguments when lossy=True)
1068
if not self.repository.has_same_location(source.repository):
1069
self.fetch(source, revid)
1070
self.set_last_revision_info(revno, revid)
1071
return (revno, revid)
1073
1001
def revision_id_to_revno(self, revision_id):
1074
1002
"""Given a revision id, return its revno"""
1075
1003
if _mod_revision.is_null(revision_id):
1107
1035
stop_revision=stop_revision,
1108
1036
possible_transports=possible_transports, *args, **kwargs)
1110
def push(self, target, overwrite=False, stop_revision=None, lossy=False,
1038
def push(self, target, overwrite=False, stop_revision=None, *args,
1112
1040
"""Mirror this branch into target.
1114
1042
This branch is considered to be 'local', having low latency.
1116
1044
return InterBranch.get(self, target).push(overwrite, stop_revision,
1117
lossy, *args, **kwargs)
1047
def lossy_push(self, target, stop_revision=None):
1048
"""Push deltas into another branch.
1050
:note: This does not, like push, retain the revision ids from
1051
the source branch and will, rather than adding bzr-specific
1052
metadata, push only those semantics of the revision that can be
1053
natively represented by this branch' VCS.
1055
:param target: Target branch
1056
:param stop_revision: Revision to push, defaults to last revision.
1057
:return: BranchPushResult with an extra member revidmap:
1058
A dictionary mapping revision ids from the target branch
1059
to new revision ids in the target branch, for each
1060
revision that was pushed.
1062
inter = InterBranch.get(self, target)
1063
lossy_push = getattr(inter, "lossy_push", None)
1064
if lossy_push is None:
1065
raise errors.LossyPushToSameVCS(self, target)
1066
return lossy_push(stop_revision)
1119
1068
def basis_tree(self):
1120
1069
"""Return `Tree` object for last revision."""
1385
1329
"""Return the most suitable metadir for a checkout of this branch.
1386
1330
Weaves are used if this branch's repository uses weaves.
1388
format = self.repository.bzrdir.checkout_metadir()
1389
format.set_branch_format(self._format)
1332
if isinstance(self.bzrdir, bzrdir.BzrDirPreSplitOut):
1333
from bzrlib.repofmt import weaverepo
1334
format = bzrdir.BzrDirMetaFormat1()
1335
format.repository_format = weaverepo.RepositoryFormat7()
1337
format = self.repository.bzrdir.checkout_metadir()
1338
format.set_branch_format(self._format)
1392
1341
def create_clone_on_transport(self, to_transport, revision_id=None,
1393
stacked_on=None, create_prefix=False, use_existing_dir=False,
1342
stacked_on=None, create_prefix=False, use_existing_dir=False):
1395
1343
"""Create a clone of this branch and its bzrdir.
1397
1345
:param to_transport: The transport to clone onto.
1534
1480
raise AssertionError("invalid heads: %r" % (heads,))
1536
def heads_to_fetch(self):
1537
"""Return the heads that must and that should be fetched to copy this
1538
branch into another repo.
1540
:returns: a 2-tuple of (must_fetch, if_present_fetch). must_fetch is a
1541
set of heads that must be fetched. if_present_fetch is a set of
1542
heads that must be fetched if present, but no error is necessary if
1543
they are not present.
1545
# For bzr native formats must_fetch is just the tip, and if_present_fetch
1547
must_fetch = set([self.last_revision()])
1549
if_present_fetch = set(self.tags.get_reverse_tag_dict())
1550
except errors.TagsNotSupported:
1551
if_present_fetch = set()
1552
must_fetch.discard(_mod_revision.NULL_REVISION)
1553
if_present_fetch.discard(_mod_revision.NULL_REVISION)
1554
return must_fetch, if_present_fetch
1557
class BranchFormat(controldir.ControlComponentFormat):
1483
class BranchFormat(object):
1558
1484
"""An encapsulation of the initialization and open routines for a format.
1560
1486
Formats provide three things:
1587
1519
transport = a_bzrdir.get_branch_transport(None, name=name)
1588
1520
format_string = transport.get_bytes("format")
1589
return format_registry.get(format_string)
1521
format = klass._formats[format_string]
1522
if isinstance(format, MetaDirBranchFormatFactory):
1590
1525
except errors.NoSuchFile:
1591
1526
raise errors.NotBranchError(path=transport.base, bzrdir=a_bzrdir)
1592
1527
except KeyError:
1593
1528
raise errors.UnknownFormatError(format=format_string, kind='branch')
1596
@deprecated_method(deprecated_in((2, 4, 0)))
1597
1531
def get_default_format(klass):
1598
1532
"""Return the current default format."""
1599
return format_registry.get_default()
1533
return klass._default_format
1602
@deprecated_method(deprecated_in((2, 4, 0)))
1603
1536
def get_formats(klass):
1604
1537
"""Get all the known formats.
1606
1539
Warning: This triggers a load of all lazy registered formats: do not
1607
1540
use except when that is desireed.
1609
return format_registry._get_all()
1543
for fmt in klass._formats.values():
1544
if isinstance(fmt, MetaDirBranchFormatFactory):
1611
1549
def get_reference(self, a_bzrdir, name=None):
1612
1550
"""Get the target reference of the branch in a_bzrdir.
1651
1589
for hook in hooks:
1654
def initialize(self, a_bzrdir, name=None, repository=None):
1592
def _initialize_helper(self, a_bzrdir, utf8_files, name=None,
1593
lock_type='metadir', set_format=True):
1594
"""Initialize a branch in a bzrdir, with specified files
1596
:param a_bzrdir: The bzrdir to initialize the branch in
1597
:param utf8_files: The files to create as a list of
1598
(filename, content) tuples
1599
:param name: Name of colocated branch to create, if any
1600
:param set_format: If True, set the format with
1601
self.get_format_string. (BzrBranch4 has its format set
1603
:return: a branch in this format
1605
mutter('creating branch %r in %s', self, a_bzrdir.user_url)
1606
branch_transport = a_bzrdir.get_branch_transport(self, name=name)
1608
'metadir': ('lock', lockdir.LockDir),
1609
'branch4': ('branch-lock', lockable_files.TransportLock),
1611
lock_name, lock_class = lock_map[lock_type]
1612
control_files = lockable_files.LockableFiles(branch_transport,
1613
lock_name, lock_class)
1614
control_files.create_lock()
1616
control_files.lock_write()
1617
except errors.LockContention:
1618
if lock_type != 'branch4':
1624
utf8_files += [('format', self.get_format_string())]
1626
for (filename, content) in utf8_files:
1627
branch_transport.put_bytes(
1629
mode=a_bzrdir._get_file_mode())
1632
control_files.unlock()
1633
branch = self.open(a_bzrdir, name, _found=True)
1634
self._run_post_branch_init_hooks(a_bzrdir, name, branch)
1637
def initialize(self, a_bzrdir, name=None):
1655
1638
"""Create a branch of this format in a_bzrdir.
1657
1640
:param name: Name of the colocated branch to create.
1705
1687
raise NotImplementedError(self.open)
1708
@deprecated_method(deprecated_in((2, 4, 0)))
1709
1690
def register_format(klass, format):
1710
1691
"""Register a metadir format.
1712
1693
See MetaDirBranchFormatFactory for the ability to register a format
1713
1694
without loading the code the format needs until it is actually used.
1715
format_registry.register(format)
1696
klass._formats[format.get_format_string()] = format
1697
# Metadir formats have a network name of their format string, and get
1698
# registered as factories.
1699
if isinstance(format, MetaDirBranchFormatFactory):
1700
network_format_registry.register(format.get_format_string(), format)
1702
network_format_registry.register(format.get_format_string(),
1718
@deprecated_method(deprecated_in((2, 4, 0)))
1719
1706
def set_default_format(klass, format):
1720
format_registry.set_default(format)
1707
klass._default_format = format
1722
1709
def supports_set_append_revisions_only(self):
1723
1710
"""True if this format supports set_append_revisions_only."""
1785
1767
These are all empty initially, because by default nothing should get
1788
Hooks.__init__(self, "bzrlib.branch", "Branch.hooks")
1789
self.add_hook('set_rh',
1770
Hooks.__init__(self)
1771
self.create_hook(HookPoint('set_rh',
1790
1772
"Invoked whenever the revision history has been set via "
1791
1773
"set_revision_history. The api signature is (branch, "
1792
1774
"revision_history), and the branch will be write-locked. "
1793
1775
"The set_rh hook can be expensive for bzr to trigger, a better "
1794
"hook to use is Branch.post_change_branch_tip.", (0, 15))
1795
self.add_hook('open',
1776
"hook to use is Branch.post_change_branch_tip.", (0, 15), None))
1777
self.create_hook(HookPoint('open',
1796
1778
"Called with the Branch object that has been opened after a "
1797
"branch is opened.", (1, 8))
1798
self.add_hook('post_push',
1779
"branch is opened.", (1, 8), None))
1780
self.create_hook(HookPoint('post_push',
1799
1781
"Called after a push operation completes. post_push is called "
1800
1782
"with a bzrlib.branch.BranchPushResult object and only runs in the "
1801
"bzr client.", (0, 15))
1802
self.add_hook('post_pull',
1783
"bzr client.", (0, 15), None))
1784
self.create_hook(HookPoint('post_pull',
1803
1785
"Called after a pull operation completes. post_pull is called "
1804
1786
"with a bzrlib.branch.PullResult object and only runs in the "
1805
"bzr client.", (0, 15))
1806
self.add_hook('pre_commit',
1807
"Called after a commit is calculated but before it is "
1787
"bzr client.", (0, 15), None))
1788
self.create_hook(HookPoint('pre_commit',
1789
"Called after a commit is calculated but before it is is "
1808
1790
"completed. pre_commit is called with (local, master, old_revno, "
1809
1791
"old_revid, future_revno, future_revid, tree_delta, future_tree"
1810
1792
"). old_revid is NULL_REVISION for the first commit to a branch, "
1812
1794
"basis revision. hooks MUST NOT modify this delta. "
1813
1795
" future_tree is an in-memory tree obtained from "
1814
1796
"CommitBuilder.revision_tree() and hooks MUST NOT modify this "
1816
self.add_hook('post_commit',
1797
"tree.", (0,91), None))
1798
self.create_hook(HookPoint('post_commit',
1817
1799
"Called in the bzr client after a commit has completed. "
1818
1800
"post_commit is called with (local, master, old_revno, old_revid, "
1819
1801
"new_revno, new_revid). old_revid is NULL_REVISION for the first "
1820
"commit to a branch.", (0, 15))
1821
self.add_hook('post_uncommit',
1802
"commit to a branch.", (0, 15), None))
1803
self.create_hook(HookPoint('post_uncommit',
1822
1804
"Called in the bzr client after an uncommit completes. "
1823
1805
"post_uncommit is called with (local, master, old_revno, "
1824
1806
"old_revid, new_revno, new_revid) where local is the local branch "
1825
1807
"or None, master is the target branch, and an empty branch "
1826
"receives new_revno of 0, new_revid of None.", (0, 15))
1827
self.add_hook('pre_change_branch_tip',
1808
"receives new_revno of 0, new_revid of None.", (0, 15), None))
1809
self.create_hook(HookPoint('pre_change_branch_tip',
1828
1810
"Called in bzr client and server before a change to the tip of a "
1829
1811
"branch is made. pre_change_branch_tip is called with a "
1830
1812
"bzrlib.branch.ChangeBranchTipParams. Note that push, pull, "
1831
"commit, uncommit will all trigger this hook.", (1, 6))
1832
self.add_hook('post_change_branch_tip',
1813
"commit, uncommit will all trigger this hook.", (1, 6), None))
1814
self.create_hook(HookPoint('post_change_branch_tip',
1833
1815
"Called in bzr client and server after a change to the tip of a "
1834
1816
"branch is made. post_change_branch_tip is called with a "
1835
1817
"bzrlib.branch.ChangeBranchTipParams. Note that push, pull, "
1836
"commit, uncommit will all trigger this hook.", (1, 4))
1837
self.add_hook('transform_fallback_location',
1818
"commit, uncommit will all trigger this hook.", (1, 4), None))
1819
self.create_hook(HookPoint('transform_fallback_location',
1838
1820
"Called when a stacked branch is activating its fallback "
1839
1821
"locations. transform_fallback_location is called with (branch, "
1840
1822
"url), and should return a new url. Returning the same url "
1845
1827
"fallback locations have not been activated. When there are "
1846
1828
"multiple hooks installed for transform_fallback_location, "
1847
1829
"all are called with the url returned from the previous hook."
1848
"The order is however undefined.", (1, 9))
1849
self.add_hook('automatic_tag_name',
1850
"Called to determine an automatic tag name for a revision. "
1830
"The order is however undefined.", (1, 9), None))
1831
self.create_hook(HookPoint('automatic_tag_name',
1832
"Called to determine an automatic tag name for a revision."
1851
1833
"automatic_tag_name is called with (branch, revision_id) and "
1852
1834
"should return a tag name or None if no tag name could be "
1853
1835
"determined. The first non-None tag name returned will be used.",
1855
self.add_hook('post_branch_init',
1837
self.create_hook(HookPoint('post_branch_init',
1856
1838
"Called after new branch initialization completes. "
1857
1839
"post_branch_init is called with a "
1858
1840
"bzrlib.branch.BranchInitHookParams. "
1859
1841
"Note that init, branch and checkout (both heavyweight and "
1860
"lightweight) will all trigger this hook.", (2, 2))
1861
self.add_hook('post_switch',
1842
"lightweight) will all trigger this hook.", (2, 2), None))
1843
self.create_hook(HookPoint('post_switch',
1862
1844
"Called after a checkout switches branch. "
1863
1845
"post_switch is called with a "
1864
"bzrlib.branch.SwitchHookParams.", (2, 2))
1846
"bzrlib.branch.SwitchHookParams.", (2, 2), None))
1980
1967
self.revision_id)
1970
class BzrBranchFormat4(BranchFormat):
1971
"""Bzr branch format 4.
1974
- a revision-history file.
1975
- a branch-lock lock file [ to be shared with the bzrdir ]
1978
def get_format_description(self):
1979
"""See BranchFormat.get_format_description()."""
1980
return "Branch format 4"
1982
def initialize(self, a_bzrdir, name=None):
1983
"""Create a branch of this format in a_bzrdir."""
1984
utf8_files = [('revision-history', ''),
1985
('branch-name', ''),
1987
return self._initialize_helper(a_bzrdir, utf8_files, name=name,
1988
lock_type='branch4', set_format=False)
1991
super(BzrBranchFormat4, self).__init__()
1992
self._matchingbzrdir = bzrdir.BzrDirFormat6()
1994
def network_name(self):
1995
"""The network name for this format is the control dirs disk label."""
1996
return self._matchingbzrdir.get_format_string()
1998
def open(self, a_bzrdir, name=None, _found=False, ignore_fallbacks=False):
1999
"""See BranchFormat.open()."""
2001
# we are being called directly and must probe.
2002
raise NotImplementedError
2003
return BzrBranch(_format=self,
2004
_control_files=a_bzrdir._control_files,
2007
_repository=a_bzrdir.open_repository())
2010
return "Bazaar-NG branch format 4"
1983
2013
class BranchFormatMetadir(BranchFormat):
1984
2014
"""Common logic for meta-dir based branch formats."""
1987
2017
"""What class to instantiate on open calls."""
1988
2018
raise NotImplementedError(self._branch_class)
1990
def _initialize_helper(self, a_bzrdir, utf8_files, name=None,
1992
"""Initialize a branch in a bzrdir, with specified files
1994
:param a_bzrdir: The bzrdir to initialize the branch in
1995
:param utf8_files: The files to create as a list of
1996
(filename, content) tuples
1997
:param name: Name of colocated branch to create, if any
1998
:return: a branch in this format
2000
mutter('creating branch %r in %s', self, a_bzrdir.user_url)
2001
branch_transport = a_bzrdir.get_branch_transport(self, name=name)
2002
control_files = lockable_files.LockableFiles(branch_transport,
2003
'lock', lockdir.LockDir)
2004
control_files.create_lock()
2005
control_files.lock_write()
2007
utf8_files += [('format', self.get_format_string())]
2008
for (filename, content) in utf8_files:
2009
branch_transport.put_bytes(
2011
mode=a_bzrdir._get_file_mode())
2013
control_files.unlock()
2014
branch = self.open(a_bzrdir, name, _found=True,
2015
found_repository=repository)
2016
self._run_post_branch_init_hooks(a_bzrdir, name, branch)
2019
2020
def network_name(self):
2020
2021
"""A simple byte string uniquely identifying this format for RPC calls.
2145
2140
"""See BranchFormat.get_format_description()."""
2146
2141
return "Branch format 8"
2148
def initialize(self, a_bzrdir, name=None, repository=None):
2143
def initialize(self, a_bzrdir, name=None):
2149
2144
"""Create a branch of this format in a_bzrdir."""
2150
2145
utf8_files = [('last-revision', '0 null:\n'),
2151
2146
('branch.conf', ''),
2153
2148
('references', '')
2155
return self._initialize_helper(a_bzrdir, utf8_files, name, repository)
2150
return self._initialize_helper(a_bzrdir, utf8_files, name)
2153
super(BzrBranchFormat8, self).__init__()
2154
self._matchingbzrdir.repository_format = \
2155
RepositoryFormatKnitPack5RichRoot()
2157
2157
def make_tags(self, branch):
2158
2158
"""See bzrlib.branch.BranchFormat.make_tags()."""
2341
2316
__format6 = BzrBranchFormat6()
2342
2317
__format7 = BzrBranchFormat7()
2343
2318
__format8 = BzrBranchFormat8()
2344
format_registry.register(__format5)
2345
format_registry.register(BranchReferenceFormat())
2346
format_registry.register(__format6)
2347
format_registry.register(__format7)
2348
format_registry.register(__format8)
2349
format_registry.set_default(__format7)
2319
BranchFormat.register_format(__format5)
2320
BranchFormat.register_format(BranchReferenceFormat())
2321
BranchFormat.register_format(__format6)
2322
BranchFormat.register_format(__format7)
2323
BranchFormat.register_format(__format8)
2324
BranchFormat.set_default_format(__format7)
2325
_legacy_formats = [BzrBranchFormat4(),
2327
network_format_registry.register(
2328
_legacy_formats[0].network_name(), _legacy_formats[0].__class__)
2352
2331
class BranchWriteLockResult(LogicalLockResult):
2500
2479
"""See Branch.print_file."""
2501
2480
return self.repository.print_file(file, revision_id)
2482
def _write_revision_history(self, history):
2483
"""Factored out of set_revision_history.
2485
This performs the actual writing to disk.
2486
It is intended to be called by BzrBranch5.set_revision_history."""
2487
self._transport.put_bytes(
2488
'revision-history', '\n'.join(history),
2489
mode=self.bzrdir._get_file_mode())
2492
def set_revision_history(self, rev_history):
2493
"""See Branch.set_revision_history."""
2494
if 'evil' in debug.debug_flags:
2495
mutter_callsite(3, "set_revision_history scales with history.")
2496
check_not_reserved_id = _mod_revision.check_not_reserved_id
2497
for rev_id in rev_history:
2498
check_not_reserved_id(rev_id)
2499
if Branch.hooks['post_change_branch_tip']:
2500
# Don't calculate the last_revision_info() if there are no hooks
2502
old_revno, old_revid = self.last_revision_info()
2503
if len(rev_history) == 0:
2504
revid = _mod_revision.NULL_REVISION
2506
revid = rev_history[-1]
2507
self._run_pre_change_branch_tip_hooks(len(rev_history), revid)
2508
self._write_revision_history(rev_history)
2509
self._clear_cached_state()
2510
self._cache_revision_history(rev_history)
2511
for hook in Branch.hooks['set_rh']:
2512
hook(self, rev_history)
2513
if Branch.hooks['post_change_branch_tip']:
2514
self._run_post_change_branch_tip_hooks(old_revno, old_revid)
2516
def _synchronize_history(self, destination, revision_id):
2517
"""Synchronize last revision and revision history between branches.
2519
This version is most efficient when the destination is also a
2520
BzrBranch5, but works for BzrBranch6 as long as the revision
2521
history is the true lefthand parent history, and all of the revisions
2522
are in the destination's repository. If not, set_revision_history
2525
:param destination: The branch to copy the history into
2526
:param revision_id: The revision-id to truncate history at. May
2527
be None to copy complete history.
2529
if not isinstance(destination._format, BzrBranchFormat5):
2530
super(BzrBranch, self)._synchronize_history(
2531
destination, revision_id)
2533
if revision_id == _mod_revision.NULL_REVISION:
2536
new_history = self.revision_history()
2537
if revision_id is not None and new_history != []:
2539
new_history = new_history[:new_history.index(revision_id) + 1]
2541
rev = self.repository.get_revision(revision_id)
2542
new_history = rev.get_history(self.repository)[1:]
2543
destination.set_revision_history(new_history)
2503
2545
@needs_write_lock
2504
2546
def set_last_revision_info(self, revno, revision_id):
2505
if not revision_id or not isinstance(revision_id, basestring):
2506
raise errors.InvalidRevisionId(revision_id=revision_id, branch=self)
2547
"""Set the last revision of this branch.
2549
The caller is responsible for checking that the revno is correct
2550
for this revision id.
2552
It may be possible to set the branch last revision to an id not
2553
present in the repository. However, branches can also be
2554
configured to check constraints on history, in which case this may not
2507
2557
revision_id = _mod_revision.ensure_null(revision_id)
2508
old_revno, old_revid = self.last_revision_info()
2509
if self._get_append_revisions_only():
2510
self._check_history_violation(revision_id)
2511
self._run_pre_change_branch_tip_hooks(revno, revision_id)
2512
self._write_last_revision_info(revno, revision_id)
2513
self._clear_cached_state()
2514
self._last_revision_info_cache = revno, revision_id
2515
self._run_post_change_branch_tip_hooks(old_revno, old_revid)
2558
# this old format stores the full history, but this api doesn't
2559
# provide it, so we must generate, and might as well check it's
2561
history = self._lefthand_history(revision_id)
2562
if len(history) != revno:
2563
raise AssertionError('%d != %d' % (len(history), revno))
2564
self.set_revision_history(history)
2566
def _gen_revision_history(self):
2567
history = self._transport.get_bytes('revision-history').split('\n')
2568
if history[-1:] == ['']:
2569
# There shouldn't be a trailing newline, but just in case.
2574
def generate_revision_history(self, revision_id, last_rev=None,
2576
"""Create a new revision history that will finish with revision_id.
2578
:param revision_id: the new tip to use.
2579
:param last_rev: The previous last_revision. If not None, then this
2580
must be a ancestory of revision_id, or DivergedBranches is raised.
2581
:param other_branch: The other branch that DivergedBranches should
2582
raise with respect to.
2584
self.set_revision_history(self._lefthand_history(revision_id,
2585
last_rev, other_branch))
2517
2587
def basis_tree(self):
2518
2588
"""See Branch.basis_tree."""
2600
def _basic_push(self, target, overwrite, stop_revision):
2601
"""Basic implementation of push without bound branches or hooks.
2603
Must be called with source read locked and target write locked.
2605
result = BranchPushResult()
2606
result.source_branch = self
2607
result.target_branch = target
2608
result.old_revno, result.old_revid = target.last_revision_info()
2609
self.update_references(target)
2610
if result.old_revid != self.last_revision():
2611
# We assume that during 'push' this repository is closer than
2613
graph = self.repository.get_graph(target.repository)
2614
target.update_revisions(self, stop_revision,
2615
overwrite=overwrite, graph=graph)
2616
if self._push_should_merge_tags():
2617
result.tag_conflicts = self.tags.merge_to(target.tags,
2619
result.new_revno, result.new_revid = target.last_revision_info()
2530
2622
def get_stacked_on_url(self):
2531
2623
raise errors.UnstackableBranchFormat(self._format, self.user_url)
2543
2635
self._transport.put_bytes('parent', url + '\n',
2544
2636
mode=self.bzrdir._get_file_mode())
2639
class BzrBranch5(BzrBranch):
2640
"""A format 5 branch. This supports new features over plain branches.
2642
It has support for a master_branch which is the data for bound branches.
2645
def get_bound_location(self):
2647
return self._transport.get_bytes('bound')[:-1]
2648
except errors.NoSuchFile:
2652
def get_master_branch(self, possible_transports=None):
2653
"""Return the branch we are bound to.
2655
:return: Either a Branch, or None
2657
This could memoise the branch, but if thats done
2658
it must be revalidated on each new lock.
2659
So for now we just don't memoise it.
2660
# RBC 20060304 review this decision.
2662
bound_loc = self.get_bound_location()
2666
return Branch.open(bound_loc,
2667
possible_transports=possible_transports)
2668
except (errors.NotBranchError, errors.ConnectionError), e:
2669
raise errors.BoundBranchConnectionFailure(
2546
2672
@needs_write_lock
2548
"""If bound, unbind"""
2549
return self.set_bound_location(None)
2673
def set_bound_location(self, location):
2674
"""Set the target where this branch is bound to.
2676
:param location: URL to the target branch
2679
self._transport.put_bytes('bound', location+'\n',
2680
mode=self.bzrdir._get_file_mode())
2683
self._transport.delete('bound')
2684
except errors.NoSuchFile:
2551
2688
@needs_write_lock
2552
2689
def bind(self, other):
2574
2711
# history around
2575
2712
self.set_bound_location(other.base)
2577
def get_bound_location(self):
2579
return self._transport.get_bytes('bound')[:-1]
2580
except errors.NoSuchFile:
2584
def get_master_branch(self, possible_transports=None):
2585
"""Return the branch we are bound to.
2587
:return: Either a Branch, or None
2589
if self._master_branch_cache is None:
2590
self._master_branch_cache = self._get_master_branch(
2591
possible_transports)
2592
return self._master_branch_cache
2594
def _get_master_branch(self, possible_transports):
2595
bound_loc = self.get_bound_location()
2599
return Branch.open(bound_loc,
2600
possible_transports=possible_transports)
2601
except (errors.NotBranchError, errors.ConnectionError), e:
2602
raise errors.BoundBranchConnectionFailure(
2605
2714
@needs_write_lock
2606
def set_bound_location(self, location):
2607
"""Set the target where this branch is bound to.
2609
:param location: URL to the target branch
2611
self._master_branch_cache = None
2613
self._transport.put_bytes('bound', location+'\n',
2614
mode=self.bzrdir._get_file_mode())
2617
self._transport.delete('bound')
2618
except errors.NoSuchFile:
2716
"""If bound, unbind"""
2717
return self.set_bound_location(None)
2622
2719
@needs_write_lock
2623
2720
def update(self, possible_transports=None):
2639
def _read_last_revision_info(self):
2640
revision_string = self._transport.get_bytes('last-revision')
2641
revno, revision_id = revision_string.rstrip('\n').split(' ', 1)
2642
revision_id = cache_utf8.get_cached_utf8(revision_id)
2644
return revno, revision_id
2646
def _write_last_revision_info(self, revno, revision_id):
2647
"""Simply write out the revision id, with no checks.
2649
Use set_last_revision_info to perform this safely.
2651
Does not update the revision_history cache.
2653
revision_id = _mod_revision.ensure_null(revision_id)
2654
out_string = '%d %s\n' % (revno, revision_id)
2655
self._transport.put_bytes('last-revision', out_string,
2656
mode=self.bzrdir._get_file_mode())
2659
class FullHistoryBzrBranch(BzrBranch):
2660
"""Bzr branch which contains the full revision history."""
2663
def set_last_revision_info(self, revno, revision_id):
2664
if not revision_id or not isinstance(revision_id, basestring):
2665
raise errors.InvalidRevisionId(revision_id=revision_id, branch=self)
2666
revision_id = _mod_revision.ensure_null(revision_id)
2667
# this old format stores the full history, but this api doesn't
2668
# provide it, so we must generate, and might as well check it's
2670
history = self._lefthand_history(revision_id)
2671
if len(history) != revno:
2672
raise AssertionError('%d != %d' % (len(history), revno))
2673
self._set_revision_history(history)
2675
def _read_last_revision_info(self):
2676
rh = self.revision_history()
2679
return (revno, rh[-1])
2681
return (0, _mod_revision.NULL_REVISION)
2683
@deprecated_method(deprecated_in((2, 4, 0)))
2685
def set_revision_history(self, rev_history):
2686
"""See Branch.set_revision_history."""
2687
self._set_revision_history(rev_history)
2689
def _set_revision_history(self, rev_history):
2690
if 'evil' in debug.debug_flags:
2691
mutter_callsite(3, "set_revision_history scales with history.")
2692
check_not_reserved_id = _mod_revision.check_not_reserved_id
2693
for rev_id in rev_history:
2694
check_not_reserved_id(rev_id)
2695
if Branch.hooks['post_change_branch_tip']:
2696
# Don't calculate the last_revision_info() if there are no hooks
2698
old_revno, old_revid = self.last_revision_info()
2699
if len(rev_history) == 0:
2700
revid = _mod_revision.NULL_REVISION
2702
revid = rev_history[-1]
2703
self._run_pre_change_branch_tip_hooks(len(rev_history), revid)
2704
self._write_revision_history(rev_history)
2705
self._clear_cached_state()
2706
self._cache_revision_history(rev_history)
2707
for hook in Branch.hooks['set_rh']:
2708
hook(self, rev_history)
2709
if Branch.hooks['post_change_branch_tip']:
2710
self._run_post_change_branch_tip_hooks(old_revno, old_revid)
2712
def _write_revision_history(self, history):
2713
"""Factored out of set_revision_history.
2715
This performs the actual writing to disk.
2716
It is intended to be called by set_revision_history."""
2717
self._transport.put_bytes(
2718
'revision-history', '\n'.join(history),
2719
mode=self.bzrdir._get_file_mode())
2721
def _gen_revision_history(self):
2722
history = self._transport.get_bytes('revision-history').split('\n')
2723
if history[-1:] == ['']:
2724
# There shouldn't be a trailing newline, but just in case.
2728
def _synchronize_history(self, destination, revision_id):
2729
if not isinstance(destination, FullHistoryBzrBranch):
2730
super(BzrBranch, self)._synchronize_history(
2731
destination, revision_id)
2733
if revision_id == _mod_revision.NULL_REVISION:
2736
new_history = self.revision_history()
2737
if revision_id is not None and new_history != []:
2739
new_history = new_history[:new_history.index(revision_id) + 1]
2741
rev = self.repository.get_revision(revision_id)
2742
new_history = rev.get_history(self.repository)[1:]
2743
destination._set_revision_history(new_history)
2746
def generate_revision_history(self, revision_id, last_rev=None,
2748
"""Create a new revision history that will finish with revision_id.
2750
:param revision_id: the new tip to use.
2751
:param last_rev: The previous last_revision. If not None, then this
2752
must be a ancestory of revision_id, or DivergedBranches is raised.
2753
:param other_branch: The other branch that DivergedBranches should
2754
raise with respect to.
2756
self._set_revision_history(self._lefthand_history(revision_id,
2757
last_rev, other_branch))
2760
class BzrBranch5(FullHistoryBzrBranch):
2761
"""A format 5 branch. This supports new features over plain branches.
2763
It has support for a master_branch which is the data for bound branches.
2767
class BzrBranch8(BzrBranch):
2737
class BzrBranch8(BzrBranch5):
2768
2738
"""A branch that stores tree-reference locations."""
2770
2740
def _open_hook(self):
2796
2766
self._last_revision_info_cache = None
2797
2767
self._reference_info = None
2769
def _last_revision_info(self):
2770
revision_string = self._transport.get_bytes('last-revision')
2771
revno, revision_id = revision_string.rstrip('\n').split(' ', 1)
2772
revision_id = cache_utf8.get_cached_utf8(revision_id)
2774
return revno, revision_id
2776
def _write_last_revision_info(self, revno, revision_id):
2777
"""Simply write out the revision id, with no checks.
2779
Use set_last_revision_info to perform this safely.
2781
Does not update the revision_history cache.
2782
Intended to be called by set_last_revision_info and
2783
_write_revision_history.
2785
revision_id = _mod_revision.ensure_null(revision_id)
2786
out_string = '%d %s\n' % (revno, revision_id)
2787
self._transport.put_bytes('last-revision', out_string,
2788
mode=self.bzrdir._get_file_mode())
2791
def set_last_revision_info(self, revno, revision_id):
2792
revision_id = _mod_revision.ensure_null(revision_id)
2793
old_revno, old_revid = self.last_revision_info()
2794
if self._get_append_revisions_only():
2795
self._check_history_violation(revision_id)
2796
self._run_pre_change_branch_tip_hooks(revno, revision_id)
2797
self._write_last_revision_info(revno, revision_id)
2798
self._clear_cached_state()
2799
self._last_revision_info_cache = revno, revision_id
2800
self._run_post_change_branch_tip_hooks(old_revno, old_revid)
2802
def _synchronize_history(self, destination, revision_id):
2803
"""Synchronize last revision and revision history between branches.
2805
:see: Branch._synchronize_history
2807
# XXX: The base Branch has a fast implementation of this method based
2808
# on set_last_revision_info, but BzrBranch/BzrBranch5 have a slower one
2809
# that uses set_revision_history. This class inherits from BzrBranch5,
2810
# but wants the fast implementation, so it calls
2811
# Branch._synchronize_history directly.
2812
Branch._synchronize_history(self, destination, revision_id)
2799
2814
def _check_history_violation(self, revision_id):
2800
current_revid = self.last_revision()
2801
last_revision = _mod_revision.ensure_null(current_revid)
2815
last_revision = _mod_revision.ensure_null(self.last_revision())
2802
2816
if _mod_revision.is_null(last_revision):
2804
graph = self.repository.get_graph()
2805
for lh_ancestor in graph.iter_lefthand_ancestry(revision_id):
2806
if lh_ancestor == current_revid:
2808
raise errors.AppendRevisionsOnlyViolation(self.user_url)
2818
if last_revision not in self._lefthand_history(revision_id):
2819
raise errors.AppendRevisionsOnlyViolation(self.user_url)
2810
2821
def _gen_revision_history(self):
2811
2822
"""Generate the revision history from last revision
3174
3193
branch._transport.put_bytes('format', format.get_format_string())
3196
def _run_with_write_locked_target(target, callable, *args, **kwargs):
3197
"""Run ``callable(*args, **kwargs)``, write-locking target for the
3200
_run_with_write_locked_target will attempt to release the lock it acquires.
3202
If an exception is raised by callable, then that exception *will* be
3203
propagated, even if the unlock attempt raises its own error. Thus
3204
_run_with_write_locked_target should be preferred to simply doing::
3208
return callable(*args, **kwargs)
3213
# This is very similar to bzrlib.decorators.needs_write_lock. Perhaps they
3214
# should share code?
3217
result = callable(*args, **kwargs)
3219
exc_info = sys.exc_info()
3223
raise exc_info[0], exc_info[1], exc_info[2]
3177
3229
class InterBranch(InterObject):
3178
3230
"""This class represents operations taking place between two branches.
3207
3259
raise NotImplementedError(self.pull)
3209
3261
@needs_write_lock
3210
def push(self, overwrite=False, stop_revision=None, lossy=False,
3262
def update_revisions(self, stop_revision=None, overwrite=False,
3264
"""Pull in new perfect-fit revisions.
3266
:param stop_revision: Updated until the given revision
3267
:param overwrite: Always set the branch pointer, rather than checking
3268
to see if it is a proper descendant.
3269
:param graph: A Graph object that can be used to query history
3270
information. This can be None.
3273
raise NotImplementedError(self.update_revisions)
3276
def push(self, overwrite=False, stop_revision=None,
3211
3277
_override_hook_source_branch=None):
3212
3278
"""Mirror the source branch into the target branch.
3273
3321
self.source.tags.merge_to(self.target.tags)
3275
3323
@needs_write_lock
3276
def fetch(self, stop_revision=None, limit=None):
3277
if self.target.base == self.source.base:
3279
self.source.lock_read()
3281
fetch_spec_factory = fetch.FetchSpecFactory()
3282
fetch_spec_factory.source_branch = self.source
3283
fetch_spec_factory.source_branch_stop_revision_id = stop_revision
3284
fetch_spec_factory.source_repo = self.source.repository
3285
fetch_spec_factory.target_repo = self.target.repository
3286
fetch_spec_factory.target_repo_kind = fetch.TargetRepoKinds.PREEXISTING
3287
fetch_spec_factory.limit = limit
3288
fetch_spec = fetch_spec_factory.make_fetch_spec()
3289
return self.target.repository.fetch(self.source.repository,
3290
fetch_spec=fetch_spec)
3292
self.source.unlock()
3295
def _update_revisions(self, stop_revision=None, overwrite=False,
3324
def update_revisions(self, stop_revision=None, overwrite=False,
3326
"""See InterBranch.update_revisions()."""
3297
3327
other_revno, other_last_revision = self.source.last_revision_info()
3298
3328
stop_revno = None # unknown
3299
3329
if stop_revision is None:
3357
3386
return self._pull(overwrite,
3358
3387
stop_revision, _hook_master=master_branch,
3359
3388
run_hooks=run_hooks,
3360
_override_hook_target=_override_hook_target,
3361
merge_tags_to_master=not source_is_master)
3389
_override_hook_target=_override_hook_target)
3363
3391
if master_branch:
3364
3392
master_branch.unlock()
3366
def push(self, overwrite=False, stop_revision=None, lossy=False,
3394
def push(self, overwrite=False, stop_revision=None,
3367
3395
_override_hook_source_branch=None):
3368
3396
"""See InterBranch.push.
3370
3398
This is the basic concrete implementation of push()
3372
:param _override_hook_source_branch: If specified, run the hooks
3373
passing this Branch as the source, rather than self. This is for
3374
use of RemoteBranch, where push is delegated to the underlying
3400
:param _override_hook_source_branch: If specified, run
3401
the hooks passing this Branch as the source, rather than self.
3402
This is for use of RemoteBranch, where push is delegated to the
3403
underlying vfs-based Branch.
3378
raise errors.LossyPushToSameVCS(self.source, self.target)
3379
3405
# TODO: Public option to disable running hooks - should be trivial but
3382
op = cleanup.OperationWithCleanups(self._push_with_bound_branches)
3383
op.add_cleanup(self.source.lock_read().unlock)
3384
op.add_cleanup(self.target.lock_write().unlock)
3385
return op.run(overwrite, stop_revision,
3386
_override_hook_source_branch=_override_hook_source_branch)
3388
def _basic_push(self, overwrite, stop_revision):
3389
"""Basic implementation of push without bound branches or hooks.
3391
Must be called with source read locked and target write locked.
3393
result = BranchPushResult()
3394
result.source_branch = self.source
3395
result.target_branch = self.target
3396
result.old_revno, result.old_revid = self.target.last_revision_info()
3397
self.source.update_references(self.target)
3398
if result.old_revid != stop_revision:
3399
# We assume that during 'push' this repository is closer than
3401
graph = self.source.repository.get_graph(self.target.repository)
3402
self._update_revisions(stop_revision, overwrite=overwrite,
3404
if self.source._push_should_merge_tags():
3405
result.tag_conflicts = self.source.tags.merge_to(self.target.tags,
3407
result.new_revno, result.new_revid = self.target.last_revision_info()
3410
def _push_with_bound_branches(self, operation, overwrite, stop_revision,
3407
self.source.lock_read()
3409
return _run_with_write_locked_target(
3410
self.target, self._push_with_bound_branches, overwrite,
3412
_override_hook_source_branch=_override_hook_source_branch)
3414
self.source.unlock()
3416
def _push_with_bound_branches(self, overwrite, stop_revision,
3411
3417
_override_hook_source_branch=None):
3412
3418
"""Push from source into target, and into target's master if any.
3425
3431
# be bound to itself? -- mbp 20070507
3426
3432
master_branch = self.target.get_master_branch()
3427
3433
master_branch.lock_write()
3428
operation.add_cleanup(master_branch.unlock)
3429
# push into the master from the source branch.
3430
master_inter = InterBranch.get(self.source, master_branch)
3431
master_inter._basic_push(overwrite, stop_revision)
3432
# and push into the target branch from the source. Note that
3433
# we push from the source branch again, because it's considered
3434
# the highest bandwidth repository.
3435
result = self._basic_push(overwrite, stop_revision)
3436
result.master_branch = master_branch
3437
result.local_branch = self.target
3435
# push into the master from the source branch.
3436
self.source._basic_push(master_branch, overwrite, stop_revision)
3437
# and push into the target branch from the source. Note that we
3438
# push from the source branch again, because its considered the
3439
# highest bandwidth repository.
3440
result = self.source._basic_push(self.target, overwrite,
3442
result.master_branch = master_branch
3443
result.local_branch = self.target
3447
master_branch.unlock()
3439
master_branch = None
3440
3449
# no master branch
3441
result = self._basic_push(overwrite, stop_revision)
3450
result = self.source._basic_push(self.target, overwrite,
3442
3452
# TODO: Why set master_branch and local_branch if there's no
3443
3453
# binding? Maybe cleaner to just leave them unset? -- mbp
3445
3455
result.master_branch = self.target
3446
3456
result.local_branch = None
3450
3460
def _pull(self, overwrite=False, stop_revision=None,
3451
3461
possible_transports=None, _hook_master=None, run_hooks=True,
3452
_override_hook_target=None, local=False,
3453
merge_tags_to_master=True):
3462
_override_hook_target=None, local=False):
3454
3463
"""See Branch.pull.
3456
3465
This function is the core worker, used by GenericInterBranch.pull to