Codex turn-diff checkpoint blobs silently consume 100+ GB disk space
Summary
Codex Desktop creates refs/codex/turn-diffs/checkpoints/ refs that store full project tree snapshots as git objects. On projects with large files (databases, models, binary artifacts), these checkpoint blobs accumulate without any garbage collection, silently consuming massive disk space.
In my case: 102 GB of orphan git objects accumulated in a single project ~/.git/objects/ directory, bringing total project size from ~5.7 GB to ~140 GB.
Version
- Codex Desktop 26.616.51431 (App Store build 4212)
- Codex CLI 0.80.0
- macOS Darwin 27.0.0 arm64
Impact
Disk exhaustion. Unlike #28241 which reports that turn-diff refs break libgit2 clients, this issue focuses on the disk space bomb created by the underlying git objects.
Reproduction
- Open a project directory with Codex Desktop where the project contains large files (e.g.,
.db,.bin,.sqlite, model weights, node_modules, etc.) - Use Codex normally for several sessions
- Observe
.git/objects/growing unboundedly
What Happened
My ~/project directory (a trusted Codex project) accumulated:
$ git count-objects -vH
count: 8476
size: 101.86 GiB <-- 8476 loose objects totaling 102 GB
in-pack: 6459
packs: 1
size-pack: 4.64 MiB
The repo had zero commits and zero staged files — all 8476 loose objects were orphans. 429 of them were individual blobs exceeding 100 MB each (largest ~244 MB), all binary content.
The only refs were Codex checkpoint refs:
refs/codex/turn-diffs/checkpoints/dc36a859.../.../476a1d45-...
refs/codex/turn-diffs/checkpoints/e31f75308.../.../99b0aa92-...
Root Cause Analysis
Based on source code review of codex-rs/git-utils/src/baseline.rs:
write_tree()recursively walks the entire project directory- For every file, it calls
repo.write_blob(bytes)— writing the full file content as a git loose object - This happens on every checkpoint/capture operation
- Large binary files (databases, model weights, etc.) each become 100MB+ loose objects
- No garbage collection or pruning is performed after checkpoints are superseded
- Git default
gc.pruneExpireis 2 weeks, but Codex never triggersgit gcorgit prune
The same write_blob behavior appears in current_file_entries() which also reads every file into memory to compute blob OIDs for diffing.
Workaround
# Nuclear: delete .git and reinitialize
rm -rf .git && git init
# Or: prune orphan objects
git gc --prune=now
After cleanup: 140 GB → 5.7 GB.
Suggested Fixes
- Add
.gitignoreawareness: Thewrite_tree()function inbaseline.rsskips.gitbut nothing else. It should respect the project.gitignoreto avoid writing blobs fornode_modules/,.dbfiles, model weights, etc.
- Size limits: Skip files above a configurable size threshold (e.g., 10 MB) when writing checkpoint blobs.
- Garbage collection: After creating new checkpoints, prune old/superseded checkpoint refs and their unreachable objects.
- Use separate git repo: Store checkpoints in a separate bare repo under
~/.codex/(similar to howcodex-rs/memories/usescodex_home/memorieswith its own git baseline), rather than polluting the user project.git/objects/.
- Dont write blobs for diff computation: The test
status_scan_does_not_write_added_file_blobsexplicitly verifies diff scans do not write objects, butwrite_tree()does. The checkpoint path should use hash-only approach.
Related Issues
- #28241 — turn-diff refs break libgit2-based Git clients (same
refs/codex/turn-diffs/mechanism) - #28750 — Codex.app repeatedly runs
git add -Afilling.git/objects/pack(same disk space impact, different mechanism) - #19588 — Ghost snapshot runs
git add -Aon trusted home directory (same root cause: uncontrolled git object creation) - #12644 — Excessive file I/O from Codex scanning
2 Comments
Potential duplicates detected. Please review them and close your issue if it is a duplicate.
Powered by Codex Action
We hit the same shape of problem (multi-GB
.git/objectswithgit statusclean) from a different writer — large files that entered the object store and were never referenced by any commit — and can offer the diagnosis + safe-reclaim recipe that worked, with numbers.Confirm what the space actually is — two independent measurements that should agree:
If you want the set-difference proof:
git cat-file --batch-all-objects --batch-checkminusgit rev-list --objects --allgives you exactly the orphans. In our case: 4.3GB.git, of which 4.20GB was 5,050 unreachable blobs; only 9.9MB of loose objects were reachable. The largest unreachable blobs exactly size-matched files still in the working tree — i.e. the content was duplicated into the object store, not unique data at risk.Before pruning, check nothing you need lives only in the object store:
Reclaim:
Result for us:
.git4.3GB → 6.5MB,git fsckclean afterwards, HEAD and all working-tree files intact. The reason the space survives normal operation isgc.pruneExpire's two-week grace period for loose objects — orphans younger than that are deliberately kept.Caveats for this issue specifically: this reclaims the 102GB but won't stop Codex from re-creating snapshots — that half is genuinely upstream's to fix. And if you want a tripwire while waiting: alert on
git count-objects -vloose size, which catches the accumulation long before it's 102GB.