135
137
def open_containing(url, possible_transports=None):
136
138
"""Open an existing branch which contains url.
138
140
This probes for a branch at url, and searches upwards from there.
140
142
Basically we keep looking up until we find the control directory or
141
143
run into the root. If there isn't one, raises NotBranchError.
142
If there is one and it is either an unrecognised format or an unsupported
144
If there is one and it is either an unrecognised format or an unsupported
143
145
format, UnknownFormatError or UnsupportedFormatError are raised.
144
146
If there is one, it is returned, along with the unused portion of url.
174
184
def is_locked(self):
175
185
raise NotImplementedError(self.is_locked)
187
def _lefthand_history(self, revision_id, last_rev=None,
189
if 'evil' in debug.debug_flags:
190
mutter_callsite(4, "_lefthand_history scales with history.")
191
# stop_revision must be a descendant of last_revision
192
graph = self.repository.get_graph()
193
if last_rev is not None:
194
if not graph.is_ancestor(last_rev, revision_id):
195
# our previous tip is not merged into stop_revision
196
raise errors.DivergedBranches(self, other_branch)
197
# make a new revision history from the graph
198
parents_map = graph.get_parent_map([revision_id])
199
if revision_id not in parents_map:
200
raise errors.NoSuchRevision(self, revision_id)
201
current_rev_id = revision_id
203
check_not_reserved_id = _mod_revision.check_not_reserved_id
204
# Do not include ghosts or graph origin in revision_history
205
while (current_rev_id in parents_map and
206
len(parents_map[current_rev_id]) > 0):
207
check_not_reserved_id(current_rev_id)
208
new_history.append(current_rev_id)
209
current_rev_id = parents_map[current_rev_id][0]
210
parents_map = graph.get_parent_map([current_rev_id])
211
new_history.reverse()
177
214
def lock_write(self):
178
215
raise NotImplementedError(self.lock_write)
464
501
def get_old_bound_location(self):
465
502
"""Return the URL of the branch we used to be bound to
467
504
raise errors.UpgradeRequired(self.base)
469
def get_commit_builder(self, parents, config=None, timestamp=None,
470
timezone=None, committer=None, revprops=None,
506
def get_commit_builder(self, parents, config=None, timestamp=None,
507
timezone=None, committer=None, revprops=None,
471
508
revision_id=None):
472
509
"""Obtain a CommitBuilder for this branch.
474
511
:param parents: Revision ids of the parents of the new revision.
475
512
:param config: Optional configuration to use.
476
513
:param timestamp: Optional timestamp recorded for commit.
483
520
if config is None:
484
521
config = self.get_config()
486
523
return self.repository.get_commit_builder(self, parents, config,
487
524
timestamp, timezone, committer, revprops, revision_id)
489
526
def get_master_branch(self, possible_transports=None):
490
527
"""Return the branch we are bound to.
492
529
:return: Either a Branch, or None
566
603
def _gen_revision_history(self):
567
604
"""Return sequence of revision hashes on to this branch.
569
606
Unlike revision_history, this method always regenerates or rereads the
570
607
revision history, i.e. it does not cache the result, so repeated calls
571
608
may be expensive.
573
610
Concrete subclasses should override this instead of revision_history so
574
611
that subclasses do not need to deal with caching logic.
576
613
This API is semi-public; it only for use by subclasses, all other code
577
614
should consider it to be private.
668
705
information. This can be None.
673
other_revno, other_last_revision = other.last_revision_info()
674
stop_revno = None # unknown
675
if stop_revision is None:
676
stop_revision = other_last_revision
677
if _mod_revision.is_null(stop_revision):
678
# if there are no commits, we're done.
680
stop_revno = other_revno
682
# what's the current last revision, before we fetch [and change it
684
last_rev = _mod_revision.ensure_null(self.last_revision())
685
# we fetch here so that we don't process data twice in the common
686
# case of having something to pull, and so that the check for
687
# already merged can operate on the just fetched graph, which will
688
# be cached in memory.
689
self.fetch(other, stop_revision)
690
# Check to see if one is an ancestor of the other
693
graph = self.repository.get_graph()
694
if self._check_if_descendant_or_diverged(
695
stop_revision, last_rev, graph, other):
696
# stop_revision is a descendant of last_rev, but we aren't
697
# overwriting, so we're done.
699
if stop_revno is None:
701
graph = self.repository.get_graph()
702
this_revno, this_last_revision = self.last_revision_info()
703
stop_revno = graph.find_distance_to_null(stop_revision,
704
[(other_last_revision, other_revno),
705
(this_last_revision, this_revno)])
706
self.set_last_revision_info(stop_revno, stop_revision)
708
return InterBranch.get(other, self).update_revisions(stop_revision,
710
711
def revision_id_to_revno(self, revision_id):
711
712
"""Given a revision id, return its revno"""
819
820
"""Set a new push location for this branch."""
820
821
raise NotImplementedError(self.set_push_location)
823
def _run_post_change_branch_tip_hooks(self, old_revno, old_revid):
824
"""Run the post_change_branch_tip hooks."""
825
hooks = Branch.hooks['post_change_branch_tip']
828
new_revno, new_revid = self.last_revision_info()
829
params = ChangeBranchTipParams(
830
self, old_revno, new_revno, old_revid, new_revid)
834
def _run_pre_change_branch_tip_hooks(self, new_revno, new_revid):
835
"""Run the pre_change_branch_tip hooks."""
836
hooks = Branch.hooks['pre_change_branch_tip']
839
old_revno, old_revid = self.last_revision_info()
840
params = ChangeBranchTipParams(
841
self, old_revno, new_revno, old_revid, new_revid)
845
except errors.TipChangeRejected:
848
exc_info = sys.exc_info()
849
hook_name = Branch.hooks.get_hook_name(hook)
850
raise errors.HookFailed(
851
'pre_change_branch_tip', hook_name, exc_info)
822
853
def set_parent(self, url):
823
854
raise NotImplementedError(self.set_parent)
825
856
@needs_write_lock
826
857
def update(self):
827
"""Synchronise this branch with the master branch if any.
858
"""Synchronise this branch with the master branch if any.
829
860
:return: None or the last_revision pivoted out during the update.
847
878
raise errors.InvalidRevisionNumber(revno)
850
def clone(self, to_bzrdir, revision_id=None):
881
def clone(self, to_bzrdir, revision_id=None, repository_policy=None):
851
882
"""Clone this branch into to_bzrdir preserving all semantic values.
884
Most API users will want 'create_clone_on_transport', which creates a
885
new bzrdir and branch on the fly.
853
887
revision_id: if not None, the revision history in the new branch will
854
888
be truncated to end with revision_id.
856
890
result = to_bzrdir.create_branch()
891
if repository_policy is not None:
892
repository_policy.configure_branch(result)
857
893
self.copy_content_into(result, revision_id=revision_id)
917
953
destination.set_parent(parent)
918
self.tags.merge_to(destination.tags)
954
if self._push_should_merge_tags():
955
self.tags.merge_to(destination.tags)
922
959
"""Check consistency of the branch.
924
961
In particular this checks that revisions given in the revision-history
925
do actually match up in the revision graph, and that they're all
962
do actually match up in the revision graph, and that they're all
926
963
present in the repository.
928
965
Callers will typically also want to check the repository.
930
967
:return: A BranchCheckResult.
969
1006
format.set_branch_format(self._format)
1009
def create_clone_on_transport(self, to_transport, revision_id=None,
1011
"""Create a clone of this branch and its bzrdir.
1013
:param to_transport: The transport to clone onto.
1014
:param revision_id: The revision id to use as tip in the new branch.
1015
If None the tip is obtained from this branch.
1016
:param stacked_on: An optional URL to stack the clone on.
1018
# XXX: Fix the bzrdir API to allow getting the branch back from the
1019
# clone call. Or something. 20090224 RBC/spiv.
1020
dir_to = self.bzrdir.clone_on_transport(to_transport,
1021
revision_id=revision_id, stacked_on=stacked_on)
1022
return dir_to.open_branch()
972
1024
def create_checkout(self, to_location, revision_id=None,
973
1025
lightweight=False, accelerator_tree=None,
974
1026
hardlink=False):
975
1027
"""Create a checkout of a branch.
977
1029
:param to_location: The url to produce the checkout at
978
1030
:param revision_id: The revision to check out
979
1031
:param lightweight: If True, produce a lightweight checkout, otherwise,
1082
1134
* a format string,
1083
1135
* an open routine.
1085
Formats are placed in an dict by their format string for reference
1137
Formats are placed in an dict by their format string for reference
1086
1138
during branch opening. Its not required that these be instances, they
1087
can be classes themselves with class methods - it simply depends on
1139
can be classes themselves with class methods - it simply depends on
1088
1140
whether state is needed for a given format or not.
1090
1142
Once a format is deprecated, just deprecate the initialize and open
1091
methods on the format class. Do not deprecate the object, as the
1143
methods on the format class. Do not deprecate the object, as the
1092
1144
object will be created every time regardless.
1196
1248
"""Is this format supported?
1198
1250
Supported formats can be initialized and opened.
1199
Unsupported formats may not support initialization or committing or
1251
Unsupported formats may not support initialization or committing or
1200
1252
some other features depending on the reason for not being supported.
1256
def network_name(self):
1257
"""A simple byte string uniquely identifying this format for RPC calls.
1259
MetaDir branch formats use their disk format string to identify the
1260
repository over the wire. All in one formats such as bzr < 0.8, and
1261
foreign formats like svn/git and hg should use some marker which is
1262
unique and immutable.
1264
raise NotImplementedError(self.network_name)
1204
1266
def open(self, a_bzrdir, _found=False):
1205
1267
"""Return the branch object for a_bzrdir
1260
1325
# (push_result)
1261
1326
# containing the members
1262
1327
# (source, local, master, old_revno, old_revid, new_revno, new_revid)
1263
# where local is the local target branch or None, master is the target
1328
# where local is the local target branch or None, master is the target
1264
1329
# master branch, and the rest should be self explanatory. The source
1265
1330
# is read locked and the target branches write locked. Source will
1266
1331
# be the local low-latency branch.
1270
1335
# (pull_result)
1271
1336
# containing the members
1272
1337
# (source, local, master, old_revno, old_revid, new_revno, new_revid)
1273
# where local is the local branch or None, master is the target
1338
# where local is the local branch or None, master is the target
1274
1339
# master branch, and the rest should be self explanatory. The source
1275
1340
# is read locked and the target branches write locked. The local
1276
1341
# branch is the low-latency branch.
1651
1740
really matter if it's on an nfs/smb/afs/coda/... share, as long as
1652
1741
it's writable, and can be accessed via the normal filesystem API.
1654
:ivar _transport: Transport for file operations on this branch's
1743
:ivar _transport: Transport for file operations on this branch's
1655
1744
control files, typically pointing to the .bzr/branch directory.
1656
1745
:ivar repository: Repository for this branch.
1657
:ivar base: The url of the base directory for this branch; the one
1746
:ivar base: The url of the base directory for this branch; the one
1658
1747
containing the .bzr directory.
1661
1750
def __init__(self, _format=None,
1662
1751
_control_files=None, a_bzrdir=None, _repository=None):
1663
1752
"""Create new branch object at a particular location."""
1795
1884
new_history = rev.get_history(self.repository)[1:]
1796
1885
destination.set_revision_history(new_history)
1798
def _run_pre_change_branch_tip_hooks(self, new_revno, new_revid):
1799
"""Run the pre_change_branch_tip hooks."""
1800
hooks = Branch.hooks['pre_change_branch_tip']
1803
old_revno, old_revid = self.last_revision_info()
1804
params = ChangeBranchTipParams(
1805
self, old_revno, new_revno, old_revid, new_revid)
1809
except errors.TipChangeRejected:
1812
exc_info = sys.exc_info()
1813
hook_name = Branch.hooks.get_hook_name(hook)
1814
raise errors.HookFailed(
1815
'pre_change_branch_tip', hook_name, exc_info)
1817
def _run_post_change_branch_tip_hooks(self, old_revno, old_revid):
1818
"""Run the post_change_branch_tip hooks."""
1819
hooks = Branch.hooks['post_change_branch_tip']
1822
new_revno, new_revid = self.last_revision_info()
1823
params = ChangeBranchTipParams(
1824
self, old_revno, new_revno, old_revid, new_revid)
1828
1887
@needs_write_lock
1829
1888
def set_last_revision_info(self, revno, revision_id):
1830
1889
"""Set the last revision of this branch.
1856
def _lefthand_history(self, revision_id, last_rev=None,
1858
if 'evil' in debug.debug_flags:
1859
mutter_callsite(4, "_lefthand_history scales with history.")
1860
# stop_revision must be a descendant of last_revision
1861
graph = self.repository.get_graph()
1862
if last_rev is not None:
1863
if not graph.is_ancestor(last_rev, revision_id):
1864
# our previous tip is not merged into stop_revision
1865
raise errors.DivergedBranches(self, other_branch)
1866
# make a new revision history from the graph
1867
parents_map = graph.get_parent_map([revision_id])
1868
if revision_id not in parents_map:
1869
raise errors.NoSuchRevision(self, revision_id)
1870
current_rev_id = revision_id
1872
check_not_reserved_id = _mod_revision.check_not_reserved_id
1873
# Do not include ghosts or graph origin in revision_history
1874
while (current_rev_id in parents_map and
1875
len(parents_map[current_rev_id]) > 0):
1876
check_not_reserved_id(current_rev_id)
1877
new_history.append(current_rev_id)
1878
current_rev_id = parents_map[current_rev_id][0]
1879
parents_map = graph.get_parent_map([current_rev_id])
1880
new_history.reverse()
1883
1915
@needs_write_lock
1884
1916
def generate_revision_history(self, revision_id, last_rev=None,
1885
1917
other_branch=None):
1958
1990
This is the basic concrete implementation of push()
1960
1992
:param _override_hook_source_branch: If specified, run
1961
the hooks passing this Branch as the source, rather than self.
1993
the hooks passing this Branch as the source, rather than self.
1962
1994
This is for use of RemoteBranch, where push is delegated to the
1963
underlying vfs-based Branch.
1995
underlying vfs-based Branch.
1965
1997
# TODO: Public option to disable running hooks - should be trivial but
2689
2713
target.unlock()
2717
class InterBranch(InterObject):
2718
"""This class represents operations taking place between two branches.
2720
Its instances have methods like pull() and push() and contain
2721
references to the source and target repositories these operations
2722
can be carried out on.
2726
"""The available optimised InterBranch types."""
2729
def _get_branch_formats_to_test():
2730
"""Return a tuple with the Branch formats to use when testing."""
2731
raise NotImplementedError(self._get_branch_formats_to_test)
2733
def update_revisions(self, stop_revision=None, overwrite=False,
2735
"""Pull in new perfect-fit revisions.
2737
:param stop_revision: Updated until the given revision
2738
:param overwrite: Always set the branch pointer, rather than checking
2739
to see if it is a proper descendant.
2740
:param graph: A Graph object that can be used to query history
2741
information. This can be None.
2744
raise NotImplementedError(self.update_revisions)
2747
class GenericInterBranch(InterBranch):
2748
"""InterBranch implementation that uses public Branch functions.
2752
def _get_branch_formats_to_test():
2753
return BranchFormat._default_format, BranchFormat._default_format
2755
def update_revisions(self, stop_revision=None, overwrite=False,
2757
"""See InterBranch.update_revisions()."""
2758
self.source.lock_read()
2760
other_revno, other_last_revision = self.source.last_revision_info()
2761
stop_revno = None # unknown
2762
if stop_revision is None:
2763
stop_revision = other_last_revision
2764
if _mod_revision.is_null(stop_revision):
2765
# if there are no commits, we're done.
2767
stop_revno = other_revno
2769
# what's the current last revision, before we fetch [and change it
2771
last_rev = _mod_revision.ensure_null(self.target.last_revision())
2772
# we fetch here so that we don't process data twice in the common
2773
# case of having something to pull, and so that the check for
2774
# already merged can operate on the just fetched graph, which will
2775
# be cached in memory.
2776
self.target.fetch(self.source, stop_revision)
2777
# Check to see if one is an ancestor of the other
2780
graph = self.target.repository.get_graph()
2781
if self.target._check_if_descendant_or_diverged(
2782
stop_revision, last_rev, graph, self.source):
2783
# stop_revision is a descendant of last_rev, but we aren't
2784
# overwriting, so we're done.
2786
if stop_revno is None:
2788
graph = self.target.repository.get_graph()
2789
this_revno, this_last_revision = \
2790
self.target.last_revision_info()
2791
stop_revno = graph.find_distance_to_null(stop_revision,
2792
[(other_last_revision, other_revno),
2793
(this_last_revision, this_revno)])
2794
self.target.set_last_revision_info(stop_revno, stop_revision)
2796
self.source.unlock()
2799
def is_compatible(self, source, target):
2800
# GenericBranch uses the public API, so always compatible
2804
InterBranch.register_optimiser(GenericInterBranch)