TL;DR: si .gitignore no funciona, el archivo casi siempre ya está tracked. Git ignora los archivos que nunca ha visto — un archivo en el index es inmune a cualquier regla que escribas. Averigua la verdad con git check-ignore -v <path>: salida silenciosa significa que la ruta está tracked y ninguna regla aplica. Arréglalo con git rm --cached <path>, haz commit, y la regla de ignore empieza a funcionar a partir de ese commit. El orden de las reglas, las trampas de negación y los falsos sospechosos de VS Code explican los casos restantes.
¿Por qué .gitignore no funciona?
Un mecanismo cubre la mayoría de los casos: el archivo se commiteó antes de que existiera la regla. .gitignore no es un filtro que esconda archivos de git — es una regla sobre qué debe tomar git add desde un estado untracked. Una vez que un archivo está en el index, git trackea sus cambios de contenido para siempre hasta que lo saques del tracking explícitamente. Editar .gitignore después del hecho no cambia nada sobre los archivos trackeados, y por eso la secuencia clásica “commiteas .env, entras en pánico, añades .env a .gitignore, commiteas otra vez” sigue enviando el secreto en cada push.
Esto muerde a todo el mundo porque git es casi universal — la encuesta de Stack Overflow 2022 midió el uso de Git en más del 93 % de los desarrolladores profesionales (survey.stackoverflow.co) — y cada uno de esos desarrolladores tarde o temprano escribe una regla para un archivo que commiteó la semana pasada.
El resto del post cubre los casos minoritarios: errores de orden de reglas, trampas de negación, casos borde de carpetas y la pregunta del IDE. Pero corre primero el chequeo de salud de la siguiente sección — más de nueve de cada diez veces termina la investigación.
¿Cómo reviso qué regla de gitignore está coincidiendo con un archivo?
git check-ignore es la herramienta de diagnóstico, y su silencio es el diagnóstico:
# Imprime la regla que coincide + archivo + número de línea cuando una regla aplica
git check-ignore -v debug.log
# .gitignore:3:*.log debug.log
# No imprime NADA cuando ninguna regla aplica — el archivo está tracked (o no existe regla)
git check-ignore -v src/.env
# (silencio = .gitignore no está ignorando esta ruta, escribas lo que escribas)
# Códigos de salida: 0 = ignorado, 1 = no ignorado — scriptable
git check-ignore -q debug.log && echo "ignored" || echo "tracked or unruly" Lectura de la salida de -v: la fuente del ignore (.gitignore, .git/info/exclude, o tu archivo global de ignore), luego line-number:pattern, luego la ruta. Si una regla posterior te sorprende, recuerda la precedencia: la última regla que coincide gana, así que !important.log después de *.log vuelve a incluir ese archivo.
¿Por qué gitignore no funciona con archivos ya commiteados?
Saca el archivo del tracking, déjalo en disco, commitea la eliminación:
# Saca un archivo del tracking (la copia local sobrevive — --cached toca solo el index)
git rm --cached .env
git commit -m "stop tracking .env"
# Verifica que la regla de ignore ahora aplica
git check-ignore -v .env Desde este commit en adelante, .gitignore es el dueño de la ruta: los edits ya no aparecen en git status, y git add . no lo volverá a tomar. El archivo queda en el historial, eso sí — si era un secreto, quitarlo del último commit no basta. Rotar la credencial es el único arreglo real; reescribir el historial es el cosmético (y deshacer el último commit solo ayuda mientras el commit malo sigue siendo la punta).
Para un repo lleno de basura commiteada antes — output de build, restos del editor, un node_modules que se coló al principio — el des-tracking masivo son dos líneas:
git rm -r --cached .
git add .
git commit -m "apply .gitignore to tracked files" Esto reconstruye el index contra las reglas actuales: las rutas ignoradas salen, todo lo demás se re-añade sin cambios. El diff se ve dramático (miles de eliminaciones) pero no borra nada del disco. Si tu objetivo es borrar esos archivos y no solo dejar de trackearlos, ese es territorio de git clean -fdx — mira git remove untracked files de forma segura.
Git ignora los archivos que nunca ha visto. Un archivo que ya está en el index es inmune a
.gitignore— ninguna regla que escribas hará que git lo olvide.
¿Por qué gitignore no funciona con una carpeta?
Tres trampas específicas de carpetas:
1. Las barras finales importan para la intención, no para el matching. build y build/ coinciden ambos con un directorio, pero build/ documenta que hablas solo de un directorio — un archivo llamado build sobreviviría. La simetría falla, eso sí, en la re-inclusión (siguiente trampa).
2. La negación no puede rescatar archivos dentro de un directorio excluido. La documentación de git es inequívoca: “No es posible volver a incluir un archivo si un directorio padre de ese archivo está excluido” (git-scm.com/docs/gitignore). Es una decisión de rendimiento — git se salta los directorios excluidos al por mayor en vez de recorrerlos. Así que esto no funciona:
build/
!build/keep.me # regla muerta — git nunca mira dentro de build/ El arreglo es excluir el contenido, no el directorio:
build/*
!build/keep.me # funciona — build/ en sí sigue abierto para inspección 3. Los .gitignore anidados ganan en su ámbito. Las reglas en subdir/.gitignore pisan al archivo raíz para las rutas bajo subdir. Cuando git check-ignore -v nombra una fuente de ignore que no esperabas, normalmente es por esto.
¿Por qué gitignore no funciona en VS Code?
Casi nunca por razones de VS Code. La vista de Source Control del editor lee el mismo index que git, así que el síntoma es idéntico: el archivo ya estaba commiteado, y ningún reinicio del IDE cambia el index. Dos realidades vecinas de VS Code que valen la pena conocer:
- Gris en el Explorer = ignorado; naranja/amarillo = trackeado con cambios. Un archivo que aparece como modificado después de que lo ignoraste es tu confirmación de que está trackeado — corre el arreglo de
git rm --cachedde arriba. - Que
.gitignoreno aparezca en la lista de cambios del Explorer significa que la regla funciona — nunca llega a aparecer como untracked en primer lugar. La gente suele reportar “VS Code ignora mi gitignore” cuando elgit statusde la CLI no coincide con una vista SCM vieja; recarga la ventana (Cmd/Ctrl+Shift+P→ “Reload Window”) antes de culpar a git.
.gitignore vs .git/info/exclude vs global: ¿cuál para qué?
| Archivo | Alcance | ¿Se commitea? | Para qué |
|---|---|---|---|
.gitignore (repo) | Todo el que clone | Sí | Output de build, dependencias, .env — reglas compartidas |
.git/info/exclude | Solo tu clon | No | Basura personal: .scratch/, restos del editor |
core.excludesFile (global) | Todos tus repos | No | Basura del OS: .DS_Store, Thumbs.db, *.swp |
.gitignore + negación | Repo | Sí | Re-incluir excepciones de config trackeada |
El archivo global es el que la mayoría de los desarrolladores nunca configura y debería:
git config --global core.excludesFile ~/.gitignore_global
printf '.DS_Store\nThumbs.db\n*.swp\n' >> ~/.gitignore_global Regla de la casa que vale la pena copiar: si una regla beneficia a todo el equipo, va en el repo; si solo te beneficia a ti, va en exclude o en el archivo global. Commitear reglas de ignore personales es como los .gitignore acaban con 300 líneas y nadie sabe qué mitad sigue importando.
¿Cómo ignoro los cambios de un archivo trackeado?
A veces quieres un archivo trackeado (una plantilla de config, un archivo de settings del IDE) pero quieres que los edits locales dejen de aparecer en git status. Dos flags de git update-index, ninguno de los cuales pertenece a un workflow de equipo:
git update-index --skip-worktree config/local.dev # los edits locales se silencian
git update-index --no-skip-worktree config/local.dev # ...y de vuelta --skip-worktree es el defendible — dice “mi versión local diverge a propósito”. Su primo --assume-unchanged es una promesa de rendimiento (“este archivo no va a cambiar”), no un mecanismo de ignore, y git puede romperlo en silencio. Ambos flags fallan fuerte al momento del pull cuando upstream también cambió el archivo — las respuestas duraderas son una config solo local vía exclude desde la creación, o un archivo plantilla (config.example) que git trackea y tú copias.
El chequeo de salud de gitignore en 30 segundos
git check-ignore -v <path> # ¿qué regla? (silencio = tracked, sin regla)
git ls-files --error-unmatch <path> # ¿está trackeado siquiera?
git rm --cached <path> # fuera del tracking, queda en disco
git commit -m "stop tracking <path>"
git check-ignore -v <path> # la regla ahora aparece Diagnostica, saca del tracking, verifica. El patrón detrás de cada reporte de “gitignore not working” es el mismo archivo con dos sombreros — trackeado de un lado del index, ignorado del otro — y un flag --cached le quita el segundo sombrero.
FAQ
¿Por qué .gitignore no funciona?
En la mayoría de los casos el archivo ya está tracked. Git solo ignora archivos untracked; un archivo en el index es inmune a .gitignore hasta que lo saques del tracking con git rm --cached y lo commitees.
¿Cómo reviso qué regla de gitignore coincide con un archivo?
Corre git check-ignore -v <path>. Imprime la línea exacta del .gitignore y el número de regla, o sale en silencio cuando el archivo está tracked y ninguna regla aplica.
¿git rm --cached borra mi archivo local?
No. --cached quita el archivo solo del index; la copia en disco se queda. Haz commit de la eliminación y el archivo pasa a untracked, después de lo cual .gitignore aplica.
¿Por qué gitignore no puede volver a incluir un archivo dentro de una carpeta ignorada?
Git se salta los directorios excluidos por completo por rendimiento. Según la documentación de git, es imposible volver a incluir un archivo si un directorio padre de ese archivo está excluido.
— mrsaynothing
Get the next one by email
One email per post. No spam, no algorithms.
what is this?¿Ollama no usa la GPU? Arréglalo en Linux, Windows y WSL
¿Te gustan estos artículos? Hago esto para vivir. contrátame