~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/vf_repository.py

Abbreviate pack_stat struct format to '>6L'

Show diffs side-by-side

added added

removed removed

Lines of Context:
19
19
 
20
20
from bzrlib.lazy_import import lazy_import
21
21
lazy_import(globals(), """
 
22
import itertools
 
23
 
22
24
from bzrlib import (
 
25
    check,
23
26
    debug,
24
27
    fetch as _mod_fetch,
25
28
    fifo_cache,
31
34
    revision as _mod_revision,
32
35
    serializer as _mod_serializer,
33
36
    static_tuple,
 
37
    symbol_versioning,
34
38
    tsort,
35
39
    ui,
36
40
    versionedfile,
39
43
from bzrlib.recordcounter import RecordCounter
40
44
from bzrlib.revisiontree import InventoryRevisionTree
41
45
from bzrlib.testament import Testament
 
46
from bzrlib.i18n import gettext
42
47
""")
43
48
 
44
49
from bzrlib import (
66
71
    )
67
72
 
68
73
from bzrlib.trace import (
69
 
    mutter,
 
74
    mutter
70
75
    )
71
76
 
72
77
 
74
79
    """Base class for all repository formats that are VersionedFiles-based."""
75
80
 
76
81
    supports_full_versioned_files = True
 
82
    supports_versioned_directories = True
77
83
 
78
84
    # Should commit add an inventory, or an inventory delta to the repository.
79
85
    _commit_inv_deltas = True
104
110
        super(VersionedFileCommitBuilder, self).__init__(repository,
105
111
            parents, config, timestamp, timezone, committer, revprops,
106
112
            revision_id, lossy)
 
113
        try:
 
114
            basis_id = self.parents[0]
 
115
        except IndexError:
 
116
            basis_id = _mod_revision.NULL_REVISION
 
117
        self.basis_delta_revision = basis_id
107
118
        self.new_inventory = Inventory(None)
108
119
        self._basis_delta = []
109
120
        self.__heads = graph.HeadsCache(repository.get_graph()).heads
123
134
        builder.record_delete().
124
135
        """
125
136
        self._recording_deletes = True
126
 
        try:
127
 
            basis_id = self.parents[0]
128
 
        except IndexError:
129
 
            basis_id = _mod_revision.NULL_REVISION
130
 
        self.basis_delta_revision = basis_id
131
137
 
132
138
    def any_changes(self):
133
139
        """Return True if any entries were changed.
274
280
 
275
281
    def _get_delta(self, ie, basis_inv, path):
276
282
        """Get a delta against the basis inventory for ie."""
277
 
        if ie.file_id not in basis_inv:
 
283
        if not basis_inv.has_id(ie.file_id):
278
284
            # add
279
285
            result = (None, path, ie.file_id, ie)
280
286
            self._basis_delta.append(result)
393
399
                # this masks when a change may have occurred against the basis.
394
400
                # To match this we always issue a delta, because the revision
395
401
                # of the root will always be changing.
396
 
                if ie.file_id in basis_inv:
 
402
                if basis_inv.has_id(ie.file_id):
397
403
                    delta = (basis_inv.id2path(ie.file_id), path,
398
404
                        ie.file_id, ie)
399
405
                else:
414
420
                return None, False, None
415
421
        # XXX: Friction: parent_candidates should return a list not a dict
416
422
        #      so that we don't have to walk the inventories again.
417
 
        parent_candiate_entries = ie.parent_candidates(parent_invs)
418
 
        head_set = self._heads(ie.file_id, parent_candiate_entries.keys())
 
423
        parent_candidate_entries = ie.parent_candidates(parent_invs)
 
424
        head_set = self._heads(ie.file_id, parent_candidate_entries.keys())
419
425
        heads = []
420
426
        for inv in parent_invs:
421
 
            if ie.file_id in inv:
 
427
            if inv.has_id(ie.file_id):
422
428
                old_rev = inv[ie.file_id].revision
423
429
                if old_rev in head_set:
424
430
                    heads.append(inv[ie.file_id].revision)
436
442
            store = True
437
443
        if not store:
438
444
            # There is a single head, look it up for comparison
439
 
            parent_entry = parent_candiate_entries[heads[0]]
 
445
            parent_entry = parent_candidate_entries[heads[0]]
440
446
            # if the non-content specific data has changed, we'll be writing a
441
447
            # node:
