Blog Post

Azure Infrastructure Blog
3 MIN READ

How to Safely Remove Secrets from Your Git History (The Right Way)

Sakshi_Gupta22's avatar
Oct 28, 2025

Accidental secret commits are one of the most common and most dangerous security mistakes in modern development.

A single leaked API key or connection string can give attackers persistent access long after you’ve deleted the file. The real challenge isn’t fixing the code — it’s cleaning the history.

This post walks through how to safely and permanently remove sensitive data from your Git history.

Why It’s Dangerous

When secrets — such as API keys, SSH private keys, OAuth tokens, or database credentials — are committed to a public or even private Git repository, the risks are serious:

  • Security breaches: Attackers can replay commit history to extract secrets.
  • Permanent exposure: Even if the file is deleted, it remains in Git history and GitHub forks/caches.
  • Automation risk: Compromised tokens can trigger, pipelines.

Deleting the file isn’t enough. You must rewrite Git history to remove it completely.

Step-by-Step Guide: Remove Secrets Using git filter-repo

Warning: History rewriting is destructive.
Always create a backup or clone before proceeding.
Coordinate with your team as everyone will need to re clone the repository after cleanup.

Step 1. Create a Safety Backup

Before touching your Git history, make a full backup. This gives you a restore point if anything goes wrong.

git clone https://github.com/org/repo.git repo-backup

Or download a ZIP snapshot from GitHub’s “Code → Download ZIP” menu.

Tip: Don’t skip this step. Once you rewrite history, the old commit hashes are gone forever.

Step 2. Prepare a Clean Mirror for Rewriting

You’ll use a mirror clone — a minimal, metadata-rich copy of your repository — ideal for surgical operations.

git clone --mirror https://github.com/org/repo.git repo-clean.git 
cd repo-clean.git

Step 3. Install git-filter-repo

git-filter-repo is the modern, fast, and officially recommended tool for rewriting Git history (it replaces the older git filter-branch).

Install:

brew install git-filter-repo        # macOS
pip install git-filter-repo         # Cross-platform

Step 4. Use git-filter-repo to Remove Secrets

Now, remove the sensitive file from every commit in your repository’s history.

git filter-repo --path "config/secrets.json" --invert-paths

If you’ve exposed multiple files, include each path:

git filter-repo --invert-paths --path ".env" --path "settings.py"

Why this works:
The --invert-paths flag deletes the file (or files) from every commit, ensuring no historical trace remains.

Step 5. Verify Remote Configuration

Check your repository’s remote URL — sometimes it’s lost during history rewriting.

git remote -v

If missing, re-add it:

git remote set-url origin https://github.com/org/repo.git

Step 6. Push the Clean History Back

Replace your remote history with the cleaned version.

git push --force --all 
git push --force --tags


All existing collaborators will need to re-sync their clones.
Communicate clearly before pushing.

Step 7. Refresh Your Local Clones

Every developer using this repo must re-sync after history rewriting.

cd repo git fetch origin git reset --hard origin/main

Tip: Never merge after a forced history rewrite — always hard reset to the updated branch.

Step 8. Verify That Secrets Are Gone

Confirm that no old commits still contain the sensitive file:

git log --all -- config/secrets.json

If it returns nothing, you’re clear. You can now safely delete the mirror repo:

rm -rf repo-clean.git

Final Thoughts and Key Takeaways

Rewriting Git history may feel risky, but git filter-repo makes it clean, fast, and reliable. It’s the simplest way to erase secrets for good and prevent long-term security exposure. That said — once a secret’s been committed, assume it’s compromised. Rotate it right away and revoke any old tokens or credentials.

  1. Rotate exposed keys immediately.
  2. Add. env and config files to .gitignore.
  3. Use secret scanning to catch issues early.
  4. Notify your team before force-pushing.
Updated Oct 28, 2025
Version 1.0
No CommentsBe the first to comment