Expand description
§gitclean — pure-Rust git-history deep-clean over gix (gitoxide)
The pure-Rust analogue of git filter-repo --invert-paths --path <p>:
remove one or more paths (e.g. a committed docs/book.pdf) from every
commit across every ref of a repository, rewriting history in place — no
git/git-filter-repo subprocess, no Python, no C. Everything runs through
gix 0.84 plumbing (gix::open, ref iteration, commit/tree reading, the
tree-editor for tree rebuild, write_object for new commits, and
edit_references for the ref repoint).
Two modes, both exposed as a reusable library fn so they are unit-testable without the CLI:
scan_blobs— read-only. Walk all refs + their ancestry, enumerate every blob and its size, and report the N largest (size, an example path, how many commits reference it) + the total.--path <glob>narrows the report.purge_paths— the deep clean. Default is a dry-run (report only);apply = trueperforms the rewrite: back up the original ref SHAs, rewrite every commit parents-first with the target path(s) stripped from its tree (subtrees that become empty are dropped by the tree editor), remap parents through the old→new map, then repoint every branch/lightweight-tag ref to the rewritten tip and leave the worktree consistent with the newHEAD.
§Honest seams
- Annotated tags (
refs/tags/*that point at a tag object, not a commit directly) are traversed for reachability but not repointed — the tag object still references the old commit. They are reported inPurgeReport::annotated_tags_skipped. Lightweight tags (direct-to-commit) ARE repointed like branches. - On-disk GC — the rewrite makes the old objects unreachable, but the
loose/packed objects still occupy
.gituntil a repack+prune. gix 0.84 has no stable high-level repack API, sogit gc --prune=now(orgit reflog expire --expire=now --all && git gc --prune=now) finalizes the on-disk reclamation. The history is rewritten regardless; only the byte savings on disk wait for GC.PurgeReport::bytes_reclaimedis the exact size of the now-unreachable blobs. - Reflogs — old reflog entries still pin the pre-rewrite commits; expiring
them (
git reflog expire --expire=now --all) is part of the same GC seam. - Empty commits are NOT pruned — a commit whose only content was the purged path is kept (with an empty/parent-equal tree) so the commit count is preserved. (Documented rather than defaulted-on to avoid surprising history shape changes.)
Structs§
- Blob
Stat - One blob’s aggregate stats in
ScanReport. - Purge
Options - Options for
purge_paths. - Purge
Report - Result of
purge_paths(identical shape for dry-run and apply). - Scan
Report - Read-only scan result from
scan_blobs.
Functions§
- purge_
paths - Deep-clean: strip
opts.pathsfrom every commit across every ref. - scan_
blobs - Read-only blob scan over ALL reachable history — “what would a clean reclaim”.