diff --git a/cinnabar/githg.py b/cinnabar/githg.py index 592735b2b..01b049bce 100644 --- a/cinnabar/githg.py +++ b/cinnabar/githg.py @@ -601,6 +601,7 @@ def __init__(self): self._replace = Git._replace self._tagcache_ref = None self._metadata_sha1 = None + broken = None # While doing a for_each_ref, ensure refs/notes/cinnabar is in the # cache. for sha1, ref in Git.for_each_ref('refs/cinnabar', @@ -613,6 +614,10 @@ def __init__(self): self._metadata_sha1 = sha1 elif ref == b'refs/cinnabar/tag_cache': self._tagcache_ref = sha1 + elif ref == b'refs/cinnabar/broken': + broken = sha1 + self._broken = broken and self._metadata_sha1 and \ + broken == self._metadata_sha1 self._replace = VersionedDict(self._replace) self._tagcache = {} @@ -1246,6 +1251,7 @@ def close(self, refresh=()): ) as commit: for sha1, target in util.iteritems(self._replace): commit.filemodify(sha1, target, b'commit') + self._metadata_sha1 = commit.sha1 for c in self._tagcache: if c not in changeset_heads: @@ -1326,6 +1332,7 @@ def tagset_lines(tags): bundle = "Please keep a copy of the " bundle += os.environ["GIT_DIR"] + "/cinnabar-last-bundle file" bundle += " before doing the following.\n" + Git.update_ref(b'refs/cinnabar/broken', self._metadata_sha1) raise Abort( "It seems you have hit a known, rare, and difficult to " "reproduce issue.\n" diff --git a/cinnabar/remote_helper.py b/cinnabar/remote_helper.py index 2d9536185..a5af45362 100644 --- a/cinnabar/remote_helper.py +++ b/cinnabar/remote_helper.py @@ -383,6 +383,10 @@ def list(self, arg=None): self._helper.flush() def import_(self, *refs): + if self._store._broken: + raise Abort('Cannot fetch with broken metadata. ' + 'Please fix your clone first.\n') + # If anything wrong happens at any time, we risk git picking # the existing refs/cinnabar refs, so remove them preventively. for sha1, ref in Git.for_each_ref('refs/cinnabar/refs/heads', @@ -470,11 +474,16 @@ def push(self, *refspecs): pushes = list((Git.resolve_ref(fsdecode(s.lstrip(b'+'))), d, s.startswith(b'+')) for s, d in (r.split(b':', 1) for r in refspecs)) - if not self._repo.capable(b'unbundle'): + if self._store._broken or not self._repo.capable(b'unbundle'): for source, dest, force in pushes: - self._helper.write( - b'error %s Remote does not support the "unbundle" ' - b'capability\n' % dest) + if self._store._broken: + self._helper.write( + b'error %s Remote does not support the "unbundle" ' + b'capability\n' % dest) + else: + self._helper.write( + b'error %s Cannot push with broken metadata. ' + b'Please fix your clone first.\n' % dest) self._helper.write(b'\n') self._helper.flush() else: