← Todas las noticias
security3 min de lectura

Deleting a committed .env file doesn't remove it from git history

Por Seaworthy · 2 de septiembre de 2026

Illuminated street light pole with tangled electrical wires at night

Photo by Gilang Cipta Permana on Unsplash

At some point in nearly every project's history, someone runs git add . before .gitignore has a line for .env, and a file full of API keys and database URLs gets committed. Usually it's caught fast: a teammate notices, a follow-up commit deletes the file, .env gets added to .gitignore, and the branch moves on. The keys are gone from the working tree, so the problem looks solved.

Deleting the file doesn't delete the commit

git rm .env
git commit -m "remove env file"

This removes .env from the current state of the repository. It does nothing to the earlier commit where the file was added, which is still sitting in the repository's history with the full contents intact. Anyone with clone access, right now or at any point in the future, can run:

git log --all --full-history -- .env
git show <commit-hash>:.env

and read exactly what was in it, including whatever secrets were live at the time. If the repository is public, that's anyone on the internet. If it's private, it's every current and former collaborator, every CI system with clone access, and every fork made before the cleanup commit.

The only real fix is rotation, not history

Once a secret has been committed, even briefly, treat it as compromised and rotate it: generate a new API key, a new database password, a new signing secret, and revoke the old one at the provider. This is true even if you're fairly confident no one saw it. "Fairly confident" isn't a security property, and rotation is cheap compared to the alternative.

Rewriting git history to strip the file out, with git filter-repo or BFG Repo-Cleaner, is worth doing for hygiene, but it doesn't undo an exposure that already happened. Anyone who cloned or fetched before the rewrite still has the old commits locally, and a force-push doesn't reach into their machine and remove them. History rewriting is cleanup, not a substitute for rotating the credential.

Stop it from happening again with a pre-commit check

# .gitignore, from the start of the project
.env
.env.local
.env.*.local

A .gitignore entry only protects files that were never tracked. If .env was committed even once early on, adding it to .gitignore later does not untrack it automatically, git rm --cached .env is still required, or the file keeps getting picked up by future commits despite the ignore rule.

A pre-commit hook that scans staged changes for high-entropy strings and known key formats catches this before it reaches a commit at all, which is a better position to be in than catching it in a code review after the branch is already pushed:

npx --yes gitleaks protect --staged

Check what's actually in your history right now

If you've never checked, it's worth running a history-wide secret scan once, rather than assuming your project is fine because you don't remember committing anything sensitive:

npx --yes gitleaks detect --source . --report-path gitleaks-report.json

Old commits from before anyone on the current team joined are a common source of surprises here.

Seaworthy scans committed history, not just the working tree, for exposed secrets.

Este artículo fue generado por IA y resume fuentes públicamente disponibles.

De los creadores de Seaworthy

Seaworthy analiza tu repositorio en busca de los problemas que se tratan en artículos como este.

Brechas de seguridad, secretos expuestos y configuraciones erróneas detectados antes de desplegar. Gratis, sin cuenta necesaria.

$ npx seaworthycode