442
448
            if (parent_entry.parent_id != ie.parent_id or
536
542
        else:
537
543
            raise NotImplementedError('unknown kind')
538
544
        ie.revision = self._new_revision_id
539
 
        self._any_changes = True
 
545
        # The initial commit adds a root directory, but this in itself is not
 
546
        # a worthwhile commit.
 
547
        if (self.basis_delta_revision != _mod_revision.NULL_REVISION or
 
548
            path != ""):
 
549
            self._any_changes = True
540
550
        return self._get_delta(ie, basis_inv, path), True, fingerprint
541
551
 
542
552
    def record_iter_changes(self, tree, basis_revision_id, iter_changes,
550
560
        :param iter_changes: An iter_changes iterator with the changes to apply
551
561
            to basis_revision_id. The iterator must not include any items with
552
562
            a current kind of None - missing items must be either filtered out
553
 
            or errored-on beefore record_iter_changes sees the item.
 
563
            or errored-on before record_iter_changes sees the item.
554
564
        :param _entry_factory: Private method to bind entry_factory locally for
555
565
            performance.
556
566
        :return: A generator of (file_id, relpath, fs_hash) tuples for use with
798
808
            if new_path == '':
799
809
                seen_root = True
800
810
        self.new_inventory = None
801
 
        if len(inv_delta):
 
811
        # The initial commit adds a root directory, but this in itself is not
 
812
        # a worthwhile commit.
 
813
        if ((len(inv_delta) > 0 and basis_revision_id != _mod_revision.NULL_REVISION) or
 
814
            (len(inv_delta) > 1 and basis_revision_id == _mod_revision.NULL_REVISION)):
802
815
            # This should perhaps be guarded by a check that the basis we
803
816
            # commit against is the basis for the commit and if not do a delta
804
817
            # against the basis.
906
919
        """
907
920
        if not self._format.supports_external_lookups:
908
921
            raise errors.UnstackableRepositoryFormat(self._format, self.base)
 
922
        # This can raise an exception, so should be done before we lock the
 
923
        # fallback repository.
 
924
        self._check_fallback_repository(repository)
909
925
        if self.is_locked():
910
926
            # This repository will call fallback.unlock() when we transition to
911
927
            # the unlocked state, so we make sure to increment the lock count
912
928
            repository.lock_read()
913
 
        self._check_fallback_repository(repository)
914
929
        self._fallback_repositories.append(repository)
915
930
        self.texts.add_fallback_versioned_files(repository.texts)
916
931
        self.inventories.add_fallback_versioned_files(repository.inventories)
1073
1088
        keys = {'chk_bytes':set(), 'inventories':set(), 'texts':set()}
1074
1089
        kinds = ['chk_bytes', 'texts']
1075
1090
        count = len(checker.pending_keys)
1076
 
        bar.update("inventories", 0, 2)
 
1091
        bar.update(gettext("inventories"), 0, 2)
1077
1092
        current_keys = checker.pending_keys
1078
1093
        checker.pending_keys = {}
1079
1094
        # Accumulate current checks.
1099
1114
            del keys['inventories']
1100
1115
        else:
1101
1116
            return
1102
 
        bar.update("texts", 1)
 
1117
        bar.update(gettext("texts"), 1)
1103
1118
        while (checker.pending_keys or keys['chk_bytes']
1104
1119
            or keys['texts']):
1105
1120
            # Something to check.
1168
1183
                'sha1 mismatch: %s has sha1 %s expected %s referenced by %s' %
1169
1184
                (record.key, sha1, item_data[1], item_data[2]))
1170
1185
 
 
1186
    @needs_read_lock
 
1187
    def _eliminate_revisions_not_present(self, revision_ids):
 
1188
        """Check every revision id in revision_ids to see if we have it.
 
1189
 
 
1190
        Returns a set of the present revisions.
 
1191
        """
 
1192
        result = []
 
1193
        graph = self.get_graph()
 
1194
        parent_map = graph.get_parent_map(revision_ids)
 
1195
        # The old API returned a list, should this actually be a set?
 
1196
        return parent_map.keys()
 
1197
 
1171
1198
    def __init__(self, _format, a_bzrdir, control_files):
1172
1199
        """Instantiate a VersionedFileRepository.
1173
1200
 
1180
1207
        # this construct will accept instances of those things.
1181
1208
        super(VersionedFileRepository, self).__init__(_format, a_bzrdir,
1182
1209
            control_files)
 
1210
        self._transport = control_files._transport
 
1211
        self.base = self._transport.base
1183
1212
        # for tests
1184
1213
        self._reconcile_does_inventory_gc = True
1185
1214
        self._reconcile_fixes_text_parents = False
1204
1233
            # result['size'] = t
1205
1234
        return result
1206
1235
 
1207
 
 
1208
1236
    def get_commit_builder(self, branch, parents, config, timestamp=None,
1209
1237
                           timezone=None, committer=None, revprops=None,
1210
1238
                           revision_id=None, lossy=False):
1417
1445
            the revision key from each parsed line will be looked up in the
1418
1446
            revision_keys filter.
1419
1447
        :return: a dictionary mapping altered file-ids to an iterable of
1420
 
        revision_ids. Each altered file-ids has the exact revision_ids that
1421
 
        altered it listed explicitly.
 
1448
            revision_ids. Each altered file-ids has the exact revision_ids that
 
1449
            altered it listed explicitly.
1422
1450
        """
1423
1451
        seen = set(self._serializer._find_text_key_references(
1424
1452
                line_iterator).iterkeys())
1453
1481
        :param _inv_weave: The inventory weave from this repository or None.
1454
1482
            If None, the inventory weave will be opened automatically.
1455
1483
        :return: a dictionary mapping altered file-ids to an iterable of
1456
 
        revision_ids. Each altered file-ids has the exact revision_ids that
1457
 
        altered it listed explicitly.
 
1484
            revision_ids. Each altered file-ids has the exact revision_ids that
 
1485
            altered it listed explicitly.
1458
1486
        """
1459
1487
        selected_keys = set((revid,) for revid in revision_ids)
1460
1488
        w = _inv_weave or self.inventories
1543
1571
        batch_size = 10 # should be ~150MB on a 55K path tree
1544
1572
        batch_count = len(revision_order) / batch_size + 1
1545
1573
        processed_texts = 0
1546
 
        pb.update("Calculating text parents", processed_texts, text_count)
 
1574
        pb.update(gettext("Calculating text parents"), processed_texts, text_count)
1547
1575
        for offset in xrange(batch_count):
1548
1576
            to_query = revision_order[offset * batch_size:(offset + 1) *
1549
1577
                batch_size]
1552
1580
            for revision_id in to_query:
1553
1581
                parent_ids = ancestors[revision_id]
1554
1582
                for text_key in revision_keys[revision_id]:
1555
 
                    pb.update("Calculating text parents", processed_texts)
 
1583
                    pb.update(gettext("Calculating text parents"), processed_texts)
1556
1584
                    processed_texts += 1
1557
1585
                    candidate_parents = []
1558
1586
                    for parent_id in parent_ids:
1628
1656
        num_file_ids = len(file_ids)
1629
1657
        for file_id, altered_versions in file_ids.iteritems():
1630
1658
            if pb is not None:
1631
 
                pb.update("Fetch texts", count, num_file_ids)
 
1659
                pb.update(gettext("Fetch texts"), count, num_file_ids)
1632
1660
            count += 1
1633
1661
            yield ("file", file_id, altered_versions)
1634
1662
 
1815
1843
        known_graph = self.revisions.get_known_graph_ancestry(revision_keys)
1816
1844
        return graph.GraphThunkIdsToKeys(known_graph)
1817
1845
 
 
1846
    @needs_read_lock
 
1847
    def get_file_graph(self):
 
1848
        """Return the graph walker for text revisions."""
 
1849
        return graph.Graph(self.texts)
 
1850
 
1818
1851
    def _get_versioned_file_checker(self, text_key_references=None,
1819
1852
        ancestors=None):
1820
1853
        """Return an object suitable for checking versioned files.
1850
1883
            raise errors.NoSuchRevision(self, revision_id)
1851
1884
        return record.get_bytes_as('fulltext')
1852
1885
 
 
1886
    @needs_read_lock
 
1887
    def _check(self, revision_ids, callback_refs, check_repo):
 
1888
        result = check.VersionedFileCheck(self, check_repo=check_repo)
 
1889
        result.check(callback_refs)
 
1890
        return result
 
1891
 
1853
1892
    def _find_inconsistent_revision_parents(self, revisions_iterator=None):
1854
1893
        """Find revisions with different parent lists in the revision object
1855
1894
        and in the index graph.
2428
2467
            self.text_index.iterkeys()])
