Git missing blob isn't really missing

Viewed 568

A colleague showed me an issue with its bare repository

git fsck --full
error: corrupt loose object 'e82fe20e35ac4cda5dad3369abf3984d6280224d'
error: unable to unpack contents of 
    ./objects/e8/2fe20e35ac4cda5dad3369abf3984d6280224d
error: e82fe20e35ac4cda5dad3369abf3984d6280224d: object corrupt or missing: 
    ./objects/e8/2fe20e35ac4cda5dad3369abf3984d6280224d
Checking object directories: 100% (256/256), done.
Checking objects: 100% (5451/5451), done.
dangling blob ca82c960c8e2be046bac1b172cef6a8e14142d53
dangling blob a308c3c7ba71d04477768ff7a6c2c4ea1d9d1c3c
dangling commit d0cbfeada696c5e2686b3a9831a8fdb832675b79
dangling blob 8b92c1a1c85088043dff200ce42a4f7bf543f9b0
dangling commit 3d930dc778c0aabef397063a60d58dcbba7dd094
dangling blob 2c2159b5181c4b3c3ab5ed0216726f6d9bf9a04f
dangling blob 732d6bde83d2605aa9e9872a90d89482fd03662e
missing blob e82fe20e35ac4cda5dad3369abf3984d6280224d
dangling blob 2b70f7cc74ffed4fa51b8630ac9afafafd1d3853
dangling blob 2479f96766eecc50420b36b64ed9746f0f26eee8
dangling blob 64fb11950ff0def78d5b38b34c0a8e5bbc48942f

Curiously the file is there:

ls -al objects/e8/2fe20e35ac4cda5dad3369abf3984d6280224d
-rw-r--r-- 1 root root 9809893 Feb 16 22:43 objects/e8/2fe20e35ac4cda5dad3369abf3984d6280224d

And when I try to get the original file from my colleague I get the correct hash:

git hash-object -w foo.pdf
e82fe20e35ac4cda5dad3369abf3984d6280224d

Why does Git still complain about this missing blob and how to fix it?

EDIT

It seems the content of ./objects/e8/2fe20e35ac4cda5dad3369abf3984d6280224d isn't a zlib file. I get an error when I try to inflate it.

So I rm the object and regenerated the object with hash-object -w. This time everything is fine. I saved the repository.

However, I don't understand how what happened. The two blobs are very different one looks like a PDF the other is apparently nothing :

enter image description here

2 Answers
error: e82fe20e35ac4cda5dad3369abf3984d6280224d: object corrupt or missing: 
    ./objects/e8/2fe20e35ac4cda5dad3369abf3984d6280224d

"object corrupt or missing". The file is there, but its checksum does not match the filename.

And when I try to get the original file from my colleague I get the correct hash

The checksum of your colleague's file matches its filename.

how to fix it?

Copy your colleague's file to your repository.

However, I don't understand how what happened.

It's a file on disk, any number of things could have happened. A disk error. An overzealous anti-virus. A bug in Git.

One major culprit would be if your repository is on any sort of shared drive such as Dropbox. A Git repo cannot be safely used on a shared drive.

  • Run a check on your disk.
  • Make sure Git is up to date.
  • Check your anti-virus didn't try to protect you against your Git repo.
  • Move your repo off a shared drive.
  • If your repo is on Dropbox, use git-remote-dropbox.

Note the error message evolves and is more precise with Git 2.34 (Q4 2021), "git fsck"(man) has been taught to report mismatch between expected and actual types of an object better.

See commit 96e41f5, commit 31deb28, commit dccb32b, commit 5848fb1, commit 3b6a8db, commit 01cab97, commit ddb3474, commit bfff2c4, commit 74ad250, commit dd45a56, commit 7e7d220, commit 59b8283, commit 70e4a57, commit a5ed333, commit 42cd635, commit f7a0dba, commit 093fffd (01 Oct 2021) by Ævar Arnfjörð Bjarmason (avar).
(Merged by Junio C Hamano -- gitster -- in commit 061a21d, 25 Oct 2021)

fsck: report invalid object type-path combinations

Signed-off-by: Ævar Arnfjörð Bjarmason

Improve the error that's emitted in cases where we find a loose object we parse, but which isn't at the location we expect it to be.

Before this change we'd prefix the error with a not-a-OID derived from the path at which the object was found, due to an emergent behavior in how we'd end up with an "OID" in these codepaths.

Now we'll instead say what object we hashed, and what path it was found at.
Before this patch series e.g.:

$ git hash-object --stdin -w -t blob </dev/null
e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
$ mv objects/e6/ objects/e7

Would emit ("[...]" used to abbreviate the OIDs):

git fsck
error: hash mismatch for ./objects/e7/9d[...] (expected e79d[...])
error: e79d[...]: object corrupt or missing: ./objects/e7/9d[...]

Now we'll instead emit:

error: e69d[...]: hash-path mismatch, found at: ./objects/e7/9d[...]

Furthermore, we'll do the right thing when the object type and its location are bad.
I.e.
this case:

$ git hash-object --stdin -w -t garbage --literally </dev/null
8315a83d2acc4c174aed59430f9a9c4ed926440f
$ mv objects/83 objects/84

As noted in an earlier commits we'd simply die early in those cases, until preceding commits fixed the hard die on invalid object type:

$ git fsck
fatal: invalid object type

Now we'll instead emit sensible error messages:

$ git fsck
error: 8315[...]: hash-path mismatch, found at: ./objects/84/15[...]
error: 8315[...]: object is of unknown type 'garbage': ./objects/84/15[...]

In both fsck.c and object-file.c we're using null_oid as a sentinel value for checking whether we got far enough to be certain that the issue was indeed this OID mismatch.

This will make the fix easier to apply.

Related