71
class RepoReconciler(object):
72
"""Reconciler that reconciles a repository.
76
def __init__(self, repo, other=None, thorough=False):
77
"""Construct a RepoReconciler.
79
:param thorough: perform a thorough check which may take longer but
80
will correct non-data loss issues such as incorrect
86
"""Perform reconciliation.
88
After reconciliation the following attributes document found issues:
89
inconsistent_parents: The number of revisions in the repository whose
90
ancestry was being reported incorrectly.
91
garbage_inventories: The number of inventory objects without revisions
92
that were garbage collected.
96
63
class GitCheck(check.Check):
98
65
def __init__(self, repository, check_repo=True):
131
98
self._report_repo_results(verbose)
134
_optimisers_loaded = False
137
def lazy_load_optimisers():
138
global _optimisers_loaded
139
if _optimisers_loaded:
141
from . import interrepo
142
for optimiser in [interrepo.InterRemoteGitNonGitRepository,
143
interrepo.InterLocalGitNonGitRepository,
144
interrepo.InterLocalGitLocalGitRepository,
145
interrepo.InterRemoteGitLocalGitRepository,
146
interrepo.InterToLocalGitRepository,
147
interrepo.InterToRemoteGitRepository,
149
repository.InterRepository.register_optimiser(optimiser)
150
_optimisers_loaded = True
101
for optimiser in ['InterRemoteGitNonGitRepository',
102
'InterLocalGitNonGitRepository',
103
'InterLocalGitLocalGitRepository',
104
'InterLocalGitRemoteGitRepository',
105
'InterRemoteGitLocalGitRepository',
106
'InterToLocalGitRepository',
107
'InterToRemoteGitRepository',
109
repository.InterRepository.register_lazy_optimiser(
110
'breezy.git.interrepo', optimiser)
153
113
class GitRepository(ForeignRepository):
162
122
super(GitRepository, self).__init__(GitRepositoryFormat(),
163
123
gitdir, control_files=None)
164
124
self.base = gitdir.root_transport.base
165
lazy_load_optimisers()
166
125
self._lock_mode = None
167
126
self._lock_count = 0
242
201
def reconcile(self, other=None, thorough=False):
243
202
"""Reconcile this repository."""
244
reconciler = RepoReconciler(self, thorough=thorough)
245
reconciler.reconcile()
203
from ..reconcile import ReconcileResult
204
ret = ReconcileResult()
248
208
def supports_rich_root(self):
289
249
:param lossy: Whether to discard data that can not be natively
290
250
represented, when pushing to a foreign VCS
252
from .commit import (
292
255
builder = GitCommitBuilder(
293
256
self, parents, config, timestamp, timezone, committer, revprops,
294
257
revision_id, lossy)
322
285
for (file_id, revision_id, identifier) in desired_files:
323
286
per_revision.setdefault(revision_id, []).append(
324
287
(file_id, identifier))
325
for revid, files in viewitems(per_revision):
288
for revid, files in per_revision.items():
327
290
(commit_id, mapping) = self.lookup_bzr_revision_id(revid)
328
291
except errors.NoSuchRevision:
341
304
obj = tree_lookup_path(
342
305
self._git.object_store.__getitem__, root_tree,
343
path.encode('utf-8'))
306
encode_git_path(path))
344
307
if isinstance(obj, tuple):
345
308
(mode, item_id) = obj
346
309
obj = self._git.object_store[item_id]
372
335
o = self._git.object_store[sha]
373
336
if not isinstance(o, Commit):
375
rev, roundtrip_revid, verifiers = mapping.import_commit(
376
o, mapping.revision_id_foreign_to_bzr)
377
yield o.id, rev.revision_id, roundtrip_revid
338
revid = mapping.revision_id_foreign_to_bzr(o.id)
379
341
def all_revision_ids(self):
381
for git_sha, revid, roundtrip_revid in self._iter_revision_ids():
383
ret.add(roundtrip_revid)
343
for git_sha, revid in self._iter_revision_ids():
388
347
def _get_parents(self, revid, no_alternates=False):
438
397
this_parent_map[revid] = parents
439
398
parent_map.update(this_parent_map)
441
for values in viewvalues(this_parent_map):
400
for values in this_parent_map.values():
442
401
pending.update(values)
443
402
pending = pending.difference(parent_map)
444
403
return _mod_graph.KnownGraph(parent_map)
478
437
commit = self._git.object_store.peel_sha(foreign_revid)
479
438
if not isinstance(commit, Commit):
480
439
raise NotCommitError(commit.id)
481
rev, roundtrip_revid, verifiers = mapping.import_commit(
482
commit, mapping.revision_id_foreign_to_bzr)
440
revid = mapping.get_revision_id(commit)
483
441
# FIXME: check testament before doing this?
485
return roundtrip_revid
487
return rev.revision_id
489
444
def has_signature_for_revision_id(self, revision_id):
490
445
"""Check whether a GPG signature is present for this revision.
536
491
(git_sha, mapping) = mapping_registry.revision_id_bzr_to_foreign(
538
493
except errors.InvalidRevisionId:
540
mapping = self.get_mapping()
542
return (self._git.refs[mapping.revid_as_refname(bzr_revid)],
545
# Update refs from Git commit objects
546
# FIXME: Hitting this a lot will be very inefficient...
547
pb = ui.ui_factory.nested_progress_bar()
549
for i, (git_sha, revid, roundtrip_revid) in enumerate(
550
self._iter_revision_ids()):
551
if not roundtrip_revid:
553
pb.update("resolving revision id", i)
554
refname = mapping.revid_as_refname(roundtrip_revid)
555
self._git.refs[refname] = git_sha
556
if roundtrip_revid == bzr_revid:
557
return git_sha, mapping
560
raise errors.NoSuchRevision(self, bzr_revid)
494
raise errors.NoSuchRevision(self, bzr_revid)
562
496
return (git_sha, mapping)
571
505
raise errors.NoSuchRevision(self, revision_id)
572
506
revision, roundtrip_revid, verifiers = mapping.import_commit(
573
commit, self.lookup_foreign_revision_id)
507
commit, self.lookup_foreign_revision_id, strict=False)
574
508
if revision is None:
575
509
raise AssertionError
576
510
# FIXME: check verifiers ?
612
546
raise ValueError('invalid revision id %s' % revision_id)
613
547
return GitRevisionTree(self, revision_id)
615
def get_deltas_for_revisions(self, revisions, specific_fileids=None):
616
"""Produce a generator of revision deltas.
618
Note that the input is a sequence of REVISIONS, not revision_ids.
619
Trees will be held in memory until the generator exits.
620
Each delta is relative to the revision's lefthand predecessor.
622
:param specific_fileids: if not None, the result is filtered
623
so that only those file-ids, their parents and their
624
children are included.
626
# Get the revision-ids of interest
627
required_trees = set()
628
for revision in revisions:
629
required_trees.add(revision.revision_id)
630
required_trees.update(revision.parent_ids[:1])
632
trees = dict((t.get_revision_id(), t) for
633
t in self.revision_trees(required_trees))
635
# Calculate the deltas
636
for revision in revisions:
637
if not revision.parent_ids:
638
old_tree = self.revision_tree(_mod_revision.NULL_REVISION)
640
old_tree = trees[revision.parent_ids[0]]
641
new_tree = trees[revision.revision_id]
642
if specific_fileids is not None:
643
specific_files = [new_tree.id2path(
644
fid) for fid in specific_fileids]
646
specific_files = None
647
yield new_tree.changes_from(
648
old_tree, specific_files=specific_files)
650
549
def set_make_working_trees(self, trees):
651
550
raise errors.UnsupportedOperation(self.set_make_working_trees, self)