2429
2468
        # text keys is now grouped by file_id
2430
2469
        n_versions = len(self.text_index)
2431
 
        progress_bar.update('loading text store', 0, n_versions)
 
2470
        progress_bar.update(gettext('loading text store'), 0, n_versions)
2432
2471
        parent_map = self.repository.texts.get_parent_map(self.text_index)
2433
2472
        # On unlistable transports this could well be empty/error...
2434
2473
        text_keys = self.repository.texts.keys()
2435
2474
        unused_keys = frozenset(text_keys) - set(self.text_index)
2436
2475
        for num, key in enumerate(self.text_index.iterkeys()):
2437
 
            progress_bar.update('checking text graph', num, n_versions)
 
2476
            progress_bar.update(gettext('checking text graph'), num, n_versions)
2438
2477
            correct_parents = self.calculate_file_version_parents(key)
2439
2478
            try:
2440
2479
                knit_parents = parent_map[key]
2446
2485
        return wrong_parents, unused_keys
2447
2486
 
2448
2487
 
2449
 
class InterDifferingSerializer(InterRepository):
 
2488
class InterVersionedFileRepository(InterRepository):
 
2489
 
 
2490
    _walk_to_common_revisions_batch_size = 50
 
2491
 
 
2492
    @needs_write_lock
 
