Tracking a pattern today does nothing for the 18 MiB already in experiment/covers. git lfs migrate rewrites history: info reports what is big, and import replaces matching files with pointers in every commit:
git switch -q experiment/covers
git lfs migrate info
git lfs migrate import --include="public/covers/*.png"
git reflog expire --expire-unreachable=now --all && git gc -q --prune=now
git count-objects -vH | grep -E "^size-pack"; du -sh .git/lfs/objects
git switch -q main... *.png 19 MB 12/12 files 100% *.json 39 KB 3/3 files 100% *.js 11 KB 4/4 files 100% *.html 3.7 KB 2/2 files 100% *.md 1.7 KB 1/1 file 100% ... Rewriting commits: 100% (4/4), done. ... size-pack: 56.81 KiB 19M .git/lfs/objects
By default migrate rewrites only the current branch, and only commits that exist on no remote: the four local commits of experiment/covers, which got new hashes and a .gitattributes line. Expiring the reflog let gc drop the old blobs, taking the pack from 18 MiB to 57 KiB. A published branch needs --everything or --include-ref, a force-push and fresh clones for everyone (Never Rebase Shared History). To purge secrets instead, use git filter-repo 13,338 (github.com/newren/git-filter-repo (https://github.com/newren/git-filter-repo 13,338 )).