Writing
Checking Git disk usage after working with Codex
How I reduced Git storage from about 7 GiB to 611 MiB by checking Codex snapshots, cleaning temporary packs, and pruning unreachable objects.
On this page
To check how much space Git is using, run these two commands inside your repository:
du -sh "$(git rev-parse --git-common-dir)"
git count-objects -vH
My repository’s .git directory was about 7 GiB. Removing 58 abandoned temporary pack files reclaimed 3.44 GiB, leaving about 3.4 GiB. Removing unreachable objects then brought it down to 611 MiB.
Read the storage breakdown
In the output from git count-objects, look for:
size-pack: space used by packed Git objects.size: space used by loose objects.garbage: the number of files Git does not recognise as valid object storage.size-garbage: the space those files occupy.
My warnings named files such as .git/objects/pack/tmp_pack_…. These were temporary pack files. Their presence was consistent with interrupted packing operations; I did not establish what interrupted them.
Codex snapshots can include untracked files
Codex can store snapshots of files you have never added or committed to Git. That means local files can occupy space inside .git even when they are absent from your branch history.
In my repository, Codex had stored snapshots under these references:
refs/codex/turn-diffs/captures/...
refs/codex/turn-diffs/checkpoints/...
You can check for them with:
git for-each-ref --format='%(objecttype) %(refname)' refs/codex
These references pointed to Git trees: stored directory snapshots. Their names indicate that they support tracking changes between turns. A Git worktree is a checkout directory; the snapshots we found were objects inside Git’s storage.
Git reuses identical file objects, while changed content can create new versions. In my case, snapshots included several versions of an untracked local database, each over 1 GiB before compression.
This makes .gitignore useful even for files you never intend to commit. After ignoring that database, I confirmed that newer Codex captures excluded it. Older snapshots still retained their copies.
Remove abandoned temporary packs
Before cleaning up, stop Codex sessions and other Git activity for the repository, including linked worktrees. Keep them stopped during cleanup. These commands work on macOS with lsof installed:
git_dir="$(git rev-parse --git-common-dir)"
lsof +D "$git_dir/objects/pack"
If lsof lists processes, wait for them to finish. No output normally means no open files were found; if it reports an error, resolve that first. This is a point-in-time check, so it cannot protect against another process starting afterwards.
List temporary pack files older than an hour:
find "$git_dir/objects/pack" -type f -name 'tmp_pack_*' -mmin +60 -print
Once you have reviewed that list and confirmed they are abandoned, the following command permanently deletes those matching temporary files. Age alone does not establish that a file is abandoned. Keep regular pack-*.pack files intact.
find "$git_dir/objects/pack" -type f -name 'tmp_pack_*' -mmin +60 -print -delete
Then run normal garbage collection and check the result:
git gc
git fsck --connectivity-only --no-dangling
du -sh "$git_dir"
git count-objects -vH
In my case, garbage and size-garbage became zero, and the connectivity check passed. The temporary-file removal produced the 3.44 GiB saving; git gc alone was not the whole cleanup.
Why unreachable objects remain
After that cleanup, .git was still 3.4 GiB.
About 2.84 GiB was unreachable data: stored objects no longer retained through references or reflogs. Git keeps recent unreachable objects for a grace period. This can help recover discarded work and protects objects another Git process may have written before attaching a reference to them.
Normal git gc uses a two-week expiry cutoff by default. In this repository it collected that data into a cruft pack, a pack for retained unreachable objects. A later collection can remove objects once they qualify for expiry. There is no background countdown that deletes them automatically.
Another roughly 0.59 GiB remained referenced, including Codex checkpoints. Ordinary branch, tag, and remote-tracking history accounted for only about 79 MiB of stored objects. Garbage collection preserves referenced data, even when it is an old database snapshot.
Remove unreachable objects now
To remove unreachable objects immediately, you can skip the age grace period. This permanently removes otherwise recoverable data. Stop Codex sessions and all other Git activity in the repository and its linked worktrees first; concurrent writes can risk corruption. Keep them stopped until collection finishes.
git gc --prune=now
This preserves objects retained by references and reflogs, including branches, tags, stashes, and Codex checkpoints. It does not remove those checkpoints.
Check the resulting size and connectivity:
du -sh "$(git rev-parse --git-common-dir)"
git count-objects -vH
git fsck --connectivity-only --no-dangling
The result
For this second cleanup, my du output went from:
3.4G .git
to:
611M .git
That reclaimed roughly another 2.8 GiB, on top of the 3.44 GiB from temporary files. The remaining storage includes referenced Codex snapshots as well as the repository’s ordinary history.