499
498
def add_inventory(self, revision_id, inv, parents):
500
499
"""Add the inventory inv to the repository as revision_id.
502
501
:param parents: The revision ids of the parents that revision_id
503
502
is known to have and are in the repository already.
505
returns the sha1 of the serialized inventory.
504
:returns: The validator(which is a sha1 digest, though what is sha'd is
505
repository format specific) of the serialized inventory.
507
507
assert self.is_in_write_group()
508
508
_mod_revision.check_not_reserved_id(revision_id)
525
525
return inv_vf.add_lines(revision_id, final_parents, lines,
526
526
check_content=check_content)[0]
529
528
def add_revision(self, revision_id, rev, inv=None, config=None):
530
529
"""Add rev to the revision store as revision_id.
766
765
result['size'] = t
768
def find_branches(self, using=False):
769
"""Find branches underneath this repository.
771
This will include branches inside other branches.
773
:param using: If True, list only branches using this repository.
775
if using and not self.is_shared():
777
return [self.bzrdir.open_branch()]
778
except errors.NotBranchError:
780
class Evaluator(object):
783
self.first_call = True
785
def __call__(self, bzrdir):
786
# On the first call, the parameter is always the bzrdir
787
# containing the current repo.
788
if not self.first_call:
790
repository = bzrdir.open_repository()
791
except errors.NoRepositoryPresent:
794
return False, (None, repository)
795
self.first_call = False
797
value = (bzrdir.open_branch(), None)
798
except errors.NotBranchError:
803
for branch, repository in bzrdir.BzrDir.find_bzrdirs(
804
self.bzrdir.root_transport, evaluate=Evaluator()):
805
if branch is not None:
806
branches.append(branch)
807
if not using and repository is not None:
808
branches.extend(repository.find_branches())
769
811
def get_data_stream(self, revision_ids):
770
812
raise NotImplementedError(self.get_data_stream)
814
def get_data_stream_for_search(self, search_result):
815
"""Get a data stream that can be inserted to a repository.
817
:param search_result: A bzrlib.graph.SearchResult selecting the
819
:return: A data stream that can be inserted into a repository using
822
raise NotImplementedError(self.get_data_stream_for_search)
772
824
def insert_data_stream(self, stream):
773
825
"""XXX What does this really do?
789
841
knit = self._revision_store.get_signature_file(
790
842
self.get_transaction())
792
raise RepositoryDataStreamError(
844
raise errors.RepositoryDataStreamError(
793
845
"Unrecognised data stream key '%s'" % (item_key,))
794
846
decoded_list = bencode.bdecode(bytes)
795
847
format = decoded_list.pop(0)
798
850
for version, options, parents, some_bytes in decoded_list:
799
851
data_list.append((version, options, len(some_bytes), parents))
800
852
knit_bytes += some_bytes
853
buffer = StringIO(knit_bytes)
854
def reader_func(count):
858
return buffer.read(count)
801
859
knit.insert_data_stream(
802
(format, data_list, StringIO(knit_bytes).read))
860
(format, data_list, reader_func))
863
def search_missing_revision_ids(self, other, revision_id=None, find_ghosts=True):
864
"""Return the revision ids that other has that this does not.
866
These are returned in topological order.
868
revision_id: only return revision ids included by revision_id.
870
return InterRepository.get(other, self).search_missing_revision_ids(
871
revision_id, find_ghosts)
873
@deprecated_method(symbol_versioning.one_two)
805
875
def missing_revision_ids(self, other, revision_id=None, find_ghosts=True):
806
876
"""Return the revision ids that other has that this does not.
810
880
revision_id: only return revision ids included by revision_id.
812
return InterRepository.get(other, self).missing_revision_ids(
813
revision_id, find_ghosts)
882
keys = self.search_missing_revision_ids(
883
other, revision_id, find_ghosts).get_keys()
886
parents = other.get_graph().get_parent_map(keys)
889
return tsort.topo_sort(parents)
976
1052
@needs_read_lock
977
1053
def has_revision(self, revision_id):
978
1054
"""True if this repository has a copy of the revision."""
979
if 'evil' in debug.debug_flags:
980
mutter_callsite(3, "has_revision is a LBYL symptom.")
1055
return revision_id in self.has_revisions((revision_id,))
1057
def has_revisions(self, revision_ids):
1058
"""Probe to find out the presence of multiple revisions.
1060
:param revision_ids: An iterable of revision_ids.
1061
:return: A set of the revision_ids that were present.
1063
raise NotImplementedError(self.has_revisions)
981
1065
return self._revision_store.has_revision_id(revision_id,
982
1066
self.get_transaction())
1408
1492
@needs_read_lock
1409
1493
def get_inventory(self, revision_id):
1410
"""Get Inventory object by hash."""
1411
return self.deserialise_inventory(
1412
revision_id, self.get_inventory_xml(revision_id))
1494
"""Get Inventory object by revision id."""
1495
return self.iter_inventories([revision_id]).next()
1497
def iter_inventories(self, revision_ids):
1498
"""Get many inventories by revision_ids.
1500
This will buffer some or all of the texts used in constructing the
1501
inventories in memory, but will only parse a single inventory at a
1504
:return: An iterator of inventories.
1506
assert None not in revision_ids
1507
assert _mod_revision.NULL_REVISION not in revision_ids
1508
return self._iter_inventories(revision_ids)
1510
def _iter_inventories(self, revision_ids):
1511
"""single-document based inventory iteration."""
1512
texts = self.get_inventory_weave().get_texts(revision_ids)
1513
for text, revision_id in zip(texts, revision_ids):
1514
yield self.deserialise_inventory(revision_id, text)
1414
1516
def deserialise_inventory(self, revision_id, xml):
1415
1517
"""Transform the xml into an inventory object.
1417
1519
:param revision_id: The expected revision id of the inventory.
1418
1520
:param xml: A serialised inventory.
1420
return self._serializer.read_inventory_from_string(xml, revision_id)
1522
result = self._serializer.read_inventory_from_string(xml, revision_id)
1523
if result.revision_id != revision_id:
1524
raise AssertionError('revision id mismatch %s != %s' % (
1525
result.revision_id, revision_id))
1422
1528
def serialise_inventory(self, inv):
1423
1529
return self._serializer.write_inventory_to_string(inv)
1583
1689
"""Return Tree for a revision on this branch.
1585
1691
`revision_id` may not be None or 'null:'"""
1586
assert None not in revision_ids
1587
assert _mod_revision.NULL_REVISION not in revision_ids
1588
texts = self.get_inventory_weave().get_texts(revision_ids)
1589
for text, revision_id in zip(texts, revision_ids):
1590
inv = self.deserialise_inventory(revision_id, text)
1591
yield RevisionTree(self, inv, revision_id)
1692
inventories = self.iter_inventories(revision_ids)
1693
for inv in inventories:
1694
yield RevisionTree(self, inv, inv.revision_id)
1593
1696
@needs_read_lock
1594
1697
def get_ancestry(self, revision_id, topo_sorted=True):
1654
1757
parent_map = {}
1655
1758
for revision_id in keys:
1656
1759
if revision_id == _mod_revision.NULL_REVISION:
1657
parent_map[revision_id] = []
1760
parent_map[revision_id] = ()
1660
parent_ids = self.get_revision(revision_id).parent_ids
1763
parent_id_list = self.get_revision(revision_id).parent_ids
1661
1764
except errors.NoSuchRevision:
1664
if len(parent_ids) == 0:
1665
parent_ids = [_mod_revision.NULL_REVISION]
1767
if len(parent_id_list) == 0:
1768
parent_ids = (_mod_revision.NULL_REVISION,)
1770
parent_ids = tuple(parent_id_list)
1666
1771
parent_map[revision_id] = parent_ids
1667
1772
return parent_map
1673
1778
"""Return the graph walker for this repository format"""
1674
1779
parents_provider = self._make_parents_provider()
1675
1780
if (other_repository is not None and
1676
other_repository.bzrdir.transport.base !=
1677
self.bzrdir.transport.base):
1781
not self.has_same_location(other_repository)):
1678
1782
parents_provider = graph._StackedParentsProvider(
1679
1783
[parents_provider, other_repository._make_parents_provider()])
1680
1784
return graph.Graph(parents_provider)
1683
1787
"""Return an object suitable for checking versioned files."""
1684
1788
return _VersionedFileChecker(self)
1790
def revision_ids_to_search_result(self, result_set):
1791
"""Convert a set of revision ids to a graph SearchResult."""
1792
result_parents = set()
1793
for parents in self.get_graph().get_parent_map(
1794
result_set).itervalues():
1795
result_parents.update(parents)
1796
included_keys = result_set.intersection(result_parents)
1797
start_keys = result_set.difference(included_keys)
1798
exclude_keys = result_parents.difference(result_set)
1799
result = graph.SearchResult(start_keys, exclude_keys,
1800
len(result_set), result_set)
1686
1803
@needs_write_lock
1687
1804
def set_make_working_trees(self, new_value):
1688
1805
"""Set the policy flag for making working trees when creating branches.
1769
1886
depend on the revision index being consistent.
1771
1888
raise NotImplementedError(self.revision_graph_can_have_wrong_parents)
1773
1891
# remove these delegates a while after bzr 0.15
1774
1892
def __make_delegated(name, from_module):
1775
1893
def _deprecated_repository_forwarder():
1809
1927
install_revisions(repository, [(rev, revision_tree, None)])
1812
def install_revisions(repository, iterable):
1930
def install_revisions(repository, iterable, num_revisions=None, pb=None):
1813
1931
"""Install all revision data into a repository.
1815
1933
Accepts an iterable of revision, tree, signature tuples. The signature
1818
1936
repository.start_write_group()
1820
for revision, revision_tree, signature in iterable:
1938
for n, (revision, revision_tree, signature) in enumerate(iterable):
1821
1939
_install_revision(repository, revision, revision_tree, signature)
1941
pb.update('Transferring revisions', n + 1, num_revisions)
1823
1943
repository.abort_write_group()
1970
2090
# Set to True or False in derived classes. True indicates that the format
1971
2091
# supports ghosts gracefully.
1972
2092
supports_ghosts = None
2093
# Can this repository be given external locations to lookup additional
2094
# data. Set to True or False in derived classes.
2095
supports_external_lookups = None
1974
2097
def __str__(self):
1975
2098
return "<%s>" % self.__class__.__name__
2179
2303
# Pack-based formats. There is one format for pre-subtrees, and one for
2180
2304
# post-subtrees to allow ease of testing.
2181
# NOTE: These are experimental in 0.92.
2305
# NOTE: These are experimental in 0.92. Stable in 1.0 and above
2182
2306
format_registry.register_lazy(
2183
2307
'Bazaar pack repository format 1 (needs bzr 0.92)\n',
2184
2308
'bzrlib.repofmt.pack_repo',
2194
2318
'bzrlib.repofmt.pack_repo',
2195
2319
'RepositoryFormatKnitPack4',
2321
# Development formats.
2323
# development 0 - stub to introduce development versioning scheme.
2324
format_registry.register_lazy(
2325
"Bazaar development format 0 (needs bzr.dev from before 1.3)\n",
2326
'bzrlib.repofmt.pack_repo',
2327
'RepositoryFormatPackDevelopment0',
2329
format_registry.register_lazy(
2330
("Bazaar development format 0 with subtree support "
2331
"(needs bzr.dev from before 1.3)\n"),
2332
'bzrlib.repofmt.pack_repo',
2333
'RepositoryFormatPackDevelopment0Subtree',
2335
# 1.3->1.4 go below here
2199
2338
class InterRepository(InterObject):
2228
2367
(copied, failures).
2230
2369
raise NotImplementedError(self.fetch)
2371
def _walk_to_common_revisions(self, revision_ids):
2372
"""Walk out from revision_ids in source to revisions target has.
2374
:param revision_ids: The start point for the search.
2375
:return: A set of revision ids.
2377
graph = self.source.get_graph()
2378
missing_revs = set()
2379
# ensure we don't pay silly lookup costs.
2380
revision_ids = frozenset(revision_ids)
2381
searcher = graph._make_breadth_first_searcher(revision_ids)
2382
null_set = frozenset([_mod_revision.NULL_REVISION])
2385
next_revs, ghosts = searcher.next_with_ghosts()
2386
except StopIteration:
2388
if revision_ids.intersection(ghosts):
2389
absent_ids = set(revision_ids.intersection(ghosts))
2390
# If all absent_ids are present in target, no error is needed.
2391
absent_ids.difference_update(
2392
self.target.has_revisions(absent_ids))
2394
raise errors.NoSuchRevision(self.source, absent_ids.pop())
2395
# we don't care about other ghosts as we can't fetch them and
2396
# haven't been asked to.
2397
next_revs = set(next_revs)
2398
# we always have NULL_REVISION present.
2399
have_revs = self.target.has_revisions(next_revs).union(null_set)
2400
missing_revs.update(next_revs - have_revs)
2401
searcher.stop_searching_any(have_revs)
2402
return searcher.get_result()
2404
@deprecated_method(symbol_versioning.one_two)
2232
2405
@needs_read_lock
2233
2406
def missing_revision_ids(self, revision_id=None, find_ghosts=True):
2234
2407
"""Return the revision ids that source has that target does not.
2238
2411
:param revision_id: only return revision ids included by this
2413
:param find_ghosts: If True find missing revisions in deep history
2414
rather than just finding the surface difference.
2416
return list(self.search_missing_revision_ids(
2417
revision_id, find_ghosts).get_keys())
2420
def search_missing_revision_ids(self, revision_id=None, find_ghosts=True):
2421
"""Return the revision ids that source has that target does not.
2423
:param revision_id: only return revision ids included by this
2425
:param find_ghosts: If True find missing revisions in deep history
2426
rather than just finding the surface difference.
2427
:return: A bzrlib.graph.SearchResult.
2429
# stop searching at found target revisions.
2430
if not find_ghosts and revision_id is not None:
2431
return self._walk_to_common_revisions([revision_id])
2241
2432
# generic, possibly worst case, slow code path.
2242
2433
target_ids = set(self.target.all_revision_ids())
2243
2434
if revision_id is not None:
2248
2439
source_ids = self.source.all_revision_ids()
2249
2440
result_set = set(source_ids).difference(target_ids)
2250
# this may look like a no-op: its not. It preserves the ordering
2251
# other_ids had while only returning the members from other_ids
2252
# that we've decided we need.
2253
return [rev_id for rev_id in source_ids if rev_id in result_set]
2441
return self.source.revision_ids_to_search_result(result_set)
2256
2444
def _same_model(source, target):
2315
2503
f = GenericRepoFetcher(to_repository=self.target,
2316
2504
from_repository=self.source,
2317
2505
last_revision=revision_id,
2506
pb=pb, find_ghosts=find_ghosts)
2319
2507
return f.count_copied, f.failed_revisions
2393
2581
f = GenericRepoFetcher(to_repository=self.target,
2394
2582
from_repository=self.source,
2395
2583
last_revision=revision_id,
2584
pb=pb, find_ghosts=find_ghosts)
2397
2585
return f.count_copied, f.failed_revisions
2399
2587
@needs_read_lock
2400
def missing_revision_ids(self, revision_id=None, find_ghosts=True):
2588
def search_missing_revision_ids(self, revision_id=None, find_ghosts=True):
2401
2589
"""See InterRepository.missing_revision_ids()."""
2402
2590
# we want all revisions to satisfy revision_id in source.
2403
2591
# but we don't want to stat every file here and there.
2423
2611
# we do not have a revision as that would be pointless.
2424
2612
target_ids = set(self.target._all_possible_ids())
2425
2613
possibly_present_revisions = target_ids.intersection(source_ids_set)
2426
actually_present_revisions = set(self.target._eliminate_revisions_not_present(possibly_present_revisions))
2614
actually_present_revisions = set(
2615
self.target._eliminate_revisions_not_present(possibly_present_revisions))
2427
2616
required_revisions = source_ids_set.difference(actually_present_revisions)
2428
required_topo_revisions = [rev_id for rev_id in source_ids if rev_id in required_revisions]
2429
2617
if revision_id is not None:
2430
2618
# we used get_ancestry to determine source_ids then we are assured all
2431
2619
# revisions referenced are present as they are installed in topological order.
2432
2620
# and the tip revision was validated by get_ancestry.
2433
return required_topo_revisions
2621
result_set = required_revisions
2435
2623
# if we just grabbed the possibly available ids, then
2436
2624
# we only have an estimate of whats available and need to validate
2437
2625
# that against the revision records.
2438
return self.source._eliminate_revisions_not_present(required_topo_revisions)
2627
self.source._eliminate_revisions_not_present(required_revisions))
2628
return self.source.revision_ids_to_search_result(result_set)
2441
2631
class InterKnitRepo(InterSameDataRepository):
2471
2661
f = KnitRepoFetcher(to_repository=self.target,
2472
2662
from_repository=self.source,
2473
2663
last_revision=revision_id,
2664
pb=pb, find_ghosts=find_ghosts)
2475
2665
return f.count_copied, f.failed_revisions
2477
2667
@needs_read_lock
2478
def missing_revision_ids(self, revision_id=None, find_ghosts=True):
2668
def search_missing_revision_ids(self, revision_id=None, find_ghosts=True):
2479
2669
"""See InterRepository.missing_revision_ids()."""
2480
2670
if revision_id is not None:
2481
2671
source_ids = self.source.get_ancestry(revision_id)
2490
2680
# we do not have a revision as that would be pointless.
2491
2681
target_ids = set(self.target.all_revision_ids())
2492
2682
possibly_present_revisions = target_ids.intersection(source_ids_set)
2493
actually_present_revisions = set(self.target._eliminate_revisions_not_present(possibly_present_revisions))
2683
actually_present_revisions = set(
2684
self.target._eliminate_revisions_not_present(possibly_present_revisions))
2494
2685
required_revisions = source_ids_set.difference(actually_present_revisions)
2495
required_topo_revisions = [rev_id for rev_id in source_ids if rev_id in required_revisions]
2496
2686
if revision_id is not None:
2497
2687
# we used get_ancestry to determine source_ids then we are assured all
2498
2688
# revisions referenced are present as they are installed in topological order.
2499
2689
# and the tip revision was validated by get_ancestry.
2500
return required_topo_revisions
2690
result_set = required_revisions
2502
2692
# if we just grabbed the possibly available ids, then
2503
2693
# we only have an estimate of whats available and need to validate
2504
2694
# that against the revision records.
2505
return self.source._eliminate_revisions_not_present(required_topo_revisions)
2696
self.source._eliminate_revisions_not_present(required_revisions))
2697
return self.source.revision_ids_to_search_result(result_set)
2508
2700
class InterPackRepo(InterSameDataRepository):
2558
revision_ids = self.missing_revision_ids(revision_id,
2559
find_ghosts=find_ghosts)
2750
revision_ids = self.search_missing_revision_ids(revision_id,
2751
find_ghosts=find_ghosts).get_keys()
2560
2752
except errors.NoSuchRevision:
2561
2753
raise errors.InstallFailed([revision_id])
2562
2754
packs = self.source._pack_collection.all_packs()
2575
2767
@needs_read_lock
2576
def missing_revision_ids(self, revision_id=None, find_ghosts=True):
2768
def search_missing_revision_ids(self, revision_id=None, find_ghosts=True):
2577
2769
"""See InterRepository.missing_revision_ids().
2579
:param find_ghosts: Find ghosts throughough the ancestry of
2771
:param find_ghosts: Find ghosts throughout the ancestry of
2582
2774
if not find_ghosts and revision_id is not None:
2583
graph = self.source.get_graph()
2584
missing_revs = set()
2585
searcher = graph._make_breadth_first_searcher([revision_id])
2587
self.target._pack_collection.revision_index.combined_index
2588
null_set = frozenset([_mod_revision.NULL_REVISION])
2591
next_revs = set(searcher.next())
2592
except StopIteration:
2594
next_revs.difference_update(null_set)
2595
target_keys = [(key,) for key in next_revs]
2596
have_revs = frozenset(node[1][0] for node in
2597
target_index.iter_entries(target_keys))
2598
missing_revs.update(next_revs - have_revs)
2599
searcher.stop_searching_any(have_revs)
2600
if next_revs - have_revs == set([revision_id]):
2601
# we saw the start rev itself, but no parents from it (or
2602
# next_revs would have been updated to e.g. set(). We remove
2603
# have_revs because if we found revision_id locally we
2604
# stop_searching at the first time around.
2605
raise errors.NoSuchRevision(self.source, revision_id)
2775
return self._walk_to_common_revisions([revision_id])
2607
2776
elif revision_id is not None:
2608
2777
source_ids = self.source.get_ancestry(revision_id)
2609
2778
assert source_ids[0] is None
2615
2784
# have in target, but don't try to check for existence where we know
2616
2785
# we do not have a revision as that would be pointless.
2617
2786
target_ids = set(self.target.all_revision_ids())
2618
return [r for r in source_ids if (r not in target_ids)]
2787
result_set = set(source_ids).difference(target_ids)
2788
return self.source.revision_ids_to_search_result(result_set)
2621
2791
class InterModel1and2(InterRepository):
2638
2808
f = Model1toKnit2Fetcher(to_repository=self.target,
2639
2809
from_repository=self.source,
2640
2810
last_revision=revision_id,
2811
pb=pb, find_ghosts=find_ghosts)
2642
2812
return f.count_copied, f.failed_revisions
2644
2814
@needs_write_lock
2676
2846
from bzrlib.repofmt.knitrepo import (RepositoryFormatKnit1,
2677
2847
RepositoryFormatKnit3)
2678
from bzrlib.repofmt.pack_repo import (RepositoryFormatKnitPack1,
2679
RepositoryFormatKnitPack3)
2680
return (isinstance(source._format,
2681
(RepositoryFormatKnit1, RepositoryFormatKnitPack1)) and
2682
isinstance(target._format,
2683
(RepositoryFormatKnit3, RepositoryFormatKnitPack3))
2848
from bzrlib.repofmt.pack_repo import (
2849
RepositoryFormatKnitPack1,
2850
RepositoryFormatKnitPack3,
2851
RepositoryFormatPackDevelopment0,
2852
RepositoryFormatPackDevelopment0Subtree,
2855
RepositoryFormatKnit1,
2856
RepositoryFormatKnitPack1,
2857
RepositoryFormatPackDevelopment0,
2860
RepositoryFormatKnit3,
2861
RepositoryFormatKnitPack3,
2862
RepositoryFormatPackDevelopment0Subtree,
2864
return (isinstance(source._format, nosubtrees) and
2865
isinstance(target._format, subtrees))
2685
2866
except AttributeError:
2695
2876
f = Knit1to2Fetcher(to_repository=self.target,
2696
2877
from_repository=self.source,
2697
2878
last_revision=revision_id,
2879
pb=pb, find_ghosts=find_ghosts)
2699
2880
return f.count_copied, f.failed_revisions
2720
2901
@needs_write_lock
2721
2902
def fetch(self, revision_id=None, pb=None, find_ghosts=False):
2722
2903
"""See InterRepository.fetch()."""
2723
revision_ids = self.target.missing_revision_ids(self.source,
2904
revision_ids = self.target.search_missing_revision_ids(self.source,
2905
revision_id, find_ghosts=find_ghosts).get_keys()
2906
revision_ids = tsort.topo_sort(
2907
self.source.get_graph().get_parent_map(revision_ids))
2725
2908
def revisions_iterator():
2726
2909
for current_revision_id in revision_ids:
2727
2910
revision = self.source.get_revision(current_revision_id)
2732
2915
except errors.NoSuchRevision:
2733
2916
signature = None
2734
2917
yield revision, tree, signature
2735
install_revisions(self.target, revisions_iterator())
2919
my_pb = ui.ui_factory.nested_progress_bar()
2924
install_revisions(self.target, revisions_iterator(),
2925
len(revision_ids), pb)
2927
if my_pb is not None:
2736
2929
return len(revision_ids), 0
2746
2939
def is_compatible(source, target):
2747
2940
if not isinstance(source, remote.RemoteRepository):
2942
# Is source's model compatible with target's model?
2749
2943
source._ensure_real()
2750
2944
real_source = source._real_repository
2751
# Is source's model compatible with target's model, and are they the
2752
# same format? Currently we can only optimise fetching from an
2753
# identical model & format repo.
2754
2945
assert not isinstance(real_source, remote.RemoteRepository), (
2755
2946
"We don't support remote repos backed by remote repos yet.")
2756
return real_source._format == target._format
2947
return InterRepository._same_model(real_source, target)
2758
2949
@needs_write_lock
2759
2950
def fetch(self, revision_id=None, pb=None, find_ghosts=False):
2766
2957
f = RemoteToOtherFetcher(to_repository=self.target,
2767
2958
from_repository=self.source,
2768
2959
last_revision=revision_id,
2960
pb=pb, find_ghosts=find_ghosts)
2770
2961
return f.count_copied, f.failed_revisions
2799
2990
def fetch(self, revision_id=None, pb=None, find_ghosts=False):
2800
2991
self._ensure_real_inter()
2801
self._real_inter.fetch(revision_id=revision_id, pb=pb)
2992
self._real_inter.fetch(revision_id=revision_id, pb=pb,
2993
find_ghosts=find_ghosts)
2804
2996
def _get_repo_format_to_test(self):