Git never forgets. Every commit is content-addressed: change a file, and the old version remains stored in history forever — or until you rewrite history itself. That's why the standard "delete the line, commit, push" flow fixes nothing for anyone willing to run git log -p. This walkthrough covers the complete purge, in the correct order.
Step 0: Revoke the credential
Before touching history, kill the key at its provider. History rewrites take time; a live key keeps working the whole way. Revoke first, clean second, always. If you need the full incident sequence, start with API Key Leaked? Here's What to Do.
Step 1: Find every occurrence
Before rewriting, know exactly what you're removing. Search all history for the secret and its variants:
The variants matter. The key itself, yes — but also any placeholder, encoded form, or secondary credential that leaked alongside it.
Step 2: Rewrite history with git filter-repo
git filter-repo is the modern tool for this job — fast, safe, and it replaces both the deprecated filter-branch and the BFG for most purges. Install it, clone a fresh copy of the repo, and replace the secret everywhere:
The --replace-text file maps literal strings to replacements and applies them across every commit, branch, and tag. For deleting entire files — an accidentally committed .env — use --path .env --invert-paths to drop the file from history altogether.
Step 3: Force-push and coordinate
Rewriting history invalidates every clone. Push the rewritten refs, then tell the team: everyone re-clones, nobody force-pulls their local copy back over yours. Forks — GitHub forks included — are separate repositories with the old history and must be handled individually. If the secret was public, treat every fork and cache as compromised.
Step 4: Verify like an attacker
After the rewrite, scan the remote history exactly the way an attacker would:
If the scan still finds it — in a tag, a stale branch, an old remote — it's still exposed. Keep rewriting until nothing matches.
Why prevention beats purges
Purging history is the painful, disruptive fix. The cheap fix happens before the commit exists: a pre-commit scan that catches the secret while it's still a keystroke, push protection that blocks it if it slips through, and continuous history scanning that surfaces leaks the day they land — not the day an attacker finds them. Layered together, the next purge you perform will be someone else's. Vooda covers all three layers from a single self-hosted platform; the scan commands above are the real CLI.
Frequently asked questions
Does deleting a secret from the current code remove it from git history?
No. Git keeps every version of every file. A secret committed three years ago is still readable in that old commit until history itself is rewritten with a tool like git filter-repo.
Should I revoke the secret before rewriting git history?
Yes, always revoke first. Rewriting history takes time, and the credential keeps working the whole way. Kill it at the provider, then clean the repository.
What is the best tool to remove a secret from git history?
git filter-repo is the recommended modern tool — fast, safe, and maintained. It replaces filter-branch and the BFG for most purges, including string replacement across all history, branches, and tags.
Does force-pushing rewritten history affect other developers?
Yes. Every clone, fork, and local copy has the old history and must be re-cloned or reset. Coordinate before rewriting shared history, and re-check the remote afterward.
How do I verify the secret is really gone from git history?
Run a scanner across the rewritten history the way an attacker would. If it finds the credential in any commit, branch, or tag, it is still exposed.