| name | git-history-clean |
| description | This skill should be used when preparing a git repository for public release by stripping dev tooling artifacts (e.g. .beads/, .ralph-tui/, editor configs, CI caches) from entire git history. Also use when the user wants to remove tracked files from all commits, not just the working tree. Triggers on phrases like "clean history", "strip files from history", "prepare repo for publishing", or "remove X from all commits". |
Git History Clean
Overview
Strip tracked files and directories from entire git history before publishing. Uses git filter-repo to rewrite all commits, removing specified paths and dropping commits that become empty. Results in a clean history where the removed paths never existed.
Prerequisites
git filter-repo must be installed (brew install git-filter-repo on macOS, pip install git-filter-repo elsewhere)
- Working directory must be a git repository
- No uncommitted changes (stash or commit first)
Workflow
1. Audit: Identify paths to remove
Scan the full history for dev tooling artifacts that should not be published.
git log --all --name-only --pretty=format: | sort -u | head -100
Common candidates:
.beads/, .ralph-tui/ — task orchestration state
.claude/, .cursor/, .windsurf/ — agent/editor config
*.log, .env, credentials.json — secrets and logs
Confirm the list with the user before proceeding.
2. Run filter-repo
Build the command from the identified paths. Use --path for exact files, --path-glob for directories.
git filter-repo --invert-paths \
--path-glob '<dir>/*' \
--path '<file>' \
--prune-empty always \
--force
Key flags:
--invert-paths — remove (not keep) the listed paths
--prune-empty always — drop commits that become empty after removal
--force — required if the repo has a remote configured
This rewrites every commit. Commit hashes will change. The operation is irreversible on the rewritten repo (but the original can be recovered from a remote or backup).
3. Verify history is clean
Run all three checks. All must pass.
git log --all --name-only | grep -E '<pattern>' | wc -l
git log --all -p -- '<path1>' '<path2>'
git log --oneline | wc -l
Report the before/after commit count to the user.
4. Update .gitignore
Add every removed path to .gitignore to prevent re-tracking. Merge with existing entries — do not duplicate.
5. Build and test
Run the project's build and test commands to confirm nothing broke:
- Swift:
swift build && swift test
- Node:
npm run build && npm test
- Python:
pytest
- Go:
go build ./... && go test ./...
- Rust:
cargo build && cargo test
Only report success after all checks pass.
Important Warnings
- This rewrites history. All commit hashes change. Collaborators must re-clone.
- Back up first if there is no remote. The rewrite is irreversible locally.
- Force-push required if a remote exists:
git push --force-with-lease. Confirm with the user before pushing.
- Never run on a shared branch without explicit user approval.