Next.js starter your AI actually understands. Ship internal tools in days not weeks. Pre-order $199 $499 → [Get it now]

How to rewrite Git history with git filter-repo

git filter-repo is the modern replacement for git filter-branch, rewriting repository history up to 50 times faster while providing a cleaner, safer interface with better defaults. As the creator of CoreUI with 25 years of open-source development experience, I switched all projects to git filter-repo the moment it became the officially recommended tool in Git documentation. It is not bundled with Git — install it separately — but its performance and safety features make it the clear choice for any history rewriting task. Always work on a fresh clone before running it, as the operation cannot be undone once complete.

Install git filter-repo and remove a specific file from all history.

# Install (macOS)
brew install git-filter-repo

# Install (pip)
pip install git-filter-repo

# Verify
git filter-repo --version
# Clone a fresh copy first (filter-repo refuses to run on repos with a remote unless forced)
git clone --no-local original-repo clean-repo
cd clean-repo

# Remove a specific file from entire history
git filter-repo --path secrets.env --invert-paths

--path secrets.env selects the file. --invert-paths inverts the selection — keep everything EXCEPT the specified path. The result is a repository where secrets.env never existed in any commit.

Remove a Directory from History

Delete an entire folder from every commit.

# Remove the dist/ directory from all commits
git filter-repo --path dist/ --invert-paths

# Remove multiple paths at once
git filter-repo \
  --path dist/ \
  --path node_modules/ \
  --path coverage/ \
  --invert-paths

Listing multiple --path options removes all of them in a single pass. This is much faster than running filter-branch separately for each path.

Remove Files by Pattern

Delete files matching a glob or regex.

# Remove all .env files
git filter-repo --path-glob '*.env' --invert-paths

# Remove all files matching a regex
git filter-repo --path-regex '.*\.(log|tmp|bak)$' --invert-paths

--path-glob uses shell glob syntax. --path-regex uses Python regex syntax. These are useful for removing all files of a certain type without listing each one individually.

Update Author Email Across History

Replace incorrect committer emails globally.

git filter-repo --email-callback '
  return email if email != b"[email protected]" else b"[email protected]"
'

The --email-callback receives and returns bytes. Python’s conditional expression a if condition else b makes the replacement concise. Similar callbacks exist for --name-callback, --message-callback, and --commit-callback for full control over every commit attribute.

Push the Rewritten History

Force-push all branches and tags after rewriting.

# Re-add the remote (filter-repo removes it by default)
git remote add origin https://github.com/user/repo.git

# Push all branches
git push origin --force --all

# Push all tags
git push origin --force --tags

git filter-repo removes all configured remotes as a safety measure to prevent accidental pushes. Re-add the remote explicitly and force-push after verifying the rewritten history looks correct with git log --oneline.

Best Practice Note

After pushing rewritten history, all collaborators must re-clone the repository — their local branches diverge from the rewritten history and cannot be cleanly merged. Coordinate with your team before running this operation. For the legacy approach when git filter-repo is not available, see how to rewrite Git history with filter-branch. For removing sensitive data specifically, GitHub and GitLab may also cache content in pull request diffs — contact their support to purge those caches after cleaning your history.


Speed up your responsive apps and websites with fully-featured, ready-to-use open-source admin panel templates—free to use and built for efficiency.


About the Author