Git race with geometric repack hides objects from live readers
Elijah Newren fixes multi-pack-index lookups that treat present objects as missing when a concurrent repack retires their owning pack, plus a replay crash and mktree --batch bugs.
Git can spuriously report objects as missing when a long-running process races with a geometric repack that rewrites the multi-pack-index (MIDX). Elijah Newren has posted fixes so lookups recover instead of failing, and so a few related callers stop crashing or giving wrong answers.
The failure window is tiny, but Newren cites evidence from production across at least eight server-side operations and seven commands. Merge-tree, diff, rev-list, merge-base, rev-parse, cat-file, fsck, and repack can all hit a read miss even though a copy of the object still exists elsewhere. Paths that do not hard-error can still misbehave: upload-pack may drop a client's common "have" during negotiation and send more data than needed, and batch cat-file can claim objects do not exist.
A MIDX attributes each object to exactly one owning pack. After geometric repack writes a new pack and index and deletes the packs it subsumed, a process still holding the old MIDX keeps routing those objects to a pack that is gone. Reloading the on-disk pack set does not refresh the cached MIDX, and the normal fallback deliberately skips every MIDX-covered pack, so a surviving duplicate stays hidden. The fix makes MIDX lookup report "owner unavailable" separately from "not in the index," then on a second read scan the remaining MIDX packs for a live copy. Full invalidation of a borrowed stale MIDX is left for later as a larger change. Deferring pack deletion with multi-pack-index expire is noted as a complementary way to hit the race less often.
Separately, git replay could SIGSEGV when merge inputs were unreadable: the merge machinery already signals failure, but replay only tested the clean/conflict bit and then dereferenced a null tree. That path now fails with an error. Git mktree --batch was also corrected: it no longer uses a QUICK object lookup that accepts false negatives across a concurrent repack (it still skips promisor fetches), and it frees per-tree entry allocations it previously leaked across batch iterations. Jeff King pushed back on broadening QUICK recovery in general, arguing false negatives are intentional for callers such as upload-pack; the revised series leaves that contract alone and only stops mktree from opting in.