2493
    def fetch(self, revision_id=None, find_ghosts=False,
 
2494
            fetch_spec=None):
 
2495
        """Fetch the content required to construct revision_id.
 
2496
 
 
2497
        The content is copied from self.source to self.target.
 
2498
 
 
2499
        :param revision_id: if None all content is copied, if NULL_REVISION no
 
2500
                            content is copied.
 
2501
        :return: None.
 
2502
        """
 
2503
        if self.target._format.experimental:
 
2504
            ui.ui_factory.show_user_warning('experimental_format_fetch',
 
2505
                from_format=self.source._format,
 
2506
                to_format=self.target._format)
 
2507
        from bzrlib.fetch import RepoFetcher
 
2508
        # See <https://launchpad.net/bugs/456077> asking for a warning here
 
2509
        if self.source._format.network_name() != self.target._format.network_name():
 
2510
            ui.ui_factory.show_user_warning('cross_format_fetch',
 
2511
                from_format=self.source._format,
 
2512
                to_format=self.target._format)
 
2513
        f = RepoFetcher(to_repository=self.target,
 
2514
                               from_repository=self.source,
 
2515
                               last_revision=revision_id,
 
2516
                               fetch_spec=fetch_spec,
 
2517
                               find_ghosts=find_ghosts)
 
2518
 
 
2519
    def _walk_to_common_revisions(self, revision_ids, if_present_ids=None):
 
2520
        """Walk out from revision_ids in source to revisions target has.
 
2521
 
 
2522
        :param revision_ids: The start point for the search.
 
2523
        :return: A set of revision ids.
 
2524
        """
 
2525
        target_graph = self.target.get_graph()
 
2526
        revision_ids = frozenset(revision_ids)
 
2527
        if if_present_ids:
 
2528
            all_wanted_revs = revision_ids.union(if_present_ids)
 
2529
        else:
 
2530
            all_wanted_revs = revision_ids
 
2531
        missing_revs = set()
 
2532
        source_graph = self.source.get_graph()
 
2533
        # ensure we don't pay silly lookup costs.
 
2534
        searcher = source_graph._make_breadth_first_searcher(all_wanted_revs)
 
2535
        null_set = frozenset([_mod_revision.NULL_REVISION])
 
2536
        searcher_exhausted = False
 
2537
        while True:
 
2538
            next_revs = set()
 
2539
            ghosts = set()
 
2540
            # Iterate the searcher until we have enough next_revs
 
2541
            while len(next_revs) < self._walk_to_common_revisions_batch_size:
 
2542
                try:
 
2543
                    next_revs_part, ghosts_part = searcher.next_with_ghosts()
 
2544
                    next_revs.update(next_revs_part)
 
2545
                    ghosts.update(ghosts_part)
 
2546
                except StopIteration:
 
2547
                    searcher_exhausted = True
 
2548
                    break
 
2549
            # If there are ghosts in the source graph, and the caller asked for
 
2550
            # them, make sure that they are present in the target.
 
2551
            # We don't care about other ghosts as we can't fetch them and
 
2552
            # haven't been asked to.
 
2553
            ghosts_to_check = set(revision_ids.intersection(ghosts))
 
2554
            revs_to_get = set(next_revs).union(ghosts_to_check)
 
2555
            if revs_to_get:
 
2556
                have_revs = set(target_graph.get_parent_map(revs_to_get))
 
2557
                # we always have NULL_REVISION present.
 
