How to Remove a Secret From Git History

A committed .env file with an AWS_SECRET_ACCESS_KEY lives in every commit from that point forward - not just the working tree. Removing it means rewriting history with git filter-branch (or git filter-repo), then deleting the backup refs git leaves behind. Here's the full procedure.

Security Engineergitsecuritysecrets

Why deleting the file is not enough

Running git rm .env && git commit removes the file from the working tree and the next commit's tree, but every earlier commit still contains it. Anyone who clones the repo, runs git log -p, or checks out an old ref gets the plaintext secret. Git history is a linked chain of snapshots - to scrub a file you have to rewrite every snapshot that contains it.

Step 1: prevent re-commit with .gitignore

Before rewriting anything, make sure the file cannot come back:

echo ".env" >> .gitignore
git add .gitignore
git commit -m "chore: gitignore .env"

Step 2: rewrite history with git filter-branch

git filter-branch --index-filter runs a command against every commit's index (the staging area) without checking files out to disk - much faster than --tree-filter:

git filter-branch --force \
    --index-filter "git rm --cached --ignore-unmatch .env" \
    --prune-empty -- --all

Step 3: delete the backup refs git left behind

git filter-branch saves the original commits under refs/original/ so you can undo. Those refs still point at history containing the secret, so drop them:

git for-each-ref --format="%(refname)" refs/original/ \
    | xargs -n 1 git update-ref -d

Then verify the secret is gone from all reachable history:

git log --all -p | grep AWS_SECRET_ACCESS_KEY
# should print nothing

What to do if the secret already pushed

History rewriting on a remote repo is destructive: every collaborator's clone still has the old history. If the commit was pushed to a public or shared remote:

  1. Rotate the key immediately - treat it as compromised, full stop.
  2. Force-push the rewritten history: git push --force --all (coordinate with the team first).
  3. Ask collaborators to re-clone or run git pull --rebase against the new history.

Prefer git filter-repo for real incidents

git filter-branch is slow on large repos and has sharp edges. The community tool git filter-repo (a single Python script) is faster, safer, and more explicit - it is now the recommended approach in the git documentation:

pip install git-filter-repo
git filter-repo --path .env --invert-paths

Either way, rotate the secret - history scrubbing removes it from future clones, not from anyone who already has it.

Want to try it hands-on? HeyDevJob gives you this exact setup in a live cloud workspace in your browser - edit it, run it, and see it work. Free, nothing to install.

Try it in a workspace →

What you'll practice

FAQ

How do I remove a file from all git history?

Use git filter-branch --index-filter 'git rm --cached --ignore-unmatch <file>' --prune-empty -- --all to rewrite every commit, then delete the backup refs under refs/original/ with git for-each-ref | xargs git update-ref -d. Verify with git log --all -p | grep <secret>.

Does git rm remove a file from history?

No. git rm removes the file from the working tree and the next commit, but the file still exists in every earlier commit. You need to rewrite history with git filter-branch or git filter-repo to remove it from past commits.

What are refs/original/ in git filter-branch?

git filter-branch saves the original (pre-rewrite) commit SHAs under refs/original/ so you can undo. If you're scrubbing a secret, these refs still point at history containing the plaintext - you must delete them with git update-ref -d after confirming the rewrite worked.

Keep learning

Close a SQL Injection in a Search EndpointSecurity projectNeutralize a Stored XSS in CommentsSecurity projectRemove Hardcoded Credentials From Source CodeSecurity projectSecurity roadmapStep by step to hiredSecurity interview questionsSTAR answersAll Security projectsProjects hub

Learn it by doing. Open this in a live cloud workspace, make the change yourself, and keep a record of the work you can share.

Open the workspace →