Rewrite git history using git-filter-repo (not filter-branch)
View on GitHubSelect agents to install to:
npx add-skill https://github.com/cowwoc/cat/blob/main/plugin/skills/git-rewrite-history/SKILL.md -a claude-code --skill git-rewrite-historyInstallation paths:
.claude/skills/git-rewrite-history/# Git Rewrite History Skill
**Purpose**: Safely rewrite git history using `git-filter-repo`, the modern replacement for
`git filter-branch`.
## Why git-filter-repo over git-filter-branch
**Always use `git-filter-repo` instead of `git filter-branch`**. Git itself warns against filter-branch:
> git-filter-branch has a glut of gotchas generating mangled history rewrites.
> Use git-filter-repo instead.
| Feature | git-filter-repo | git-filter-branch |
|---------|-----------------|-------------------|
| Speed | 10-50x faster | Slow |
| Safety | Handles edge cases | Many gotchas |
| Maintenance | Actively maintained | Deprecated |
| Syntax | Simple, intuitive | Complex, error-prone |
## Installation
```bash
pip install git-filter-repo
# or
pip install --break-system-packages git-filter-repo
```
## Safety Pattern: Backup-Verify-Cleanup
**ALWAYS follow this pattern:**
1. **Work on a fresh clone** (filter-repo requires this by default)
2. Create backup of original remote URL
3. Execute the filter operation **with `--partial`** (preserves reflog for recovery)
4. **Verify immediately** - check history is correct
5. Force push only after verification and explicit user approval
### MANDATORY: Always Use --partial Flag
**Always include the `--partial` flag with git-filter-repo**. Without it:
- Reflog is expired (old commits unrecoverable)
- Automatic `git gc` runs (objects permanently deleted)
- No recovery possible after force-push
With `--partial`:
- Old commits preserved in reflog
- Recovery via `git reset --hard HEAD@{n}` possible
- New history is active, old history available as fallback
## Common Operations
### Remove a File from All History
```bash
# Fresh clone required
git clone --mirror <url> repo-filter
cd repo-filter
# Remove file (--partial preserves reflog for recovery)
git filter-repo --partial --path secrets.txt --invert-paths
# Verify
git log --all --oneline -- secrets.txt # Should return nothing
# If wrong, recover: git reflog && git reset --