2558
                have_revs = have_revs.union(null_set)
 
2559
                # Check if the target is missing any ghosts we need.
 
2560
                ghosts_to_check.difference_update(have_revs)
 
2561
                if ghosts_to_check:
 
2562
                    # One of the caller's revision_ids is a ghost in both the
 
2563
                    # source and the target.
 
2564
                    raise errors.NoSuchRevision(
 
2565
                        self.source, ghosts_to_check.pop())
 
2566
                missing_revs.update(next_revs - have_revs)
 
2567
                # Because we may have walked past the original stop point, make
 
2568
                # sure everything is stopped
 
2569
                stop_revs = searcher.find_seen_ancestors(have_revs)
 
2570
                searcher.stop_searching_any(stop_revs)
 
2571
            if searcher_exhausted:
 
2572
                break
 
2573
        return searcher.get_result()
 
2574
 
 
2575
    @needs_read_lock
 
2576
    def search_missing_revision_ids(self,
 
2577
            revision_id=symbol_versioning.DEPRECATED_PARAMETER,
 
2578
            find_ghosts=True, revision_ids=None, if_present_ids=None,
 
2579
            limit=None):
 
2580
        """Return the revision ids that source has that target does not.
 
2581
 
 
2582
        :param revision_id: only return revision ids included by this
 
2583
            revision_id.
 
2584
        :param revision_ids: return revision ids included by these
 
2585
            revision_ids.  NoSuchRevision will be raised if any of these
 
2586
            revisions are not present.
 
2587
        :param if_present_ids: like revision_ids, but will not cause
 
2588
            NoSuchRevision if any of these are absent, instead they will simply
 
2589
            not be in the result.  This is useful for e.g. finding revisions
 
2590
            to fetch for tags, which may reference absent revisions.
 
2591
        :param find_ghosts: If True find missing revisions in deep history
 
2592
            rather than just finding the surface difference.
 
2593
        :return: A bzrlib.graph.SearchResult.
 
2594
        """
 
2595
        if symbol_versioning.deprecated_passed(revision_id):
 
2596
            symbol_versioning.warn(
 
2597
                'search_missing_revision_ids(revision_id=...) was '
 
2598
                'deprecated in 2.4.  Use revision_ids=[...] instead.',
 
2599
                DeprecationWarning, stacklevel=2)
 
2600
            if revision_ids is not None:
 
2601
                raise AssertionError(
 
2602
                    'revision_ids is mutually exclusive with revision_id')
 
2603
            if revision_id is not None:
 
2604
                revision_ids = [revision_id]
 
2605
        del revision_id
 
2606
        # stop searching at found target revisions.
 
2607
        if not find_ghosts and (revision_ids is not None or if_present_ids is
 
2608
                not None):
 
2609
            result = self._walk_to_common_revisions(revision_ids,
 
2610
                    if_present_ids=if_present_ids)
 
2611
            if limit is None:
 
2612
                return result
 
2613
            result_set = result.get_keys()
 
2614
        else:
 
2615
            # generic, possibly worst case, slow code path.
 
2616
            target_ids = set(self.target.all_revision_ids())
 
2617
            source_ids = self._present_source_revisions_for(
 
2618
                revision_ids, if_present_ids)
 
2619
            result_set = set(source_ids).difference(target_ids)
 
2620
        if limit is not None:
 
2621
            topo_ordered = self.source.get_graph().iter_topo_order(result_set)
 
2622
            result_set = set(itertools.islice(topo_ordered, limit))
 
2623
        return self.source.revision_ids_to_search_result(result_set)
 
2624
 
 
2625
    def _present_source_revisions_for(self, revision_ids, if_present_ids=None):
 
2626
        """Returns set of all revisions in ancestry of revision_ids present in
 
2627
        the source repo.
 
2628
 
 
2629
        :param revision_ids: if None, all revisions in source are returned.
 
2630
        :param if_present_ids: like revision_ids, but if any/all of these are
 
2631
            absent no error is raised.
 
2632
        """
 
2633
        if revision_ids is not None or if_present_ids is not None:
 
2634
            # First, ensure all specified revisions exist.  Callers expect
 
2635
            # NoSuchRevision when they pass absent revision_ids here.
 
2636
            if revision_ids is None:
 
2637
                revision_ids = set()
 
2638
            if if_present_ids is None:
 
2639
                if_present_ids = set()
 
2640
            revision_ids = set(revision_ids)
 
2641
            if_present_ids = set(if_present_ids)
 
