Este capítulo lo escribo con cariño porque le pasa a todo el mundo, incluida
gente con veinte años de oficio. Un git add . se llevó el
.env, y ahora las claves de la base de ventas están en
internet 😬
Lo importante es el orden. Casi todo el mundo lo hace al revés.
El orden correcto
| Paso | Qué | Por qué |
|---|---|---|
| 1 | Rotar la clave en el proveedor | Es lo único que la vuelve inútil |
| 2 | Poner el repositorio en privado, si era público | Corta el goteo mientras limpias |
| 3 | Sacar el archivo y agregarlo al .gitignore | Para que no vuelva a entrar |
| 4 | Limpiar la historia, si hace falta | Es lo más caro y lo menos urgente |
Fíjate en que limpiar la historia es el último paso y no el primero. Es el que más tiempo cuesta y el que menos resuelve 🧯
Por qué borrar el archivo no basta
mkdir tienda cd tienda git init -q printf 'ciudad,monto\nLima,1200\n' > ventas.csv printf 'API_KEY=clave-de-ejemplo-1234\n' > .env git add . git commit -q -m "Conexion a la base de ventas" git rm -q .env git commit -q -m "Se quita el archivo de configuracion" ls -a git log --oneline
. .. .git ventas.csv e115bef Se quita el archivo de configuracion baabc8f Conexion a la base de ventas
El archivo ya no está en la carpeta. Pero:
git show HEAD~1:.env
git log --all --oneline -- .env
API_KEY=clave-de-ejemplo-1234 e115bef Se quita el archivo de configuracion baabc8f Conexion a la base de ventas
Ahí está la clave, entera, sacada de la historia con un comando. Cualquiera con acceso al repositorio puede hacer eso, y en GitHub además quedó en la vista de commits 🔍
Que no vuelva a entrar
printf 'API_KEY=otra-clave-de-ejemplo\n' > .env printf '.env\n*.key\n' > .gitignore git add .gitignore git commit -q -m "El archivo de configuracion no entra al repositorio" git status --short git check-ignore -v .env
.gitignore:1:.env .env
Ese check-ignore te dice qué línea del
.gitignore está tapando el archivo, que es lo que hay que
comprobar y no suponer. Todo esto está en 9 🚫
Y lo que sí va al repositorio
La costumbre que resuelve esto para siempre: un archivo de ejemplo, sin valores, que sí se sube y le dice a quien clone qué tiene que rellenar.
printf 'API_KEY=\nBASE_URL=\n' > .env.ejemplo git add .env.ejemplo git commit -q -m "Ejemplo de configuracion, sin valores" cat .env.ejemplo git ls-files
API_KEY= BASE_URL= .env.ejemplo .gitignore ventas.csv
El repositorio lleva el molde y nunca los valores. Es lo que hace todo proyecto serio 📄
Limpiar la historia, si hace falta
Existe, se hace con la herramienta git filter-repo, y hay que saber tres cosas antes:
- Reescribe todos los commits, o sea que cambian todos los hashes, con lo que vimos en 27.
- Todo el que tenga una copia tiene que clonar de nuevo.
- Los pull requests viejos de GitHub pueden seguir mostrando el contenido, y hay que pedirle soporte a GitHub que los purgue.
O sea que es caro. Y con la clave ya rotada, casi nunca es urgente: lo que queda en la historia es una clave que no abre nada 🔒
Buscar antes de subir
grep -rn "API_KEY\|PASSWORD\|SECRET" . --exclude-dir=.git --exclude=".env" || echo "limpio" git ls-files
./.env.ejemplo:1:API_KEY= .env.ejemplo .gitignore ventas.csv
Ese grep, corrido antes del primer push de un proyecto, es de las cosas que más disgustos ahorran. Y GitHub tiene lo suyo: el secret scanning, que avisa solo cuando detecta una clave de un proveedor conocido 🔔
La trampa
Subiste sin querer el archivo con la clave de la API. Lo borras, haces commit y respiras.
$ git rm .env
$ git commit -m "Se quita el archivo de configuracion"
$ git push
$ git log --all --oneline -- .env
8f2a91c Conexion a la base de ventas
Qué está mal
El archivo se fue del presente y sigue en la historia 🔍
Borrar algo en Git es un cambio más: el commit de ayer sigue teniendo el archivo entero, y cualquiera puede sacarlo con un git show. En GitHub, además, quedó en la vista de commits.
Y aunque limpiaras la historia entera, sigue habiendo algo que no controlas: los robots que rastrean GitHub buscando claves ya la copiaron, casi siempre en cuestión de minutos.
Por eso el primer paso nunca es limpiar el repositorio. Es rotar la clave en el proveedor, que la vuelve inútil. Limpiar viene después y con calma.
Comprueba que se entendió
Comprueba que lo tienes
Te das cuenta de que subiste el .env con la clave de la API. ¿Qué haces primero?
- Rotar la clave en el proveedor
- Borrar el archivo y hacer push
- Borrar el repositorio de GitHub
- Limpiar la historia con filter-repo
Ejercicios
1. Comete el error a propósito
Un git add . que se lleva el archivo de
configuración.
cd .. mkdir bodega cd bodega git init -q printf 'bodega,ciudad\nBodega Inti,Cusco\n' > bodegas.csv printf 'API_KEY=clave-de-ejemplo-abcd\n' > .env git add . git commit -q -m "Conexion al catalogo de bodegas" git ls-files
.env bodegas.csv
Ahí está el .env dentro del repositorio.
2. Comprueba que borrarlo no basta
Quítalo y sácalo igual de la historia.
git rm -q .env git commit -q -m "Se quita el archivo de configuracion" ls -a git show HEAD~1:.env
. .. .git bodegas.csv API_KEY=clave-de-ejemplo-abcd
Fuera de la carpeta y dentro de la historia. Por eso se rota primero 🔑
3. Ponle el gitignore
Que no pueda volver a entrar.
printf 'API_KEY=otra-clave\n' > .env printf '.env\n' > .gitignore git add .gitignore git commit -q -m "El .env no entra al repositorio" git status --short git check-ignore -v .env
.gitignore:1:.env .env
Comprobado, no supuesto.
4. Sube el molde sin valores
El archivo de ejemplo que sí va al repositorio.
printf 'API_KEY=\nBASE_URL=\n' > .env.ejemplo git add .env.ejemplo git commit -q -m "Ejemplo de configuracion, sin valores" cat .env.ejemplo git ls-files
API_KEY= BASE_URL= .env.ejemplo .gitignore bodegas.csv
Quien clone sabe qué rellenar y no recibe ninguna clave 📄
5. Busca secretos antes de subir
La revisión de cinco segundos antes del primer push.
grep -rn "API_KEY\|PASSWORD" . --exclude-dir=.git --exclude=".env" || echo "limpio"
./.env.ejemplo:1:API_KEY=
Solo aparece el molde vacío, que es justo lo que debe aparecer.
6. Revisa toda la historia, no solo el presente
Busca el archivo en cualquier commit del repositorio.
git log --all --oneline -- .env
d5b0f0c Se quita el archivo de configuracion ce26339 Conexion al catalogo de bodegas
Dos commits lo tocaron: el que lo metió y el que lo sacó. Los dos lo contienen 🔍
7. Pide un archivo que ya no está en el último commit
Comprueba qué contesta Git cuando pides el
.env de ahora.
git show HEAD:.env
fatal: path '.env' exists on disk, but not in 'HEAD'
En el presente no está, y ese es justo el error que hace creer que el problema se resolvió 🙈
Lo que te llevas
Rotar primero. Borrar el archivo no lo saca de la historia, y la historia es lo de menos si la clave ya no abre nada.