512
462
"""Iterate over an inclusive range of sorted revisions."""
513
463
rev_iter = iter(merge_sorted_revisions)
514
464
if start_revision_id is not None:
515
for node in rev_iter:
465
for rev_id, depth, revno, end_of_merge in rev_iter:
517
466
if rev_id != start_revision_id:
520
469
# The decision to include the start or not
521
470
# depends on the stop_rule if a stop is provided
522
# so pop this node back into the iterator
523
rev_iter = chain(iter([node]), rev_iter)
472
iter([(rev_id, depth, revno, end_of_merge)]),
525
475
if stop_revision_id is None:
527
for node in rev_iter:
529
yield (rev_id, node.merge_depth, node.revno,
476
for rev_id, depth, revno, end_of_merge in rev_iter:
477
yield rev_id, depth, revno, end_of_merge
531
478
elif stop_rule == 'exclude':
532
for node in rev_iter:
479
for rev_id, depth, revno, end_of_merge in rev_iter:
534
480
if rev_id == stop_revision_id:
536
yield (rev_id, node.merge_depth, node.revno,
482
yield rev_id, depth, revno, end_of_merge
538
483
elif stop_rule == 'include':
539
for node in rev_iter:
541
yield (rev_id, node.merge_depth, node.revno,
484
for rev_id, depth, revno, end_of_merge in rev_iter:
485
yield rev_id, depth, revno, end_of_merge
543
486
if rev_id == stop_revision_id:
545
elif stop_rule == 'with-merges-without-common-ancestry':
546
# We want to exclude all revisions that are already part of the
547
# stop_revision_id ancestry.
548
graph = self.repository.get_graph()
549
ancestors = graph.find_unique_ancestors(start_revision_id,
551
for node in rev_iter:
553
if rev_id not in ancestors:
555
yield (rev_id, node.merge_depth, node.revno,
557
488
elif stop_rule == 'with-merges':
558
489
stop_rev = self.repository.get_revision(stop_revision_id)
559
490
if stop_rev.parent_ids:
560
491
left_parent = stop_rev.parent_ids[0]
562
493
left_parent = _mod_revision.NULL_REVISION
563
# left_parent is the actual revision we want to stop logging at,
564
# since we want to show the merged revisions after the stop_rev too
565
reached_stop_revision_id = False
566
revision_id_whitelist = []
567
for node in rev_iter:
494
for rev_id, depth, revno, end_of_merge in rev_iter:
569
495
if rev_id == left_parent:
570
# reached the left parent after the stop_revision
572
if (not reached_stop_revision_id or
573
rev_id in revision_id_whitelist):
574
yield (rev_id, node.merge_depth, node.revno,
576
if reached_stop_revision_id or rev_id == stop_revision_id:
577
# only do the merged revs of rev_id from now on
578
rev = self.repository.get_revision(rev_id)
580
reached_stop_revision_id = True
581
revision_id_whitelist.extend(rev.parent_ids)
497
yield rev_id, depth, revno, end_of_merge
583
499
raise ValueError('invalid stop_rule %r' % stop_rule)
585
def _filter_start_non_ancestors(self, rev_iter):
586
# If we started from a dotted revno, we want to consider it as a tip
587
# and don't want to yield revisions that are not part of its
588
# ancestry. Given the order guaranteed by the merge sort, we will see
589
# uninteresting descendants of the first parent of our tip before the
591
first = rev_iter.next()
592
(rev_id, merge_depth, revno, end_of_merge) = first
595
# We start at a mainline revision so by definition, all others
596
# revisions in rev_iter are ancestors
597
for node in rev_iter:
602
pmap = self.repository.get_parent_map([rev_id])
603
parents = pmap.get(rev_id, [])
605
whitelist.update(parents)
607
# If there is no parents, there is nothing of interest left
609
# FIXME: It's hard to test this scenario here as this code is never
610
# called in that case. -- vila 20100322
613
for (rev_id, merge_depth, revno, end_of_merge) in rev_iter:
615
if rev_id in whitelist:
616
pmap = self.repository.get_parent_map([rev_id])
617
parents = pmap.get(rev_id, [])
618
whitelist.remove(rev_id)
619
whitelist.update(parents)
621
# We've reached the mainline, there is nothing left to
625
# A revision that is not part of the ancestry of our
628
yield (rev_id, merge_depth, revno, end_of_merge)
630
501
def leave_lock_in_place(self):
631
502
"""Tell this branch object not to release the physical lock when this
632
503
object is unlocked.
859
697
old_repository = self.repository
860
698
if len(old_repository._fallback_repositories) != 1:
861
699
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()
700
"of %r" % (self.repository,))
701
# unlock it, including unlocking the fallback
891
702
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):
703
old_repository.lock_read()
705
# Repositories don't offer an interface to remove fallback
706
# repositories today; take the conceptually simpler option and just
707
# reopen it. We reopen it starting from the URL so that we
708
# get a separate connection for RemoteRepositories and can
709
# stream from one of them to the other. This does mean doing
710
# separate SSH connection setup, but unstacking is not a
711
# common operation so it's tolerable.
712
new_bzrdir = bzrdir.BzrDir.open(self.bzrdir.root_transport.base)
713
new_repository = new_bzrdir.find_repository()
714
self.repository = new_repository
715
if self.repository._fallback_repositories:
716
raise AssertionError("didn't expect %r to have "
717
"fallback_repositories"
718
% (self.repository,))
719
# this is not paired with an unlock because it's just restoring
720
# the previous state; the lock's released when set_stacked_on_url
910
722
self.repository.lock_write()
911
# Fetch from the old repository into the new.
912
old_repository.lock_read()
914
723
# XXX: If you unstack a branch while it has a working tree
915
724
# with a pending merge, the pending-merged revisions will no
916
725
# 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)
727
# XXX: This only fetches up to the tip of the repository; it
728
# doesn't bring across any tags. That's fairly consistent
729
# with how branch works, but perhaps not ideal.
730
self.repository.fetch(old_repository,
731
revision_id=self.last_revision(),
926
734
old_repository.unlock()
1031
832
:return: A tuple (revno, revision_id).
1033
834
if self._last_revision_info_cache is None:
1034
self._last_revision_info_cache = self._read_last_revision_info()
835
self._last_revision_info_cache = self._last_revision_info()
1035
836
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)))
838
def _last_revision_info(self):
839
rh = self.revision_history()
842
return (revno, rh[-1])
844
return (0, _mod_revision.NULL_REVISION)
846
@deprecated_method(deprecated_in((1, 6, 0)))
847
def missing_revisions(self, other, stop_revision=None):
848
"""Return a list of new revisions that would perfectly fit.
850
If self and other have not diverged, return a list of the revisions
851
present in other, but missing from self.
853
self_history = self.revision_history()
854
self_len = len(self_history)
855
other_history = other.revision_history()
856
other_len = len(other_history)
857
common_index = min(self_len, other_len) -1
858
if common_index >= 0 and \
859
self_history[common_index] != other_history[common_index]:
860
raise errors.DivergedBranches(self, other)
862
if stop_revision is None:
863
stop_revision = other_len
865
if stop_revision > other_len:
866
raise errors.NoSuchRevision(self, stop_revision)
867
return other_history[self_len:stop_revision]
870
def update_revisions(self, other, stop_revision=None, overwrite=False,
872
"""Pull in new perfect-fit revisions.
874
:param other: Another Branch to pull from
875
:param stop_revision: Updated until the given revision
876
:param overwrite: Always set the branch pointer, rather than checking
877
to see if it is a proper descendant.
878
:param graph: A Graph object that can be used to query history
879
information. This can be None.
882
return InterBranch.get(other, self).update_revisions(stop_revision,
1041
885
def import_last_revision_info(self, source_repo, revno, revid):
1042
886
"""Set the last revision info, importing from another repo if necessary.
888
This is used by the bound branch code to upload a revision to
889
the master branch first before updating the tip of the local branch.
1044
891
:param source_repo: Source repository to optionally fetch from
1045
892
:param revno: Revision number of the new tip
1046
893
:param revid: Revision id of the new tip
1364
1222
Callers will typically also want to check the repository.
1366
:param refs: Calculated refs for this branch as specified by
1367
branch._get_check_refs()
1368
1224
:return: A BranchCheckResult.
1370
result = BranchCheckResult(self)
1226
ret = BranchCheckResult(self)
1227
mainline_parent_id = None
1371
1228
last_revno, last_revision_id = self.last_revision_info()
1372
actual_revno = refs[('lefthand-distance', last_revision_id)]
1373
if actual_revno != last_revno:
1374
result.errors.append(errors.BzrCheckError(
1375
'revno does not match len(mainline) %s != %s' % (
1376
last_revno, actual_revno)))
1377
# TODO: We should probably also check that self.revision_history
1378
# matches the repository for older branch formats.
1379
# If looking for the code that cross-checks repository parents against
1380
# the iter_reverse_revision_history output, that is now a repository
1229
real_rev_history = []
1231
for revid in self.repository.iter_reverse_revision_history(
1233
real_rev_history.append(revid)
1234
except errors.RevisionNotPresent:
1235
ret.ghosts_in_mainline = True
1237
ret.ghosts_in_mainline = False
1238
real_rev_history.reverse()
1239
if len(real_rev_history) != last_revno:
1240
raise errors.BzrCheckError('revno does not match len(mainline)'
1241
' %s != %s' % (last_revno, len(real_rev_history)))
1242
# TODO: We should probably also check that real_rev_history actually
1243
# matches self.revision_history()
1244
for revision_id in real_rev_history:
1246
revision = self.repository.get_revision(revision_id)
1247
except errors.NoSuchRevision, e:
1248
raise errors.BzrCheckError("mainline revision {%s} not in repository"
1250
# In general the first entry on the revision history has no parents.
1251
# But it's not illegal for it to have parents listed; this can happen
1252
# in imports from Arch when the parents weren't reachable.
1253
if mainline_parent_id is not None:
1254
if mainline_parent_id not in revision.parent_ids:
1255
raise errors.BzrCheckError("previous revision {%s} not listed among "
1257
% (mainline_parent_id, revision_id))
1258
mainline_parent_id = revision_id
1384
1261
def _get_checkout_format(self):
1385
1262
"""Return the most suitable metadir for a checkout of this branch.
1386
1263
Weaves are used if this branch's repository uses weaves.
1388
format = self.repository.bzrdir.checkout_metadir()
1389
format.set_branch_format(self._format)
1265
if isinstance(self.bzrdir, bzrdir.BzrDirPreSplitOut):
1266
from bzrlib.repofmt import weaverepo
1267
format = bzrdir.BzrDirMetaFormat1()
1268
format.repository_format = weaverepo.RepositoryFormat7()
1270
format = self.repository.bzrdir.checkout_metadir()
1271
format.set_branch_format(self._format)
1392
1274
def create_clone_on_transport(self, to_transport, revision_id=None,
1393
stacked_on=None, create_prefix=False, use_existing_dir=False,
1275
stacked_on=None, create_prefix=False, use_existing_dir=False):
1395
1276
"""Create a clone of this branch and its bzrdir.
1397
1278
:param to_transport: The transport to clone onto.
1643
1487
"""Return the short format description for this format."""
1644
1488
raise NotImplementedError(self.get_format_description)
1646
def _run_post_branch_init_hooks(self, a_bzrdir, name, branch):
1647
hooks = Branch.hooks['post_branch_init']
1650
params = BranchInitHookParams(self, a_bzrdir, name, branch)
1490
def _initialize_helper(self, a_bzrdir, utf8_files, lock_type='metadir',
1492
"""Initialize a branch in a bzrdir, with specified files
1654
def initialize(self, a_bzrdir, name=None, repository=None):
1655
"""Create a branch of this format in a_bzrdir.
1657
:param name: Name of the colocated branch to create.
1494
:param a_bzrdir: The bzrdir to initialize the branch in
1495
:param utf8_files: The files to create as a list of
1496
(filename, content) tuples
1497
:param set_format: If True, set the format with
1498
self.get_format_string. (BzrBranch4 has its format set
1500
:return: a branch in this format
1502
mutter('creating branch %r in %s', self, a_bzrdir.transport.base)
1503
branch_transport = a_bzrdir.get_branch_transport(self)
1505
'metadir': ('lock', lockdir.LockDir),
1506
'branch4': ('branch-lock', lockable_files.TransportLock),
1508
lock_name, lock_class = lock_map[lock_type]
1509
control_files = lockable_files.LockableFiles(branch_transport,
1510
lock_name, lock_class)
1511
control_files.create_lock()
1513
control_files.lock_write()
1514
except errors.LockContention:
1515
if lock_type != 'branch4':
1521
utf8_files += [('format', self.get_format_string())]
1523
for (filename, content) in utf8_files:
1524
branch_transport.put_bytes(
1526
mode=a_bzrdir._get_file_mode())
1529
control_files.unlock()
1530
return self.open(a_bzrdir, _found=True)
1532
def initialize(self, a_bzrdir):
1533
"""Create a branch of this format in a_bzrdir."""
1659
1534
raise NotImplementedError(self.initialize)
1661
1536
def is_supported(self):
1785
1622
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',
1625
Hooks.__init__(self)
1626
self.create_hook(HookPoint('set_rh',
1790
1627
"Invoked whenever the revision history has been set via "
1791
1628
"set_revision_history. The api signature is (branch, "
1792
1629
"revision_history), and the branch will be write-locked. "
1793
1630
"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',
1631
"hook to use is Branch.post_change_branch_tip.", (0, 15), None))
1632
self.create_hook(HookPoint('open',
1796
1633
"Called with the Branch object that has been opened after a "
1797
"branch is opened.", (1, 8))
1798
self.add_hook('post_push',
1634
"branch is opened.", (1, 8), None))
1635
self.create_hook(HookPoint('post_push',
1799
1636
"Called after a push operation completes. post_push is called "
1800
1637
"with a bzrlib.branch.BranchPushResult object and only runs in the "
1801
"bzr client.", (0, 15))
1802
self.add_hook('post_pull',
1638
"bzr client.", (0, 15), None))
1639
self.create_hook(HookPoint('post_pull',
1803
1640
"Called after a pull operation completes. post_pull is called "
1804
1641
"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 "
1642
"bzr client.", (0, 15), None))
1643
self.create_hook(HookPoint('pre_commit',
1644
"Called after a commit is calculated but before it is is "
1808
1645
"completed. pre_commit is called with (local, master, old_revno, "
1809
1646
"old_revid, future_revno, future_revid, tree_delta, future_tree"
1810
1647
"). old_revid is NULL_REVISION for the first commit to a branch, "
1812
1649
"basis revision. hooks MUST NOT modify this delta. "
1813
1650
" future_tree is an in-memory tree obtained from "
1814
1651
"CommitBuilder.revision_tree() and hooks MUST NOT modify this "
1816
self.add_hook('post_commit',
1652
"tree.", (0,91), None))
1653
self.create_hook(HookPoint('post_commit',
1817
1654
"Called in the bzr client after a commit has completed. "
1818
1655
"post_commit is called with (local, master, old_revno, old_revid, "
1819
1656
"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',
1657
"commit to a branch.", (0, 15), None))
1658
self.create_hook(HookPoint('post_uncommit',
1822
1659
"Called in the bzr client after an uncommit completes. "
1823
1660
"post_uncommit is called with (local, master, old_revno, "
1824
1661
"old_revid, new_revno, new_revid) where local is the local branch "
1825
1662
"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',
1663
"receives new_revno of 0, new_revid of None.", (0, 15), None))
1664
self.create_hook(HookPoint('pre_change_branch_tip',
1828
1665
"Called in bzr client and server before a change to the tip of a "
1829
1666
"branch is made. pre_change_branch_tip is called with a "
1830
1667
"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',
1668
"commit, uncommit will all trigger this hook.", (1, 6), None))
1669
self.create_hook(HookPoint('post_change_branch_tip',
1833
1670
"Called in bzr client and server after a change to the tip of a "
1834
1671
"branch is made. post_change_branch_tip is called with a "
1835
1672
"bzrlib.branch.ChangeBranchTipParams. Note that push, pull, "
1836
"commit, uncommit will all trigger this hook.", (1, 4))
1837
self.add_hook('transform_fallback_location',
1673
"commit, uncommit will all trigger this hook.", (1, 4), None))
1674
self.create_hook(HookPoint('transform_fallback_location',
1838
1675
"Called when a stacked branch is activating its fallback "
1839
1676
"locations. transform_fallback_location is called with (branch, "
1840
1677
"url), and should return a new url. Returning the same url "
1907
1727
self.old_revno, self.old_revid, self.new_revno, self.new_revid)
1910
class BranchInitHookParams(object):
1911
"""Object holding parameters passed to `*_branch_init` hooks.
1913
There are 4 fields that hooks may wish to access:
1915
:ivar format: the branch format
1916
:ivar bzrdir: the BzrDir where the branch will be/has been initialized
1917
:ivar name: name of colocated branch, if any (or None)
1918
:ivar branch: the branch created
1920
Note that for lightweight checkouts, the bzrdir and format fields refer to
1921
the checkout, hence they are different from the corresponding fields in
1922
branch, which refer to the original branch.
1925
def __init__(self, format, a_bzrdir, name, branch):
1926
"""Create a group of BranchInitHook parameters.
1928
:param format: the branch format
1929
:param a_bzrdir: the BzrDir where the branch will be/has been
1931
:param name: name of colocated branch, if any (or None)
1932
:param branch: the branch created
1934
Note that for lightweight checkouts, the bzrdir and format fields refer
1935
to the checkout, hence they are different from the corresponding fields
1936
in branch, which refer to the original branch.
1938
self.format = format
1939
self.bzrdir = a_bzrdir
1941
self.branch = branch
1943
def __eq__(self, other):
1944
return self.__dict__ == other.__dict__
1947
return "<%s of %s>" % (self.__class__.__name__, self.branch)
1950
class SwitchHookParams(object):
1951
"""Object holding parameters passed to `*_switch` hooks.
1953
There are 4 fields that hooks may wish to access:
1955
:ivar control_dir: BzrDir of the checkout to change
1956
:ivar to_branch: branch that the checkout is to reference
1957
:ivar force: skip the check for local commits in a heavy checkout
1958
:ivar revision_id: revision ID to switch to (or None)
1961
def __init__(self, control_dir, to_branch, force, revision_id):
1962
"""Create a group of SwitchHook parameters.
1964
:param control_dir: BzrDir of the checkout to change
1965
:param to_branch: branch that the checkout is to reference
1966
:param force: skip the check for local commits in a heavy checkout
1967
:param revision_id: revision ID to switch to (or None)
1969
self.control_dir = control_dir
1970
self.to_branch = to_branch
1972
self.revision_id = revision_id
1974
def __eq__(self, other):
1975
return self.__dict__ == other.__dict__
1978
return "<%s for %s to (%s, %s)>" % (self.__class__.__name__,
1979
self.control_dir, self.to_branch,
1730
class BzrBranchFormat4(BranchFormat):
1731
"""Bzr branch format 4.
1734
- a revision-history file.
1735
- a branch-lock lock file [ to be shared with the bzrdir ]
1738
def get_format_description(self):
1739
"""See BranchFormat.get_format_description()."""
1740
return "Branch format 4"
1742
def initialize(self, a_bzrdir):
1743
"""Create a branch of this format in a_bzrdir."""
1744
utf8_files = [('revision-history', ''),
1745
('branch-name', ''),
1747
return self._initialize_helper(a_bzrdir, utf8_files,
1748
lock_type='branch4', set_format=False)
1751
super(BzrBranchFormat4, self).__init__()
1752
self._matchingbzrdir = bzrdir.BzrDirFormat6()
1754
def network_name(self):
1755
"""The network name for this format is the control dirs disk label."""
1756
return self._matchingbzrdir.get_format_string()
1758
def open(self, a_bzrdir, _found=False, ignore_fallbacks=False):
1759
"""See BranchFormat.open()."""
1761
# we are being called directly and must probe.
1762
raise NotImplementedError
1763
return BzrBranch(_format=self,
1764
_control_files=a_bzrdir._control_files,
1766
_repository=a_bzrdir.open_repository())
1769
return "Bazaar-NG branch format 4"
1983
1772
class BranchFormatMetadir(BranchFormat):
2227
1978
"""See BranchFormat.get_format_description()."""
2228
1979
return "Checkout reference format 1"
2230
def get_reference(self, a_bzrdir, name=None):
1981
def get_reference(self, a_bzrdir):
2231
1982
"""See BranchFormat.get_reference()."""
2232
transport = a_bzrdir.get_branch_transport(None, name=name)
2233
return transport.get_bytes('location')
1983
transport = a_bzrdir.get_branch_transport(None)
1984
return transport.get('location').read()
2235
def set_reference(self, a_bzrdir, name, to_branch):
1986
def set_reference(self, a_bzrdir, to_branch):
2236
1987
"""See BranchFormat.set_reference()."""
2237
transport = a_bzrdir.get_branch_transport(None, name=name)
1988
transport = a_bzrdir.get_branch_transport(None)
2238
1989
location = transport.put_bytes('location', to_branch.base)
2240
def initialize(self, a_bzrdir, name=None, target_branch=None,
1991
def initialize(self, a_bzrdir, target_branch=None):
2242
1992
"""Create a branch of this format in a_bzrdir."""
2243
1993
if target_branch is None:
2244
1994
# this format does not implement branch itself, thus the implicit
2245
1995
# creation contract must see it as uninitializable
2246
1996
raise errors.UninitializableFormat(self)
2247
mutter('creating branch reference in %s', a_bzrdir.user_url)
2248
branch_transport = a_bzrdir.get_branch_transport(self, name=name)
1997
mutter('creating branch reference in %s', a_bzrdir.transport.base)
1998
branch_transport = a_bzrdir.get_branch_transport(self)
2249
1999
branch_transport.put_bytes('location',
2250
target_branch.bzrdir.user_url)
2000
target_branch.bzrdir.root_transport.base)
2251
2001
branch_transport.put_bytes('format', self.get_format_string())
2253
a_bzrdir, name, _found=True,
2003
a_bzrdir, _found=True,
2254
2004
possible_transports=[target_branch.bzrdir.root_transport])
2255
self._run_post_branch_init_hooks(a_bzrdir, name, branch)
2258
2006
def __init__(self):
2259
2007
super(BranchReferenceFormat, self).__init__()
2500
2190
"""See Branch.print_file."""
2501
2191
return self.repository.print_file(file, revision_id)
2193
def _write_revision_history(self, history):
2194
"""Factored out of set_revision_history.
2196
This performs the actual writing to disk.
2197
It is intended to be called by BzrBranch5.set_revision_history."""
2198
self._transport.put_bytes(
2199
'revision-history', '\n'.join(history),
2200
mode=self.bzrdir._get_file_mode())
2203
def set_revision_history(self, rev_history):
2204
"""See Branch.set_revision_history."""
2205
if 'evil' in debug.debug_flags:
2206
mutter_callsite(3, "set_revision_history scales with history.")
2207
check_not_reserved_id = _mod_revision.check_not_reserved_id
2208
for rev_id in rev_history:
2209
check_not_reserved_id(rev_id)
2210
if Branch.hooks['post_change_branch_tip']:
2211
# Don't calculate the last_revision_info() if there are no hooks
2213
old_revno, old_revid = self.last_revision_info()
2214
if len(rev_history) == 0:
2215
revid = _mod_revision.NULL_REVISION
2217
revid = rev_history[-1]
2218
self._run_pre_change_branch_tip_hooks(len(rev_history), revid)
2219
self._write_revision_history(rev_history)
2220
self._clear_cached_state()
2221
self._cache_revision_history(rev_history)
2222
for hook in Branch.hooks['set_rh']:
2223
hook(self, rev_history)
2224
if Branch.hooks['post_change_branch_tip']:
2225
self._run_post_change_branch_tip_hooks(old_revno, old_revid)
2227
def _synchronize_history(self, destination, revision_id):
2228
"""Synchronize last revision and revision history between branches.
2230
This version is most efficient when the destination is also a
2231
BzrBranch5, but works for BzrBranch6 as long as the revision
2232
history is the true lefthand parent history, and all of the revisions
2233
are in the destination's repository. If not, set_revision_history
2236
:param destination: The branch to copy the history into
2237
:param revision_id: The revision-id to truncate history at. May
2238
be None to copy complete history.
2240
if not isinstance(destination._format, BzrBranchFormat5):
2241
super(BzrBranch, self)._synchronize_history(
2242
destination, revision_id)
2244
if revision_id == _mod_revision.NULL_REVISION:
2247
new_history = self.revision_history()
2248
if revision_id is not None and new_history != []:
2250
new_history = new_history[:new_history.index(revision_id) + 1]
2252
rev = self.repository.get_revision(revision_id)
2253
new_history = rev.get_history(self.repository)[1:]
2254
destination.set_revision_history(new_history)
2503
2256
@needs_write_lock
2504
2257
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)
2258
"""Set the last revision of this branch.
2260
The caller is responsible for checking that the revno is correct
2261
for this revision id.
2263
It may be possible to set the branch last revision to an id not
2264
present in the repository. However, branches can also be
2265
configured to check constraints on history, in which case this may not
2507
2268
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)
2269
# this old format stores the full history, but this api doesn't
2270
# provide it, so we must generate, and might as well check it's
2272
history = self._lefthand_history(revision_id)
2273
if len(history) != revno:
2274
raise AssertionError('%d != %d' % (len(history), revno))
2275
self.set_revision_history(history)
2277
def _gen_revision_history(self):
2278
history = self._transport.get_bytes('revision-history').split('\n')
2279
if history[-1:] == ['']:
2280
# There shouldn't be a trailing newline, but just in case.
2285
def generate_revision_history(self, revision_id, last_rev=None,
2287
"""Create a new revision history that will finish with revision_id.
2289
:param revision_id: the new tip to use.
2290
:param last_rev: The previous last_revision. If not None, then this
2291
must be a ancestory of revision_id, or DivergedBranches is raised.
2292
:param other_branch: The other branch that DivergedBranches should
2293
raise with respect to.
2295
self.set_revision_history(self._lefthand_history(revision_id,
2296
last_rev, other_branch))
2517
2298
def basis_tree(self):
2518
2299
"""See Branch.basis_tree."""
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):
2448
class BzrBranch8(BzrBranch5):
2768
2449
"""A branch that stores tree-reference locations."""
2770
2451
def _open_hook(self):
2796
2477
self._last_revision_info_cache = None
2797
2478
self._reference_info = None
2480
def _last_revision_info(self):
2481
revision_string = self._transport.get_bytes('last-revision')
2482
revno, revision_id = revision_string.rstrip('\n').split(' ', 1)
2483
revision_id = cache_utf8.get_cached_utf8(revision_id)
2485
return revno, revision_id
2487
def _write_last_revision_info(self, revno, revision_id):
2488
"""Simply write out the revision id, with no checks.
2490
Use set_last_revision_info to perform this safely.
2492
Does not update the revision_history cache.
2493
Intended to be called by set_last_revision_info and
2494
_write_revision_history.
2496
revision_id = _mod_revision.ensure_null(revision_id)
2497
out_string = '%d %s\n' % (revno, revision_id)
2498
self._transport.put_bytes('last-revision', out_string,
2499
mode=self.bzrdir._get_file_mode())
2502
def set_last_revision_info(self, revno, revision_id):
2503
revision_id = _mod_revision.ensure_null(revision_id)
2504
old_revno, old_revid = self.last_revision_info()
2505
if self._get_append_revisions_only():
2506
self._check_history_violation(revision_id)
2507
self._run_pre_change_branch_tip_hooks(revno, revision_id)
2508
self._write_last_revision_info(revno, revision_id)
2509
self._clear_cached_state()
2510
self._last_revision_info_cache = revno, revision_id
2511
self._run_post_change_branch_tip_hooks(old_revno, old_revid)
2513
def _synchronize_history(self, destination, revision_id):
2514
"""Synchronize last revision and revision history between branches.
2516
:see: Branch._synchronize_history
2518
# XXX: The base Branch has a fast implementation of this method based
2519
# on set_last_revision_info, but BzrBranch/BzrBranch5 have a slower one
2520
# that uses set_revision_history. This class inherits from BzrBranch5,
2521
# but wants the fast implementation, so it calls
2522
# Branch._synchronize_history directly.
2523
Branch._synchronize_history(self, destination, revision_id)
2799
2525
def _check_history_violation(self, revision_id):
2800
current_revid = self.last_revision()
2801
last_revision = _mod_revision.ensure_null(current_revid)
2526
last_revision = _mod_revision.ensure_null(self.last_revision())
2802
2527
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)
2529
if last_revision not in self._lefthand_history(revision_id):
2530
raise errors.AppendRevisionsOnlyViolation(self.base)
2810
2532
def _gen_revision_history(self):
2811
2533
"""Generate the revision history from last revision
3216
2986
raise NotImplementedError(self.push)
3219
def copy_content_into(self, revision_id=None):
3220
"""Copy the content of source into target
3222
revision_id: if not None, the revision history in the new branch will
3223
be truncated to end with revision_id.
3225
raise NotImplementedError(self.copy_content_into)
3228
def fetch(self, stop_revision=None, limit=None):
3231
:param stop_revision: Last revision to fetch
3232
:param limit: Optional rough limit of revisions to fetch
3234
raise NotImplementedError(self.fetch)
3237
2989
class GenericInterBranch(InterBranch):
3238
"""InterBranch implementation that uses public Branch functions."""
3241
def is_compatible(klass, source, target):
3242
# GenericBranch uses the public API, so always compatible
3246
def _get_branch_formats_to_test(klass):
3247
return [(format_registry.get_default(), format_registry.get_default())]
3250
def unwrap_format(klass, format):
3251
if isinstance(format, remote.RemoteBranchFormat):
3252
format._ensure_real()
3253
return format._custom_format
3257
def copy_content_into(self, revision_id=None):
3258
"""Copy the content of source into target
3260
revision_id: if not None, the revision history in the new branch will
3261
be truncated to end with revision_id.
3263
self.source.update_references(self.target)
3264
self.source._synchronize_history(self.target, revision_id)
3266
parent = self.source.get_parent()
3267
except errors.InaccessibleParent, e:
3268
mutter('parent was not accessible to copy: %s', e)
3271
self.target.set_parent(parent)
3272
if self.source._push_should_merge_tags():
3273
self.source.tags.merge_to(self.target.tags)
3276
def fetch(self, stop_revision=None, limit=None):
3277
if self.target.base == self.source.base:
2990
"""InterBranch implementation that uses public Branch functions.
2994
def _get_branch_formats_to_test():
2995
return BranchFormat._default_format, BranchFormat._default_format
2997
def update_revisions(self, stop_revision=None, overwrite=False,
2999
"""See InterBranch.update_revisions()."""
3279
3000
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)
3002
other_revno, other_last_revision = self.source.last_revision_info()
3003
stop_revno = None # unknown
3004
if stop_revision is None:
3005
stop_revision = other_last_revision
3006
if _mod_revision.is_null(stop_revision):
3007
# if there are no commits, we're done.
3009
stop_revno = other_revno
3011
# what's the current last revision, before we fetch [and change it
3013
last_rev = _mod_revision.ensure_null(self.target.last_revision())
3014
# we fetch here so that we don't process data twice in the common
3015
# case of having something to pull, and so that the check for
3016
# already merged can operate on the just fetched graph, which will
3017
# be cached in memory.
3018
self.target.fetch(self.source, stop_revision)
3019
# Check to see if one is an ancestor of the other
3022
graph = self.target.repository.get_graph()
3023
if self.target._check_if_descendant_or_diverged(
3024
stop_revision, last_rev, graph, self.source):
3025
# stop_revision is a descendant of last_rev, but we aren't
3026
# overwriting, so we're done.
3028
if stop_revno is None:
3030
graph = self.target.repository.get_graph()
3031
this_revno, this_last_revision = \
3032
self.target.last_revision_info()
3033
stop_revno = graph.find_distance_to_null(stop_revision,
3034
[(other_last_revision, other_revno),
3035
(this_last_revision, this_revno)])
3036
self.target.set_last_revision_info(stop_revno, stop_revision)
3292
3038
self.source.unlock()
3295
def _update_revisions(self, stop_revision=None, overwrite=False,
3297
other_revno, other_last_revision = self.source.last_revision_info()
3298
stop_revno = None # unknown
3299
if stop_revision is None:
3300
stop_revision = other_last_revision
3301
if _mod_revision.is_null(stop_revision):
3302
# if there are no commits, we're done.
3304
stop_revno = other_revno
3306
# what's the current last revision, before we fetch [and change it
3308
last_rev = _mod_revision.ensure_null(self.target.last_revision())
3309
# we fetch here so that we don't process data twice in the common
3310
# case of having something to pull, and so that the check for
3311
# already merged can operate on the just fetched graph, which will
3312
# be cached in memory.
3313
self.fetch(stop_revision=stop_revision)
3314
# Check to see if one is an ancestor of the other
3317
graph = self.target.repository.get_graph()
3318
if self.target._check_if_descendant_or_diverged(
3319
stop_revision, last_rev, graph, self.source):
3320
# stop_revision is a descendant of last_rev, but we aren't
3321
# overwriting, so we're done.
3323
if stop_revno is None:
3325
graph = self.target.repository.get_graph()
3326
this_revno, this_last_revision = \
3327
self.target.last_revision_info()
3328
stop_revno = graph.find_distance_to_null(stop_revision,
3329
[(other_last_revision, other_revno),
3330
(this_last_revision, this_revno)])
3331
self.target.set_last_revision_info(stop_revno, stop_revision)
3334
3040
def pull(self, overwrite=False, stop_revision=None,
3335
possible_transports=None, run_hooks=True,
3336
_override_hook_target=None, local=False):
3337
"""Pull from source into self, updating my master if any.
3339
:param run_hooks: Private parameter - if false, this branch
3340
is being called because it's the master of the primary branch,
3341
so it should not run its hooks.
3343
bound_location = self.target.get_bound_location()
3344
if local and not bound_location:
3345
raise errors.LocalRequiresBoundBranch()
3346
master_branch = None
3347
source_is_master = (self.source.user_url == bound_location)
3348
if not local and bound_location and not source_is_master:
3349
# not pulling from master, so we need to update master.
3350
master_branch = self.target.get_master_branch(possible_transports)
3351
master_branch.lock_write()
3354
# pull from source into master.
3355
master_branch.pull(self.source, overwrite, stop_revision,
3357
return self._pull(overwrite,
3358
stop_revision, _hook_master=master_branch,
3359
run_hooks=run_hooks,
3360
_override_hook_target=_override_hook_target,
3361
merge_tags_to_master=not source_is_master)
3364
master_branch.unlock()
3366
def push(self, overwrite=False, stop_revision=None, lossy=False,
3367
_override_hook_source_branch=None):
3368
"""See InterBranch.push.
3370
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
3378
raise errors.LossyPushToSameVCS(self.source, self.target)
3379
# 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,
3411
_override_hook_source_branch=None):
3412
"""Push from source into target, and into target's master if any.
3415
if _override_hook_source_branch:
3416
result.source_branch = _override_hook_source_branch
3417
for hook in Branch.hooks['post_push']:
3420
bound_location = self.target.get_bound_location()
3421
if bound_location and self.target.base != bound_location:
3422
# there is a master branch.
3424
# XXX: Why the second check? Is it even supported for a branch to
3425
# be bound to itself? -- mbp 20070507
3426
master_branch = self.target.get_master_branch()
3427
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
3439
master_branch = None
3441
result = self._basic_push(overwrite, stop_revision)
3442
# TODO: Why set master_branch and local_branch if there's no
3443
# binding? Maybe cleaner to just leave them unset? -- mbp
3445
result.master_branch = self.target
3446
result.local_branch = None
3450
def _pull(self, overwrite=False, stop_revision=None,
3451
3041
possible_transports=None, _hook_master=None, run_hooks=True,
3452
_override_hook_target=None, local=False,
3453
merge_tags_to_master=True):
3042
_override_hook_target=None, local=False):
3454
3043
"""See Branch.pull.
3456
This function is the core worker, used by GenericInterBranch.pull to
3457
avoid duplication when pulling source->master and source->local.
3459
3045
:param _hook_master: Private parameter - set the branch to
3460
3046
be supplied as the master to pull hooks.
3461
3047
:param run_hooks: Private parameter - if false, this branch
3462
3048
is being called because it's the master of the primary branch,
3463
3049
so it should not run its hooks.
3464
is being called because it's the master of the primary branch,
3465
so it should not run its hooks.
3466
3050
:param _override_hook_target: Private parameter - set the branch to be
3467
3051
supplied as the target_branch to pull hooks.
3468
3052
:param local: Only update the local branch, and not the bound branch.
3508
3092
self.source.unlock()
3095
def push(self, overwrite=False, stop_revision=None,
3096
_override_hook_source_branch=None):
3097
"""See InterBranch.push.
3099
This is the basic concrete implementation of push()
3101
:param _override_hook_source_branch: If specified, run
3102
the hooks passing this Branch as the source, rather than self.
3103
This is for use of RemoteBranch, where push is delegated to the
3104
underlying vfs-based Branch.
3106
# TODO: Public option to disable running hooks - should be trivial but
3108
self.source.lock_read()
3110
return _run_with_write_locked_target(
3111
self.target, self._push_with_bound_branches, overwrite,
3113
_override_hook_source_branch=_override_hook_source_branch)
3115
self.source.unlock()
3117
def _push_with_bound_branches(self, overwrite, stop_revision,
3118
_override_hook_source_branch=None):
3119
"""Push from source into target, and into target's master if any.
3122
if _override_hook_source_branch:
3123
result.source_branch = _override_hook_source_branch
3124
for hook in Branch.hooks['post_push']:
3127
bound_location = self.target.get_bound_location()
3128
if bound_location and self.target.base != bound_location:
3129
# there is a master branch.
3131
# XXX: Why the second check? Is it even supported for a branch to
3132
# be bound to itself? -- mbp 20070507
3133
master_branch = self.target.get_master_branch()
3134
master_branch.lock_write()
3136
# push into the master from the source branch.
3137
self.source._basic_push(master_branch, overwrite, stop_revision)
3138
# and push into the target branch from the source. Note that we
3139
# push from the source branch again, because its considered the
3140
# highest bandwidth repository.
3141
result = self.source._basic_push(self.target, overwrite,
3143
result.master_branch = master_branch
3144
result.local_branch = self.target
3148
master_branch.unlock()
3151
result = self.source._basic_push(self.target, overwrite,
3153
# TODO: Why set master_branch and local_branch if there's no
3154
# binding? Maybe cleaner to just leave them unset? -- mbp
3156
result.master_branch = self.target
3157
result.local_branch = None
3162
def is_compatible(self, source, target):
3163
# GenericBranch uses the public API, so always compatible
3167
class InterToBranch5(GenericInterBranch):
3170
def _get_branch_formats_to_test():
3171
return BranchFormat._default_format, BzrBranchFormat5()
3173
def pull(self, overwrite=False, stop_revision=None,
3174
possible_transports=None, run_hooks=True,
3175
_override_hook_target=None, local=False):
3176
"""Pull from source into self, updating my master if any.
3178
:param run_hooks: Private parameter - if false, this branch
3179
is being called because it's the master of the primary branch,
3180
so it should not run its hooks.
3182
bound_location = self.target.get_bound_location()
3183
if local and not bound_location:
3184
raise errors.LocalRequiresBoundBranch()
3185
master_branch = None
3186
if not local and bound_location and self.source.base != bound_location:
3187
# not pulling from master, so we need to update master.
3188
master_branch = self.target.get_master_branch(possible_transports)
3189
master_branch.lock_write()
3192
# pull from source into master.
3193
master_branch.pull(self.source, overwrite, stop_revision,
3195
return super(InterToBranch5, self).pull(overwrite,
3196
stop_revision, _hook_master=master_branch,
3197
run_hooks=run_hooks,
3198
_override_hook_target=_override_hook_target)
3201
master_branch.unlock()
3512
3204
InterBranch.register_optimiser(GenericInterBranch)
3205
InterBranch.register_optimiser(InterToBranch5)