2642
            all_wanted_ids = revision_ids.union(if_present_ids)
 
2643
            graph = self.source.get_graph()
 
2644
            present_revs = set(graph.get_parent_map(all_wanted_ids))
 
2645
            missing = revision_ids.difference(present_revs)
 
2646
            if missing:
 
2647
                raise errors.NoSuchRevision(self.source, missing.pop())
 
2648
            found_ids = all_wanted_ids.intersection(present_revs)
 
2649
            source_ids = [rev_id for (rev_id, parents) in
 
2650
                          graph.iter_ancestry(found_ids)
 
2651
                          if rev_id != _mod_revision.NULL_REVISION
 
2652
                          and parents is not None]
 
2653
        else:
 
2654
            source_ids = self.source.all_revision_ids()
 
2655
        return set(source_ids)
 
2656
 
 
2657
    @classmethod
 
2658
    def _get_repo_format_to_test(self):
 
2659
        return None
 
2660
 
 
2661
    @classmethod
 
2662
    def is_compatible(cls, source, target):
 
2663
        # The default implementation is compatible with everything
 
2664
        return (source._format.supports_full_versioned_files and
 
2665
                target._format.supports_full_versioned_files)
 
2666
 
 
2667
 
 
2668
class InterDifferingSerializer(InterVersionedFileRepository):
2450
2669
 
2451
2670
    @classmethod
2452
2671
    def _get_repo_format_to_test(self):
2704
2923
        for offset in range(0, len(revision_ids), batch_size):
2705
2924
            self.target.start_write_group()
2706
2925
            try:
2707
 
                pb.update('Transferring revisions', offset,
 
2926
                pb.update(gettext('Transferring revisions'), offset,
2708
2927
                          len(revision_ids))
2709
2928
                batch = revision_ids[offset:offset+batch_size]
2710
2929
                basis_id = self._fetch_batch(batch, basis_id, cache)
2718
2937
                    hints.extend(hint)
2719
2938
        if hints and self.target._format.pack_compresses:
2720
2939
            self.target.pack(hint=hints)
2721
 
        pb.update('Transferring revisions', len(revision_ids),
 
2940
        pb.update(gettext('Transferring revisions'), len(revision_ids),
2722
2941
                  len(revision_ids))
2723
2942
 
2724
2943
    @needs_write_lock
2729
2948
            revision_ids = fetch_spec.get_keys()
2730
2949
        else:
2731
2950
            revision_ids = None
2732
 
        ui.ui_factory.warn_experimental_format_fetch(self)
 
2951
        if self.source._format.experimental:
 
2952
            ui.ui_factory.show_user_warning('experimental_format_fetch',
 
2953
                from_format=self.source._format,
 
2954
                to_format=self.target._format)
2733
2955
        if (not self.source.supports_rich_root()
2734
2956
            and self.target.supports_rich_root()):
2735
2957
            self._converting_to_rich_root = True
2788
3010
        return basis_id, basis_tree
2789
3011
 
2790
3012
 
2791
 
class InterSameDataRepository(InterRepository):
 
3013
class InterSameDataRepository(InterVersionedFileRepository):
2792
3014
    """Code for converting between repositories that represent the same data.
2793
3015
 
2794
3016
    Data format and model must match for this to work.
2812
3034
            target._format.supports_full_versioned_files)
2813
3035
 
2814
3036
 
 
3037
InterRepository.register_optimiser(InterVersionedFileRepository)
2815
3038
InterRepository.register_optimiser(InterDifferingSerializer)
2816
3039
InterRepository.register_optimiser(InterSameDataRepository)
2817
3040
 
2829
3052
            _install_revision(repository, revision, revision_tree, signature,
2830
3053
                inventory_cache)
2831
3054
            if pb is not None:
2832
 
                pb.update('Transferring revisions', n + 1, num_revisions)
 
3055
                pb.update(gettext('Transferring revisions'), n + 1, num_revisions)
2833
3056
    except:
2834
3057
        repository.abort_write_group()
2835
3058
        raise
2871
3094
        # the parents inserted are not those commit would do - in particular
2872
3095
        # they are not filtered by heads(). RBC, AB
2873
3096
        for revision, tree in parent_trees.iteritems():
2874
 
            if ie.file_id not in tree:
 
3097
            if not tree.has_id(ie.file_id):
2875
3098
                continue
2876
3099
            parent_id = tree.get_file_revision(ie.file_id)
2877
3100
            if parent_id in text_parents: