18
18
from cStringIO import StringIO
21
20
from bzrlib.lazy_import import lazy_import
22
21
lazy_import(globals(), """
23
from itertools import chain
24
23
from bzrlib import (
27
27
config as _mod_config,
36
36
revision as _mod_revision,
44
from bzrlib.config import BranchConfig, TransportConfig
45
from bzrlib.tag import (
43
from bzrlib.i18n import gettext, ngettext
51
46
from bzrlib import (
67
62
from bzrlib.trace import mutter, mutter_callsite, note, is_quiet
70
BZR_BRANCH_FORMAT_4 = "Bazaar-NG branch, format 0.0.4\n"
71
BZR_BRANCH_FORMAT_5 = "Bazaar-NG branch, format 5\n"
72
BZR_BRANCH_FORMAT_6 = "Bazaar Branch Format 6 (bzr 0.15)\n"
75
65
class Branch(controldir.ControlComponent):
76
66
"""Branch holding a history of revisions.
224
214
:return: A bzrlib.config.BranchConfig.
226
return BranchConfig(self)
216
return _mod_config.BranchConfig(self)
218
def get_config_stack(self):
219
"""Get a bzrlib.config.BranchStack for this Branch.
221
This can then be used to get and set configuration options for the
224
:return: A bzrlib.config.BranchStack.
226
return _mod_config.BranchStack(self)
228
228
def _get_config(self):
229
229
"""Get the concrete config for just the config in this branch.
456
456
after. If None, the rest of history is included.
457
457
:param stop_rule: if stop_revision_id is not None, the precise rule
458
458
to use for termination:
459
460
* 'exclude' - leave the stop revision out of the result (default)
460
461
* 'include' - the stop revision is the last item in the result
461
462
* 'with-merges' - include the stop revision and all of its
463
464
* 'with-merges-without-common-ancestry' - filter out revisions
464
465
that are in both ancestries
465
466
:param direction: either 'reverse' or 'forward':
466
468
* reverse means return the start_revision_id first, i.e.
467
469
start at the most recent revision and go backwards in history
468
470
* forward returns tuples in the opposite order to reverse.
512
514
rev_iter = iter(merge_sorted_revisions)
513
515
if start_revision_id is not None:
514
516
for node in rev_iter:
515
rev_id = node.key[-1]
516
518
if rev_id != start_revision_id:
519
521
# The decision to include the start or not
520
522
# depends on the stop_rule if a stop is provided
521
523
# so pop this node back into the iterator
522
rev_iter = chain(iter([node]), rev_iter)
524
rev_iter = itertools.chain(iter([node]), rev_iter)
524
526
if stop_revision_id is None:
525
527
# Yield everything
526
528
for node in rev_iter:
527
rev_id = node.key[-1]
528
530
yield (rev_id, node.merge_depth, node.revno,
529
531
node.end_of_merge)
530
532
elif stop_rule == 'exclude':
531
533
for node in rev_iter:
532
rev_id = node.key[-1]
533
535
if rev_id == stop_revision_id:
535
537
yield (rev_id, node.merge_depth, node.revno,
536
538
node.end_of_merge)
537
539
elif stop_rule == 'include':
538
540
for node in rev_iter:
539
rev_id = node.key[-1]
540
542
yield (rev_id, node.merge_depth, node.revno,
541
543
node.end_of_merge)
542
544
if rev_id == stop_revision_id:
548
550
ancestors = graph.find_unique_ancestors(start_revision_id,
549
551
[stop_revision_id])
550
552
for node in rev_iter:
551
rev_id = node.key[-1]
552
554
if rev_id not in ancestors:
554
556
yield (rev_id, node.merge_depth, node.revno,
651
653
raise errors.UpgradeRequired(self.user_url)
655
def get_append_revisions_only(self):
656
"""Whether it is only possible to append revisions to the history.
658
if not self._format.supports_set_append_revisions_only():
660
return self.get_config(
661
).get_user_option_as_bool('append_revisions_only')
653
663
def set_append_revisions_only(self, enabled):
654
664
if not self._format.supports_set_append_revisions_only():
655
665
raise errors.UpgradeRequired(self.user_url)
669
679
raise errors.UnsupportedOperation(self.get_reference_info, self)
671
681
@needs_write_lock
672
def fetch(self, from_branch, last_revision=None):
682
def fetch(self, from_branch, last_revision=None, limit=None):
673
683
"""Copy revisions from from_branch into this branch.
675
685
:param from_branch: Where to copy from.
676
686
:param last_revision: What revision to stop at (None for at the end
688
:param limit: Optional rough limit of revisions to fetch
680
return InterBranch.get(from_branch, self).fetch(last_revision)
691
return InterBranch.get(from_branch, self).fetch(last_revision, limit=limit)
682
693
def get_bound_location(self):
683
694
"""Return the URL of the branch we are bound to.
776
787
configured to check constraints on history, in which case this may not
779
raise NotImplementedError(self.last_revision_info)
790
raise NotImplementedError(self.set_last_revision_info)
781
792
@needs_write_lock
782
793
def generate_revision_history(self, revision_id, last_rev=None,
783
794
other_branch=None):
784
795
"""See Branch.generate_revision_history"""
785
# FIXME: This shouldn't have to fetch the entire history
786
history = self._lefthand_history(revision_id, last_rev, other_branch)
796
graph = self.repository.get_graph()
797
(last_revno, last_revid) = self.last_revision_info()
798
known_revision_ids = [
799
(last_revid, last_revno),
800
(_mod_revision.NULL_REVISION, 0),
802
if last_rev is not None:
803
if not graph.is_ancestor(last_rev, revision_id):
804
# our previous tip is not merged into stop_revision
805
raise errors.DivergedBranches(self, other_branch)
806
revno = graph.find_distance_to_null(revision_id, known_revision_ids)
788
807
self.set_last_revision_info(revno, revision_id)
789
self._cache_revision_history(history)
791
809
@needs_write_lock
792
810
def set_parent(self, url):
842
860
pb = ui.ui_factory.nested_progress_bar()
844
pb.update("Unstacking")
862
pb.update(gettext("Unstacking"))
845
863
# The basic approach here is to fetch the tip of the branch,
846
864
# including all available ghosts, from the existing stacked
847
865
# repository into a new repository object without the fallbacks.
925
943
:seealso: Branch._get_tags_bytes.
927
return _run_with_write_locked_target(self, self._set_tags_bytes_locked,
945
op = cleanup.OperationWithCleanups(self._set_tags_bytes_locked)
946
op.add_cleanup(self.lock_write().unlock)
947
return op.run_simple(bytes)
930
949
def _set_tags_bytes_locked(self, bytes):
931
950
self._tags_bytes = bytes
1098
1117
stop_revision=stop_revision,
1099
1118
possible_transports=possible_transports, *args, **kwargs)
1101
def push(self, target, overwrite=False, stop_revision=None, *args,
1120
def push(self, target, overwrite=False, stop_revision=None, lossy=False,
1103
1122
"""Mirror this branch into target.
1105
1124
This branch is considered to be 'local', having low latency.
1107
1126
return InterBranch.get(self, target).push(overwrite, stop_revision,
1110
def lossy_push(self, target, stop_revision=None):
1111
"""Push deltas into another branch.
1113
:note: This does not, like push, retain the revision ids from
1114
the source branch and will, rather than adding bzr-specific
1115
metadata, push only those semantics of the revision that can be
1116
natively represented by this branch' VCS.
1118
:param target: Target branch
1119
:param stop_revision: Revision to push, defaults to last revision.
1120
:return: BranchPushResult with an extra member revidmap:
1121
A dictionary mapping revision ids from the target branch
1122
to new revision ids in the target branch, for each
1123
revision that was pushed.
1125
inter = InterBranch.get(self, target)
1126
lossy_push = getattr(inter, "lossy_push", None)
1127
if lossy_push is None:
1128
raise errors.LossyPushToSameVCS(self, target)
1129
return lossy_push(stop_revision)
1127
lossy, *args, **kwargs)
1131
1129
def basis_tree(self):
1132
1130
"""Return `Tree` object for last revision."""
1305
1303
if repository_policy is not None:
1306
1304
repository_policy.configure_branch(result)
1307
1305
self.copy_content_into(result, revision_id=revision_id)
1308
master_branch = self.get_master_branch()
1309
if master_branch is None:
1306
master_url = self.get_bound_location()
1307
if master_url is None:
1310
1308
result.set_parent(self.bzrdir.root_transport.base)
1312
result.set_parent(master_branch.bzrdir.root_transport.base)
1310
result.set_parent(master_url)
1314
1312
result.unlock()
1393
1391
# specific check.
1396
def _get_checkout_format(self):
1394
def _get_checkout_format(self, lightweight=False):
1397
1395
"""Return the most suitable metadir for a checkout of this branch.
1398
1396
Weaves are used if this branch's repository uses weaves.
1434
1432
:param to_location: The url to produce the checkout at
1435
1433
:param revision_id: The revision to check out
1436
1434
:param lightweight: If True, produce a lightweight checkout, otherwise,
1437
produce a bound branch (heavyweight checkout)
1435
produce a bound branch (heavyweight checkout)
1438
1436
:param accelerator_tree: A tree which can be used for retrieving file
1439
1437
contents more quickly than the revision tree, i.e. a workingtree.
1440
1438
The revision tree will be used for cases where accelerator_tree's
1446
1444
t = transport.get_transport(to_location)
1447
1445
t.ensure_base()
1446
format = self._get_checkout_format(lightweight=lightweight)
1448
1447
if lightweight:
1449
format = self._get_checkout_format()
1450
1448
checkout = format.initialize_on_transport(t)
1451
1449
from_branch = BranchReferenceFormat().initialize(checkout,
1452
1450
target_branch=self)
1454
format = self._get_checkout_format()
1455
1452
checkout_branch = bzrdir.BzrDir.create_branch_convenience(
1456
1453
to_location, force_new_tree=False, format=format)
1457
1454
checkout = checkout_branch.bzrdir
1487
1484
def reference_parent(self, file_id, path, possible_transports=None):
1488
1485
"""Return the parent branch for a tree-reference file_id
1489
1487
:param file_id: The file_id of the tree reference
1490
1488
:param path: The path of the file_id in the tree
1491
1489
:return: A branch associated with the file_id
1556
1554
# For bzr native formats must_fetch is just the tip, and if_present_fetch
1557
1555
# are the tags.
1558
1556
must_fetch = set([self.last_revision()])
1560
if_present_fetch = set(self.tags.get_reverse_tag_dict())
1561
except errors.TagsNotSupported:
1562
if_present_fetch = set()
1557
if_present_fetch = set()
1558
c = self.get_config()
1559
include_tags = c.get_user_option_as_bool('branch.fetch_tags',
1563
if_present_fetch = set(self.tags.get_reverse_tag_dict())
1564
except errors.TagsNotSupported:
1563
1566
must_fetch.discard(_mod_revision.NULL_REVISION)
1564
1567
if_present_fetch.discard(_mod_revision.NULL_REVISION)
1565
1568
return must_fetch, if_present_fetch
1662
1663
for hook in hooks:
1665
def initialize(self, a_bzrdir, name=None, repository=None):
1666
def initialize(self, a_bzrdir, name=None, repository=None,
1667
append_revisions_only=None):
1666
1668
"""Create a branch of this format in a_bzrdir.
1668
1670
:param name: Name of the colocated branch to create.
1690
1692
Note that it is normal for branch to be a RemoteBranch when using tags
1691
1693
on a RemoteBranch.
1693
return DisabledTags(branch)
1695
return _mod_tag.DisabledTags(branch)
1695
1697
def network_name(self):
1696
1698
"""A simple byte string uniquely identifying this format for RPC calls.
1754
1756
"""True if this format supports tags stored in the branch"""
1755
1757
return False # by default
1759
def tags_are_versioned(self):
1760
"""Whether the tag container for this branch versions tags."""
1763
def supports_tags_referencing_ghosts(self):
1764
"""True if tags can reference ghost revisions."""
1758
1768
class MetaDirBranchFormatFactory(registry._LazyObjectGetter):
1759
1769
"""A factory for a BranchFormat object, permitting simple lazy registration.
1883
1893
class ChangeBranchTipParams(object):
1884
"""Object holding parameters passed to *_change_branch_tip hooks.
1894
"""Object holding parameters passed to `*_change_branch_tip` hooks.
1886
1896
There are 5 fields that hooks may wish to access:
1921
1931
class BranchInitHookParams(object):
1922
"""Object holding parameters passed to *_branch_init hooks.
1932
"""Object holding parameters passed to `*_branch_init` hooks.
1924
1934
There are 4 fields that hooks may wish to access:
1998
2008
"""What class to instantiate on open calls."""
1999
2009
raise NotImplementedError(self._branch_class)
2011
def _get_initial_config(self, append_revisions_only=None):
2012
if append_revisions_only:
2013
return "append_revisions_only = True\n"
2015
# Avoid writing anything if append_revisions_only is disabled,
2016
# as that is the default.
2001
2019
def _initialize_helper(self, a_bzrdir, utf8_files, name=None,
2002
2020
repository=None):
2003
2021
"""Initialize a branch in a bzrdir, with specified files
2093
2111
"""See BranchFormat.get_format_description()."""
2094
2112
return "Branch format 5"
2096
def initialize(self, a_bzrdir, name=None, repository=None):
2114
def initialize(self, a_bzrdir, name=None, repository=None,
2115
append_revisions_only=None):
2097
2116
"""Create a branch of this format in a_bzrdir."""
2117
if append_revisions_only:
2118
raise errors.UpgradeRequired(a_bzrdir.user_url)
2098
2119
utf8_files = [('revision-history', ''),
2099
2120
('branch-name', ''),
2126
2147
"""See BranchFormat.get_format_description()."""
2127
2148
return "Branch format 6"
2129
def initialize(self, a_bzrdir, name=None, repository=None):
2150
def initialize(self, a_bzrdir, name=None, repository=None,
2151
append_revisions_only=None):
2130
2152
"""Create a branch of this format in a_bzrdir."""
2131
2153
utf8_files = [('last-revision', '0 null:\n'),
2132
('branch.conf', ''),
2155
self._get_initial_config(append_revisions_only)),
2135
2158
return self._initialize_helper(a_bzrdir, utf8_files, name, repository)
2137
2160
def make_tags(self, branch):
2138
2161
"""See bzrlib.branch.BranchFormat.make_tags()."""
2139
return BasicTags(branch)
2162
return _mod_tag.BasicTags(branch)
2141
2164
def supports_set_append_revisions_only(self):
2156
2179
"""See BranchFormat.get_format_description()."""
2157
2180
return "Branch format 8"
2159
def initialize(self, a_bzrdir, name=None, repository=None):
2182
def initialize(self, a_bzrdir, name=None, repository=None,
2183
append_revisions_only=None):
2160
2184
"""Create a branch of this format in a_bzrdir."""
2161
2185
utf8_files = [('last-revision', '0 null:\n'),
2162
('branch.conf', ''),
2187
self._get_initial_config(append_revisions_only)),
2164
2189
('references', '')
2168
2193
def make_tags(self, branch):
2169
2194
"""See bzrlib.branch.BranchFormat.make_tags()."""
2170
return BasicTags(branch)
2195
return _mod_tag.BasicTags(branch)
2172
2197
def supports_set_append_revisions_only(self):
2187
2212
This format was introduced in bzr 1.6.
2190
def initialize(self, a_bzrdir, name=None, repository=None):
2215
def initialize(self, a_bzrdir, name=None, repository=None,
2216
append_revisions_only=None):
2191
2217
"""Create a branch of this format in a_bzrdir."""
2192
2218
utf8_files = [('last-revision', '0 null:\n'),
2193
('branch.conf', ''),
2220
self._get_initial_config(append_revisions_only)),
2196
2223
return self._initialize_helper(a_bzrdir, utf8_files, name, repository)
2215
2242
def make_tags(self, branch):
2216
2243
"""See bzrlib.branch.BranchFormat.make_tags()."""
2217
return BasicTags(branch)
2244
return _mod_tag.BasicTags(branch)
2219
2246
supports_reference_locations = False
2249
2276
location = transport.put_bytes('location', to_branch.base)
2251
2278
def initialize(self, a_bzrdir, name=None, target_branch=None,
2279
repository=None, append_revisions_only=None):
2253
2280
"""Create a branch of this format in a_bzrdir."""
2254
2281
if target_branch is None:
2255
2282
# this format does not implement branch itself, thus the implicit
2256
2283
# creation contract must see it as uninitializable
2257
2284
raise errors.UninitializableFormat(self)
2258
2285
mutter('creating branch reference in %s', a_bzrdir.user_url)
2286
if a_bzrdir._format.fixed_components:
2287
raise errors.IncompatibleFormat(self, a_bzrdir._format)
2259
2288
branch_transport = a_bzrdir.get_branch_transport(self, name=name)
2260
2289
branch_transport.put_bytes('location',
2261
2290
target_branch.bzrdir.user_url)
2430
2459
base = property(_get_base, doc="The URL for the root of this branch.")
2432
2461
def _get_config(self):
2433
return TransportConfig(self._transport, 'branch.conf')
2462
return _mod_config.TransportConfig(self._transport, 'branch.conf')
2435
2464
def is_locked(self):
2436
2465
return self.control_files.is_locked()
2517
2546
raise errors.InvalidRevisionId(revision_id=revision_id, branch=self)
2518
2547
revision_id = _mod_revision.ensure_null(revision_id)
2519
2548
old_revno, old_revid = self.last_revision_info()
2520
if self._get_append_revisions_only():
2549
if self.get_append_revisions_only():
2521
2550
self._check_history_violation(revision_id)
2522
2551
self._run_pre_change_branch_tip_hooks(revno, revision_id)
2523
2552
self._write_last_revision_info(revno, revision_id)
2808
2837
self._reference_info = None
2810
2839
def _check_history_violation(self, revision_id):
2811
last_revision = _mod_revision.ensure_null(self.last_revision())
2840
current_revid = self.last_revision()
2841
last_revision = _mod_revision.ensure_null(current_revid)
2812
2842
if _mod_revision.is_null(last_revision):
2814
if last_revision not in self._lefthand_history(revision_id):
2815
raise errors.AppendRevisionsOnlyViolation(self.user_url)
2844
graph = self.repository.get_graph()
2845
for lh_ancestor in graph.iter_lefthand_ancestry(revision_id):
2846
if lh_ancestor == current_revid:
2848
raise errors.AppendRevisionsOnlyViolation(self.user_url)
2817
2850
def _gen_revision_history(self):
2818
2851
"""Generate the revision history from last revision
2949
2982
# you can always ask for the URL; but you might not be able to use it
2950
2983
# if the repo can't support stacking.
2951
2984
## self._check_stackable_repo()
2952
stacked_url = self._get_config_location('stacked_on_location')
2985
# stacked_on_location is only ever defined in branch.conf, so don't
2986
# waste effort reading the whole stack of config files.
2987
config = self.get_config()._get_branch_data_config()
2988
stacked_url = self._get_config_location('stacked_on_location',
2953
2990
if stacked_url is None:
2954
2991
raise errors.NotStacked(self)
2955
2992
return stacked_url
2957
def _get_append_revisions_only(self):
2958
return self.get_config(
2959
).get_user_option_as_bool('append_revisions_only')
2961
2994
@needs_read_lock
2962
2995
def get_rev_id(self, revno, history=None):
2963
2996
"""Find the revision id of the specified revno."""
3049
3082
:ivar local_branch: target branch if there is a Master, else None
3050
3083
:ivar target_branch: Target/destination branch object. (write locked)
3051
3084
:ivar tag_conflicts: A list of tag conflicts, see BasicTags.merge_to
3085
:ivar tag_updates: A dict with new tags, see BasicTags.merge_to
3054
3088
@deprecated_method(deprecated_in((2, 3, 0)))
3060
3094
return self.new_revno - self.old_revno
3062
3096
def report(self, to_file):
3097
tag_conflicts = getattr(self, "tag_conflicts", None)
3098
tag_updates = getattr(self, "tag_updates", None)
3063
3099
if not is_quiet():
3064
if self.old_revid == self.new_revid:
3065
to_file.write('No revisions to pull.\n')
3100
if self.old_revid != self.new_revid:
3067
3101
to_file.write('Now on revision %d.\n' % self.new_revno)
3103
to_file.write('%d tag(s) updated.\n' % len(tag_updates))
3104
if self.old_revid == self.new_revid and not tag_updates:
3105
if not tag_conflicts:
3106
to_file.write('No revisions or tags to pull.\n')
3108
to_file.write('No revisions to pull.\n')
3068
3109
self._show_tag_conficts(to_file)
3096
3137
return self.new_revno - self.old_revno
3098
3139
def report(self, to_file):
3099
"""Write a human-readable description of the result."""
3100
if self.old_revid == self.new_revid:
3101
note('No new revisions to push.')
3103
note('Pushed up to revision %d.' % self.new_revno)
3140
# TODO: This function gets passed a to_file, but then
3141
# ignores it and calls note() instead. This is also
3142
# inconsistent with PullResult(), which writes to stdout.
3143
# -- JRV20110901, bug #838853
3144
tag_conflicts = getattr(self, "tag_conflicts", None)
3145
tag_updates = getattr(self, "tag_updates", None)
3147
if self.old_revid != self.new_revid:
3148
note(gettext('Pushed up to revision %d.') % self.new_revno)
3150
note(ngettext('%d tag updated.', '%d tags updated.', len(tag_updates)) % len(tag_updates))
3151
if self.old_revid == self.new_revid and not tag_updates:
3152
if not tag_conflicts:
3153
note(gettext('No new revisions or tags to push.'))
3155
note(gettext('No new revisions to push.'))
3104
3156
self._show_tag_conficts(to_file)
3120
3172
:param verbose: Requests more detailed display of what was checked,
3123
note('checked branch %s format %s', self.branch.user_url,
3124
self.branch._format)
3175
note(gettext('checked branch {0} format {1}').format(
3176
self.branch.user_url, self.branch._format))
3125
3177
for error in self.errors:
3126
note('found error:%s', error)
3178
note(gettext('found error:%s'), error)
3129
3181
class Converter5to6(object):
3170
3222
class Converter7to8(object):
3171
"""Perform an in-place upgrade of format 6 to format 7"""
3223
"""Perform an in-place upgrade of format 7 to format 8"""
3173
3225
def convert(self, branch):
3174
3226
format = BzrBranchFormat8()
3177
3229
branch._transport.put_bytes('format', format.get_format_string())
3180
def _run_with_write_locked_target(target, callable, *args, **kwargs):
3181
"""Run ``callable(*args, **kwargs)``, write-locking target for the
3184
_run_with_write_locked_target will attempt to release the lock it acquires.
3186
If an exception is raised by callable, then that exception *will* be
3187
propagated, even if the unlock attempt raises its own error. Thus
3188
_run_with_write_locked_target should be preferred to simply doing::
3192
return callable(*args, **kwargs)
3197
# This is very similar to bzrlib.decorators.needs_write_lock. Perhaps they
3198
# should share code?
3201
result = callable(*args, **kwargs)
3203
exc_info = sys.exc_info()
3207
raise exc_info[0], exc_info[1], exc_info[2]
3213
3232
class InterBranch(InterObject):
3214
3233
"""This class represents operations taking place between two branches.
3243
3262
raise NotImplementedError(self.pull)
3245
3264
@needs_write_lock
3246
def push(self, overwrite=False, stop_revision=None,
3265
def push(self, overwrite=False, stop_revision=None, lossy=False,
3247
3266
_override_hook_source_branch=None):
3248
3267
"""Mirror the source branch into the target branch.
3261
3280
raise NotImplementedError(self.copy_content_into)
3263
3282
@needs_write_lock
3264
def fetch(self, stop_revision=None):
3283
def fetch(self, stop_revision=None, limit=None):
3265
3284
"""Fetch revisions.
3267
3286
:param stop_revision: Last revision to fetch
3287
:param limit: Optional rough limit of revisions to fetch
3269
3289
raise NotImplementedError(self.fetch)
3308
3328
self.source.tags.merge_to(self.target.tags)
3310
3330
@needs_write_lock
3311
def fetch(self, stop_revision=None):
3331
def fetch(self, stop_revision=None, limit=None):
3312
3332
if self.target.base == self.source.base:
3314
3334
self.source.lock_read()
3319
3339
fetch_spec_factory.source_repo = self.source.repository
3320
3340
fetch_spec_factory.target_repo = self.target.repository
3321
3341
fetch_spec_factory.target_repo_kind = fetch.TargetRepoKinds.PREEXISTING
3342
fetch_spec_factory.limit = limit
3322
3343
fetch_spec = fetch_spec_factory.make_fetch_spec()
3323
3344
return self.target.repository.fetch(self.source.repository,
3324
3345
fetch_spec=fetch_spec)
3378
3399
if local and not bound_location:
3379
3400
raise errors.LocalRequiresBoundBranch()
3380
3401
master_branch = None
3381
source_is_master = (self.source.user_url == bound_location)
3402
source_is_master = False
3404
# bound_location comes from a config file, some care has to be
3405
# taken to relate it to source.user_url
3406
normalized = urlutils.normalize_url(bound_location)
3408
relpath = self.source.user_transport.relpath(normalized)
3409
source_is_master = (relpath == '')
3410
except (errors.PathNotChild, errors.InvalidURL):
3411
source_is_master = False
3382
3412
if not local and bound_location and not source_is_master:
3383
3413
# not pulling from master, so we need to update master.
3384
3414
master_branch = self.target.get_master_branch(possible_transports)
3397
3427
if master_branch:
3398
3428
master_branch.unlock()
3400
def push(self, overwrite=False, stop_revision=None,
3430
def push(self, overwrite=False, stop_revision=None, lossy=False,
3401
3431
_override_hook_source_branch=None):
3402
3432
"""See InterBranch.push.
3404
3434
This is the basic concrete implementation of push()
3406
:param _override_hook_source_branch: If specified, run
3407
the hooks passing this Branch as the source, rather than self.
3408
This is for use of RemoteBranch, where push is delegated to the
3409
underlying vfs-based Branch.
3436
:param _override_hook_source_branch: If specified, run the hooks
3437
passing this Branch as the source, rather than self. This is for
3438
use of RemoteBranch, where push is delegated to the underlying
3442
raise errors.LossyPushToSameVCS(self.source, self.target)
3411
3443
# TODO: Public option to disable running hooks - should be trivial but
3413
self.source.lock_read()
3415
return _run_with_write_locked_target(
3416
self.target, self._push_with_bound_branches, overwrite,
3418
_override_hook_source_branch=_override_hook_source_branch)
3420
self.source.unlock()
3446
op = cleanup.OperationWithCleanups(self._push_with_bound_branches)
3447
op.add_cleanup(self.source.lock_read().unlock)
3448
op.add_cleanup(self.target.lock_write().unlock)
3449
return op.run(overwrite, stop_revision,
3450
_override_hook_source_branch=_override_hook_source_branch)
3422
3452
def _basic_push(self, overwrite, stop_revision):
3423
3453
"""Basic implementation of push without bound branches or hooks.
3436
3466
self._update_revisions(stop_revision, overwrite=overwrite,
3438
3468
if self.source._push_should_merge_tags():
3439
result.tag_conflicts = self.source.tags.merge_to(self.target.tags,
3469
result.tag_updates, result.tag_conflicts = (
3470
self.source.tags.merge_to(self.target.tags, overwrite))
3441
3471
result.new_revno, result.new_revid = self.target.last_revision_info()
3444
def _push_with_bound_branches(self, overwrite, stop_revision,
3474
def _push_with_bound_branches(self, operation, overwrite, stop_revision,
3445
3475
_override_hook_source_branch=None):
3446
3476
"""Push from source into target, and into target's master if any.
3459
3489
# be bound to itself? -- mbp 20070507
3460
3490
master_branch = self.target.get_master_branch()
3461
3491
master_branch.lock_write()
3463
# push into the master from the source branch.
3464
master_inter = InterBranch.get(self.source, master_branch)
3465
master_inter._basic_push(overwrite, stop_revision)
3466
# and push into the target branch from the source. Note that
3467
# we push from the source branch again, because it's considered
3468
# the highest bandwidth repository.
3469
result = self._basic_push(overwrite, stop_revision)
3470
result.master_branch = master_branch
3471
result.local_branch = self.target
3475
master_branch.unlock()
3492
operation.add_cleanup(master_branch.unlock)
3493
# push into the master from the source branch.
3494
master_inter = InterBranch.get(self.source, master_branch)
3495
master_inter._basic_push(overwrite, stop_revision)
3496
# and push into the target branch from the source. Note that
3497
# we push from the source branch again, because it's considered
3498
# the highest bandwidth repository.
3499
result = self._basic_push(overwrite, stop_revision)
3500
result.master_branch = master_branch
3501
result.local_branch = self.target
3503
master_branch = None
3477
3504
# no master branch
3478
3505
result = self._basic_push(overwrite, stop_revision)
3479
3506
# TODO: Why set master_branch and local_branch if there's no
3482
3509
result.master_branch = self.target
3483
3510
result.local_branch = None
3487
3514
def _pull(self, overwrite=False, stop_revision=None,
3488
3515
possible_transports=None, _hook_master=None, run_hooks=True,
3529
3556
# TODO: The old revid should be specified when merging tags,
3530
3557
# so a tags implementation that versions tags can only
3531
3558
# pull in the most recent changes. -- JRV20090506
3532
result.tag_conflicts = self.source.tags.merge_to(self.target.tags,
3533
overwrite, ignore_master=not merge_tags_to_master)
3559
result.tag_updates, result.tag_conflicts = (
3560
self.source.tags.merge_to(self.target.tags, overwrite,
3561
ignore_master=not merge_tags_to_master))
3534
3562
result.new_revno, result.new_revid = self.target.last_revision_info()
3535
3563
if _hook_master:
3536
3564
result.master_branch = _hook_master