fix git-annex repair false positive

Avoid treating refs/annex/last-index or other refs that are not commit
objects as evidence of repository corruption.

The repair code checks to find bad refs by trying to run `git log` on
them, and assumes that no output means something is broken.  But git log
on a tree object is empty.

This was worth fixing generally, not as a special case, since it's certainly
possible that other things store tree or other objects in refs.

Sponsored-by: Max Thoursie on Patreon
This commit is contained in:
Joey Hess 2022-05-04 11:32:23 -04:00
parent d0b1ecf464
commit 0406c33f58
No known key found for this signature in database
GPG key ID: DB12DB0FF05F8F38
4 changed files with 39 additions and 12 deletions

View file

@ -14,6 +14,8 @@ git-annex (10.20220323) UNRELEASED; urgency=medium
* rsync 3.2.4 broke backwards-compatability by preventing exposing
filenames to the shell. Made the rsync and gcrypt special remotes
detect this and disable shellescape. Closes: #1010397
* repair: Avoid treating refs/annex/last-index or other refs that
are not commit objects as evidence of repository corruption.
-- Joey Hess <id@joeyh.name> Mon, 28 Mar 2022 14:46:10 -0400

View file

@ -325,7 +325,11 @@ findUncorruptedCommit missing goodcommits branch r = do
- the commit. Also adds to a set of commit shas that have been verified to
- be good, which can be passed into subsequent calls to avoid
- redundant work when eg, chasing down branches to find the first
- uncorrupted commit. -}
- uncorrupted commit.
-
- When the sha is not a commit but some other git object, returns
- true, but does not add it to the set.
-}
verifyCommit :: MissingObjects -> GoodCommits -> Sha -> Repo -> IO (Bool, GoodCommits)
verifyCommit missing goodcommits commit r
| checkGoodCommit commit goodcommits = return (True, goodcommits)
@ -337,16 +341,23 @@ verifyCommit missing goodcommits commit r
, Param (fromRef commit)
] r
let committrees = map (parse . decodeBL) ls
if any isNothing committrees || null committrees
then do
void cleanup
return (False, goodcommits)
else do
let cts = catMaybes committrees
ifM (cleanup <&&> check cts)
( return (True, addGoodCommits (map fst cts) goodcommits)
, return (False, goodcommits)
)
-- git log on an object that is not a commit will
-- succeed without any output
if null committrees
then ifM cleanup
( return (True, goodcommits)
, return (False, goodcommits)
)
else if any isNothing committrees
then do
void cleanup
return (False, goodcommits)
else do
let cts = catMaybes committrees
ifM (cleanup <&&> check cts)
( return (True, addGoodCommits (map fst cts) goodcommits)
, return (False, goodcommits)
)
where
parse l = case words l of
(commitsha:treesha:[]) -> (,)

View file

@ -45,4 +45,4 @@ The bug is very easy to reproduce. This happens in a bigger repository of mine,
Using it daily, with small-sized repositories.
> [[fixed|done]] --[[Joey]]

View file

@ -0,0 +1,14 @@
[[!comment format=mdwn
username="joey"
subject="""comment 3"""
date="2022-05-04T15:06:31Z"
content="""
Thank you, your "Reproducible Example" worked for me to reproduce it!
Great work finding this and tracking down an easy way to reproduce it.
So the root of the problem is refs/annex/last-index,
which contains a tree object, not a commit object. That is unusual for a ref,
but git-annex has a good reason to record a tree's ref there.
Fixed
"""]]