Skip to main content

Module gitclean

Module gitclean 

Source
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 = true performs 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 new HEAD.

§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 in PurgeReport::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 .git until a repack+prune. gix 0.84 has no stable high-level repack API, so git gc --prune=now (or git 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_reclaimed is 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§

BlobStat
One blob’s aggregate stats in ScanReport.
PurgeOptions
Options for purge_paths.
PurgeReport
Result of purge_paths (identical shape for dry-run and apply).
ScanReport
Read-only scan result from scan_blobs.

Functions§

purge_paths
Deep-clean: strip opts.paths from every commit across every ref.
scan_blobs
Read-only blob scan over ALL reachable history — “what would a clean reclaim”.