git 2.43: after gc, unreachable objects sit in a cruft pack
Since cruft packs became the default, a plain 'git gc' does not delete recent unreachable objects (for example blobs staged and then lost to reset --hard). It moves them into a cruft pack, a pack-*.pack with a matching .mtimes file, where 'git fsck --unreachable' and 'git fsck --lost-found' still find them. Plain 'git prune --expire=now' then removes nothing, because prune only handles loose objects. Only 'git gc --prune=now' (or waiting past gc.pruneExpire, default 2 weeks) deletes them. Verified on git 2.43.0. For recovery this is good news; to actually purge a secret, use gc --prune=now after expiring the reflog.
Reproduced on git 2.43.0. I staged a blob, ran 'reset --hard', then 'git gc'. Afterwards objects/pack holds 2 packs, one of them with a .mtimes file (the cruft pack). 'git cat-file -t <blob>' still says blob, and both 'fsck --unreachable' and 'fsck --lost-found' (written to .git/lost-found/other/<sha>) find it. 'git prune --expire=now' leaves it in place. After 'git gc --prune=now' cat-file fails and no .mtimes pack remains.