CLI AI

Elimina una contraseña del historial de git

2026-06-01

Eliminar una contraseña del historial de git significa reescribir los commits que la contienen con git filter-repo --invert-paths --path <file>, y luego vaciar el reflog y ejecutar garbage collection para que los commits antiguos también desaparezcan de .git. Haz esto solo después de rotar la clave — un secreto filtrado se considera comprometido en el momento del commit, limpies o no el historial después. .gitignore y git rm --cached no afectan a los commits que ya existen.

1. Comprueba si el secreto sigue en el historial

clai
$ clai comprueba si esta clave sigue en algún lugar del historial del repositorio→ git log --all --oneline -S 'sk-live-abc123secret'0fb8c94 stop tracking .env4c1d9ff add app and env

-S busca commits donde cambió el número de apariciones de esa cadena — donde el secreto apareció y donde desapareció. Busca en todo el historial de todas las ramas, no en el árbol de trabajo.

2. Confirma que eliminarlo del índice no sirvió

clai
$ clai obtén el archivo .env del commit donde se añadió→ git show 4c1d9ff:.envAPI_KEY=sk-live-abc123secret

Ese es todo el problema en un solo comando. .env ya no está en el árbol de trabajo, está en .gitignore, y git rm --cached ya se ejecutó — y aun así cualquiera con un clon puede sacar el secreto con un solo comando. El commit sigue guardando todo el contenido.

3. Revisa en qué commits aparece la ruta

clai
$ clai muestra todos los commits que mencionan el archivo .env→ git log --all --oneline -- .env0fb8c94 stop tracking .env4c1d9ff add app and env

Esa es la lista de lo que hay que reescribir. Dos commits y te libras fácil. Doscientos repartidos en varias ramas y primero tienes que coordinarte con todo el equipo.

4. Primero rota, luego limpia

Un secreto que llegó a git hay que tratarlo como filtrado, sin excepciones. El repositorio puede haber sido clonado, forkeado, indexado por un bot o cacheado por CI antes de que notes el error. Revoca la clave y emite una nueva antes de tocar el historial: un historial limpio con una clave robada aún activa es peor que un historial desordenado con una clave ya revocada.

5. Reescribe el historial con la herramienta correcta

clai
$ clai elimina el archivo .env de todo el historial del repositorio→ git filter-repo --invert-paths --path .env⚠ DANGER — rewrites all history, every commit hash changes

git filter-repo es lo que recomienda el propio proyecto git. git filter-branch está obsoleto: es órdenes de magnitud más lento y puede corromper el repositorio en silencio si no tienes cuidado. BFG Repo-Cleaner es la otra opción: más rápido en repositorios grandes, y puede sustituir una cadena por ***REMOVED*** sin borrar el archivo entero.

6. Limpia lo que queda localmente

clai
$ clai expira las referencias antiguas y ejecuta el garbage collection de forma agresiva→ git reflog expire --expire=now --all && git gc --prune=now --aggressive

Después de reescribir, los commits antiguos siguen siendo alcanzables a través del reflog — es decir, el secreto sigue dentro de .git. Este comando los elimina para siempre. En GitHub o GitLab tendrás que pedir por separado a soporte que limpien su caché, y de los forks no se encarga nadie.

Trampas habituales

  • Un historial reescrito rompe todos los clones del equipo. Después del force-push, cada quien tiene que volver a clonar o hacer git rebase --onto. Avisa con antelación, o alguien acabará empujando el historial viejo de vuelta.
  • Los forks y pull requests sobreviven. En GitHub, un commit de un PR cerrado puede seguir siendo accesible por enlace directo incluso después de limpiar el repositorio principal. Un argumento más para rotar la clave.
  • git filter-branch está obsoleto. El propio git imprime una advertencia y te señala filter-repo al ejecutarlo. La mitad de los artículos que aparecen en los resultados todavía no lo saben.

Preguntas relacionadas

¿Basta con añadir el archivo a .gitignore? No. .gitignore solo afecta a los archivos nuevos. Lo que ya está comiteado permanece en el historial por completo.

¿Cómo evito que esto vuelva a pasar? Un hook de pre-commit con un escáner de secretos: gitleaks, detect-secrets o trufflehog. Detectan la clave antes del commit, no después de publicarla.

¿Y si el secreto ya está en GitHub? Revoca la clave de inmediato, luego limpia el historial, luego pide a soporte de GitHub que borre las vistas en caché. Ese es el orden.

Ver también

CliAI marca git filter-repo como DANGER y pide confirmación escrita antes de tocar un solo commit. Instálalo en una línea.