669
670
raise errors.UnsupportedOperation(self.get_reference_info, self)
671
672
@needs_write_lock
672
def fetch(self, from_branch, last_revision=None):
673
def fetch(self, from_branch, last_revision=None, fetch_spec=None):
673
674
"""Copy revisions from from_branch into this branch.
675
676
:param from_branch: Where to copy from.
676
677
:param last_revision: What revision to stop at (None for at the end
679
:param fetch_spec: If specified, a SearchResult or
680
PendingAncestryResult that describes which revisions to copy. This
681
allows copying multiple heads at once. Mutually exclusive with
680
return InterBranch.get(from_branch, self).fetch(last_revision)
685
return InterBranch.get(from_branch, self).fetch(last_revision,
682
688
def get_bound_location(self):
683
689
"""Return the URL of the branch we are bound to.
695
701
def get_commit_builder(self, parents, config=None, timestamp=None,
696
702
timezone=None, committer=None, revprops=None,
697
revision_id=None, lossy=False):
698
704
"""Obtain a CommitBuilder for this branch.
700
706
:param parents: Revision ids of the parents of the new revision.
704
710
:param committer: Optional committer to set for commit.
705
711
:param revprops: Optional dictionary of revision properties.
706
712
:param revision_id: Optional revision id.
707
:param lossy: Whether to discard data that can not be natively
708
represented, when pushing to a foreign VCS
711
715
if config is None:
712
716
config = self.get_config()
714
718
return self.repository.get_commit_builder(self, parents, config,
715
timestamp, timezone, committer, revprops, revision_id,
719
timestamp, timezone, committer, revprops, revision_id)
718
721
def get_master_branch(self, possible_transports=None):
719
722
"""Return the branch we are bound to.
995
998
return (0, _mod_revision.NULL_REVISION)
1000
def update_revisions(self, other, stop_revision=None, overwrite=False,
1001
graph=None, fetch_tags=True):
1002
"""Pull in new perfect-fit revisions.
1004
:param other: Another Branch to pull from
1005
:param stop_revision: Updated until the given revision
1006
:param overwrite: Always set the branch pointer, rather than checking
1007
to see if it is a proper descendant.
1008
:param graph: A Graph object that can be used to query history
1009
information. This can be None.
1010
:param fetch_tags: Flag that specifies if tags from other should be
1014
return InterBranch.get(other, self).update_revisions(stop_revision,
1015
overwrite, graph, fetch_tags=fetch_tags)
997
1017
@deprecated_method(deprecated_in((2, 4, 0)))
998
1018
def import_last_revision_info(self, source_repo, revno, revid):
999
1019
"""Set the last revision info, importing from another repo if necessary.
1006
1026
self.repository.fetch(source_repo, revision_id=revid)
1007
1027
self.set_last_revision_info(revno, revid)
1009
def import_last_revision_info_and_tags(self, source, revno, revid,
1029
def import_last_revision_info_and_tags(self, source, revno, revid):
1011
1030
"""Set the last revision info, importing from another repo if necessary.
1013
1032
This is used by the bound branch code to upload a revision to
1017
1036
:param source: Source branch to optionally fetch from
1018
1037
:param revno: Revision number of the new tip
1019
1038
:param revid: Revision id of the new tip
1020
:param lossy: Whether to discard metadata that can not be
1021
natively represented
1022
:return: Tuple with the new revision number and revision id
1023
(should only be different from the arguments when lossy=True)
1025
1040
if not self.repository.has_same_location(source.repository):
1026
self.fetch(source, revid)
1042
tags_to_fetch = set(source.tags.get_reverse_tag_dict())
1043
except errors.TagsNotSupported:
1044
tags_to_fetch = set()
1045
fetch_spec = _mod_graph.NotInOtherForRevs(self.repository,
1046
source.repository, [revid],
1047
if_present_ids=tags_to_fetch).execute()
1048
self.repository.fetch(source.repository, fetch_spec=fetch_spec)
1027
1049
self.set_last_revision_info(revno, revid)
1028
return (revno, revid)
1030
1051
def revision_id_to_revno(self, revision_id):
1031
1052
"""Given a revision id, return its revno"""
1624
1645
for hook in hooks:
1648
def _initialize_helper(self, a_bzrdir, utf8_files, name=None,
1650
"""Initialize a branch in a bzrdir, with specified files
1652
:param a_bzrdir: The bzrdir to initialize the branch in
1653
:param utf8_files: The files to create as a list of
1654
(filename, content) tuples
1655
:param name: Name of colocated branch to create, if any
1656
:return: a branch in this format
1658
mutter('creating branch %r in %s', self, a_bzrdir.user_url)
1659
branch_transport = a_bzrdir.get_branch_transport(self, name=name)
1660
control_files = lockable_files.LockableFiles(branch_transport,
1661
'lock', lockdir.LockDir)
1662
control_files.create_lock()
1663
control_files.lock_write()
1665
utf8_files += [('format', self.get_format_string())]
1666
for (filename, content) in utf8_files:
1667
branch_transport.put_bytes(
1669
mode=a_bzrdir._get_file_mode())
1671
control_files.unlock()
1672
branch = self.open(a_bzrdir, name, _found=True,
1673
found_repository=repository)
1674
self._run_post_branch_init_hooks(a_bzrdir, name, branch)
1627
1677
def initialize(self, a_bzrdir, name=None, repository=None):
1628
1678
"""Create a branch of this format in a_bzrdir.
1960
2010
"""What class to instantiate on open calls."""
1961
2011
raise NotImplementedError(self._branch_class)
1963
def _initialize_helper(self, a_bzrdir, utf8_files, name=None,
1965
"""Initialize a branch in a bzrdir, with specified files
1967
:param a_bzrdir: The bzrdir to initialize the branch in
1968
:param utf8_files: The files to create as a list of
1969
(filename, content) tuples
1970
:param name: Name of colocated branch to create, if any
1971
:return: a branch in this format
1973
mutter('creating branch %r in %s', self, a_bzrdir.user_url)
1974
branch_transport = a_bzrdir.get_branch_transport(self, name=name)
1975
control_files = lockable_files.LockableFiles(branch_transport,
1976
'lock', lockdir.LockDir)
1977
control_files.create_lock()
1978
control_files.lock_write()
1980
utf8_files += [('format', self.get_format_string())]
1981
for (filename, content) in utf8_files:
1982
branch_transport.put_bytes(
1984
mode=a_bzrdir._get_file_mode())
1986
control_files.unlock()
1987
branch = self.open(a_bzrdir, name, _found=True,
1988
found_repository=repository)
1989
self._run_post_branch_init_hooks(a_bzrdir, name, branch)
1992
2013
def network_name(self):
1993
2014
"""A simple byte string uniquely identifying this format for RPC calls.
2128
2149
return self._initialize_helper(a_bzrdir, utf8_files, name, repository)
2152
super(BzrBranchFormat8, self).__init__()
2153
self._matchingbzrdir.repository_format = \
2154
RepositoryFormatKnitPack5RichRoot()
2130
2156
def make_tags(self, branch):
2131
2157
"""See bzrlib.branch.BranchFormat.make_tags()."""
2132
2158
return BasicTags(branch)
2140
2166
supports_reference_locations = True
2143
class BzrBranchFormat7(BranchFormatMetadir):
2169
class BzrBranchFormat7(BzrBranchFormat8):
2144
2170
"""Branch format with last-revision, tags, and a stacked location pointer.
2146
2172
The stacked location pointer is passed down to the repository and requires
2171
2197
def supports_set_append_revisions_only(self):
2174
def supports_stacking(self):
2177
def make_tags(self, branch):
2178
"""See bzrlib.branch.BranchFormat.make_tags()."""
2179
return BasicTags(branch)
2181
2200
supports_reference_locations = False
2482
2501
'revision-history', '\n'.join(history),
2483
2502
mode=self.bzrdir._get_file_mode())
2485
@deprecated_method(deprecated_in((2, 4, 0)))
2486
2505
def set_revision_history(self, rev_history):
2487
2506
"""See Branch.set_revision_history."""
2488
self._set_revision_history(rev_history)
2491
def _set_revision_history(self, rev_history):
2492
2507
if 'evil' in debug.debug_flags:
2493
2508
mutter_callsite(3, "set_revision_history scales with history.")
2494
2509
check_not_reserved_id = _mod_revision.check_not_reserved_id
2538
2553
except ValueError:
2539
2554
rev = self.repository.get_revision(revision_id)
2540
2555
new_history = rev.get_history(self.repository)[1:]
2541
destination._set_revision_history(new_history)
2556
destination.set_revision_history(new_history)
2543
2558
@needs_write_lock
2544
2559
def set_last_revision_info(self, revno, revision_id):
2552
2567
configured to check constraints on history, in which case this may not
2555
if not revision_id or not isinstance(revision_id, basestring):
2556
raise errors.InvalidRevisionId(revision_id=revision_id, branch=self)
2570
revision_id = _mod_revision.ensure_null(revision_id)
2557
2571
# this old format stores the full history, but this api doesn't
2558
2572
# provide it, so we must generate, and might as well check it's
2560
2574
history = self._lefthand_history(revision_id)
2561
2575
if len(history) != revno:
2562
2576
raise AssertionError('%d != %d' % (len(history), revno))
2563
self._set_revision_history(history)
2577
self.set_revision_history(history)
2565
2579
def _gen_revision_history(self):
2566
2580
history = self._transport.get_bytes('revision-history').split('\n')
2613
def _basic_push(self, target, overwrite, stop_revision):
2614
"""Basic implementation of push without bound branches or hooks.
2616
Must be called with source read locked and target write locked.
2618
result = BranchPushResult()
2619
result.source_branch = self
2620
result.target_branch = target
2621
result.old_revno, result.old_revid = target.last_revision_info()
2622
self.update_references(target)
2623
if result.old_revid != stop_revision:
2624
# We assume that during 'push' this repository is closer than
2626
graph = self.repository.get_graph(target.repository)
2627
target.update_revisions(self, stop_revision,
2628
overwrite=overwrite, graph=graph)
2629
if self._push_should_merge_tags():
2630
result.tag_conflicts = self.tags.merge_to(target.tags, overwrite)
2631
result.new_revno, result.new_revid = target.last_revision_info()
2599
2634
def get_stacked_on_url(self):
2600
2635
raise errors.UnstackableBranchFormat(self._format, self.user_url)
2769
2804
@needs_write_lock
2770
2805
def set_last_revision_info(self, revno, revision_id):
2771
if not revision_id or not isinstance(revision_id, basestring):
2772
raise errors.InvalidRevisionId(revision_id=revision_id, branch=self)
2806
revision_id = _mod_revision.ensure_null(revision_id)
2773
2807
old_revno, old_revid = self.last_revision_info()
2774
2808
if self._get_append_revisions_only():
2775
2809
self._check_history_violation(revision_id)
3251
3285
raise NotImplementedError(self.pull)
3253
3287
@needs_write_lock
3288
def update_revisions(self, stop_revision=None, overwrite=False,
3289
graph=None, fetch_tags=True):
3290
"""Pull in new perfect-fit revisions.
3292
:param stop_revision: Updated until the given revision
3293
:param overwrite: Always set the branch pointer, rather than checking
3294
to see if it is a proper descendant.
3295
:param graph: A Graph object that can be used to query history
3296
information. This can be None.
3297
:param fetch_tags: Flag that specifies if tags from source should be
3301
raise NotImplementedError(self.update_revisions)
3254
3304
def push(self, overwrite=False, stop_revision=None,
3255
3305
_override_hook_source_branch=None):
3256
3306
"""Mirror the source branch into the target branch.
3269
3319
raise NotImplementedError(self.copy_content_into)
3271
3321
@needs_write_lock
3272
def fetch(self, stop_revision=None):
3322
def fetch(self, stop_revision=None, fetch_spec=None):
3273
3323
"""Fetch revisions.
3275
3325
:param stop_revision: Last revision to fetch
3326
:param fetch_spec: Fetch spec.
3277
3328
raise NotImplementedError(self.fetch)
3316
3367
self.source.tags.merge_to(self.target.tags)
3318
3369
@needs_write_lock
3319
def fetch(self, stop_revision=None):
3370
def fetch(self, stop_revision=None, fetch_spec=None):
3371
if fetch_spec is not None and stop_revision is not None:
3372
raise AssertionError(
3373
"fetch_spec and last_revision are mutually exclusive.")
3320
3374
if self.target.base == self.source.base:
3322
3376
self.source.lock_read()
3324
fetch_spec_factory = fetch.FetchSpecFactory()
3325
fetch_spec_factory.source_branch = self.source
3326
fetch_spec_factory.source_branch_stop_revision_id = stop_revision
3327
fetch_spec_factory.source_repo = self.source.repository
3328
fetch_spec_factory.target_repo = self.target.repository
3329
fetch_spec_factory.target_repo_kind = fetch.TargetRepoKinds.PREEXISTING
3330
fetch_spec = fetch_spec_factory.make_fetch_spec()
3378
if stop_revision is None and fetch_spec is None:
3379
stop_revision = self.source.last_revision()
3380
stop_revision = _mod_revision.ensure_null(stop_revision)
3331
3381
return self.target.repository.fetch(self.source.repository,
3332
fetch_spec=fetch_spec)
3382
revision_id=stop_revision, fetch_spec=fetch_spec)
3334
3384
self.source.unlock()
3336
3386
@needs_write_lock
3337
def _update_revisions(self, stop_revision=None, overwrite=False,
3387
def update_revisions(self, stop_revision=None, overwrite=False,
3388
graph=None, fetch_tags=True):
3389
"""See InterBranch.update_revisions()."""
3339
3390
other_revno, other_last_revision = self.source.last_revision_info()
3340
3391
stop_revno = None # unknown
3341
3392
if stop_revision is None:
3352
3403
# case of having something to pull, and so that the check for
3353
3404
# already merged can operate on the just fetched graph, which will
3354
3405
# be cached in memory.
3355
self.fetch(stop_revision=stop_revision)
3407
fetch_spec_factory = fetch.FetchSpecFactory()
3408
fetch_spec_factory.source_branch = self.source
3409
fetch_spec_factory.source_branch_stop_revision_id = stop_revision
3410
fetch_spec_factory.source_repo = self.source.repository
3411
fetch_spec_factory.target_repo = self.target.repository
3412
fetch_spec_factory.target_repo_kind = fetch.TargetRepoKinds.PREEXISTING
3413
fetch_spec = fetch_spec_factory.make_fetch_spec()
3415
fetch_spec = _mod_graph.NotInOtherForRevs(self.target.repository,
3416
self.source.repository, revision_ids=[stop_revision]).execute()
3417
self.target.fetch(self.source, fetch_spec=fetch_spec)
3356
3418
# Check to see if one is an ancestor of the other
3357
3419
if not overwrite:
3358
3420
if graph is None:
3428
3490
self.source.unlock()
3430
def _basic_push(self, overwrite, stop_revision):
3431
"""Basic implementation of push without bound branches or hooks.
3433
Must be called with source read locked and target write locked.
3435
result = BranchPushResult()
3436
result.source_branch = self.source
3437
result.target_branch = self.target
3438
result.old_revno, result.old_revid = self.target.last_revision_info()
3439
self.source.update_references(self.target)
3440
if result.old_revid != stop_revision:
3441
# We assume that during 'push' this repository is closer than
3443
graph = self.source.repository.get_graph(self.target.repository)
3444
self._update_revisions(stop_revision, overwrite=overwrite,
3446
if self.source._push_should_merge_tags():
3447
result.tag_conflicts = self.source.tags.merge_to(self.target.tags,
3449
result.new_revno, result.new_revid = self.target.last_revision_info()
3452
3492
def _push_with_bound_branches(self, overwrite, stop_revision,
3453
3493
_override_hook_source_branch=None):
3454
3494
"""Push from source into target, and into target's master if any.
3469
3509
master_branch.lock_write()
3471
3511
# push into the master from the source branch.
3472
master_inter = InterBranch.get(self.source, master_branch)
3473
master_inter._basic_push(overwrite, stop_revision)
3474
# and push into the target branch from the source. Note that
3475
# we push from the source branch again, because it's considered
3476
# the highest bandwidth repository.
3477
result = self._basic_push(overwrite, stop_revision)
3512
self.source._basic_push(master_branch, overwrite, stop_revision)
3513
# and push into the target branch from the source. Note that we
3514
# push from the source branch again, because it's considered the
3515
# highest bandwidth repository.
3516
result = self.source._basic_push(self.target, overwrite,
3478
3518
result.master_branch = master_branch
3479
3519
result.local_branch = self.target
3483
3523
master_branch.unlock()
3485
3525
# no master branch
3486
result = self._basic_push(overwrite, stop_revision)
3526
result = self.source._basic_push(self.target, overwrite,
3487
3528
# TODO: Why set master_branch and local_branch if there's no
3488
3529
# binding? Maybe cleaner to just leave them unset? -- mbp
3532
3573
# -- JRV20090506
3533
3574
result.old_revno, result.old_revid = \
3534
3575
self.target.last_revision_info()
3535
self._update_revisions(stop_revision, overwrite=overwrite,
3576
self.target.update_revisions(self.source, stop_revision,
3577
overwrite=overwrite, graph=graph)
3537
3578
# TODO: The old revid should be specified when merging tags,
3538
3579
# so a tags implementation that versions tags can only
3539
3580
# pull in the most recent changes. -- JRV20090506