Guía9 min

git check-ignore para coding agents: regla ganadora, no adivinar

Resumen

git check-ignore dice si un pathname cae en las reglas exclude. Por default no muestra tracked. -v imprime fuente, línea y patrón. -q solo admite un path. Una negación con ! sale 0 con -v y 1 sin él: coincidir no es estar ignorado. Un agente nombra el path y no adivina .gitignore. Git 2.50.1.

GitHub
Un pathname se evalúa contra exclude; tracked queda fuera salvo --no-index

Qué resuelve

Esta pieza se queda en la decisión práctica: qué instalar, qué riesgo agrega y cómo aplicarlo sin romper operación.

git check-ignore no es un sandbox ni un linter de .gitignore. El man (git-check-ignore(1), Git 2.50.1 / Apple Git-155; git-scm.com/docs/git-check-ignore HTTP 200, last-modified 2026-08-31) toma pathnames por argv o --stdin y, si el exclude los cubre, imprime el path. Default: tracked no aparecen, porque no están sujetos a exclude. --no-index salta el index.

GitHub Docs (Ignoring files, HTTP 200 2026-09-04) explica dónde poner reglas (.gitignore de repo, exclude global, .git/info/exclude). No sustituye este comando. Un agente que “lee el .gitignore a ojo” se equivoca con !, con tracked y con info/exclude.

Esta guía no sustituye gitignore (precedencia y disco del agente) ni ls-files (-o -i). El contrato: qué forma corre un agente, qué exit code significa, y por qué -v sobre una negación no es “está ignorado”.

Tres salidas, un pathname

PreguntaComandoExit si aplica
¿Este untracked está ignorado?git check-ignore -v -- path0 imprime fuente:línea:patrón + tab + path
¿Sí / no, un path?git check-ignore -q -- path0 ignorado, 1 no
¿Por qué un tracked “debería” ignorarse?git check-ignore -v --no-index -- path0 si el patrón habría ganado
¿Llegó algún patrón, incluso !?git check-ignore -v -- path0 si coincidió; lee el patrón
Stream de pathsgit check-ignore -v -z --stdin0 si alguno ignorado

El man (OUTPUT): sin -v, solo paths excluidos, uno por línea. Sin match: nada para ese path. Con -v: <source> <COLON> <linenum> <COLON> <pattern> <HT> <pathname>. source es absoluto si es core.excludesFile; relativo a la raíz si es .gitignore o .git/info/exclude. El ! y el / final se conservan.

Exit (man): 0 uno o más paths ignorados; 1 ninguno; 128 fatal. Verificado 2026-09-04: sin path → no path specified, 128. -q con dos paths → --quiet is only valid with a single pathname, 128. -z sin --stdin-z only makes sense with --stdin, 128. -n sin -v--non-matching is only valid with --verbose, 128.

-v enseña fuente y patrón; tracked no sale salvo --no-index

Lo que el agente sí / no corre

QuieroComandoTrampa
¿.env cae en exclude?git check-ignore -v -- .envAbrir .gitignore y “parece que sí”
Sí/no de un pathgit check-ignore -q -- .env-q de una lista
Tracked que “no debería estar”--no-index -v -- pathDefault (exit 1, silencioso)
Lote-v -z --stdin-z en argv
No match explícito-v -n -- path-n solo

Prohibido en autónomo:

  • Inferir ignore leyendo .gitignore. El man manda a gitignore(5) para precedencia. info/exclude y core.excludesFile no están en el working tree.
  • Tratar exit 0 de -v como “ignorado” si el patrón empieza por !. El man: coincidir un ! significa que el path NO está excluido. Verificado: !keep.env con -v imprime el patrón y sale 0; sin -v no imprime y sale 1; -q sale 1.
  • -q con más de un pathname. Fatal 128.
  • -z sin --stdin. En 2.50.1 es fatal, no “output NUL”.
  • --no-index “por si acaso” en untracked. El man lo reserva para debug de tracked (git add . / git add -f) o para diseñar negaciones. Default ya cubre untracked.
  • Usar el comando como deny-list del runtime. gitignore no es sandbox: un .env ignorado sigue en disco.
  • Encadenar a add -f porque “el patrón ya está”. -f salta exclude; es incidente.
  • Dump de check-ignore -v -n sobre el árbol entero. Nombra el path del ticket.

-n / --non-matching (solo con -v): paths sin patrón salen con campos vacíos (::\tpath). El man: sin esto, un proceso largo con --stdin no distingue “aún no hay output” de “no match”. Un agente one-shot nombra un path; no necesita el stream.

Receta (60 segundos)

Solo en un worktree propio:

git status -sb
git check-ignore -v -- .env
git check-ignore -q -- .env; echo $?

Si el humano dice “este file ya está en Git y aún así debería ignorarse”:

git ls-files --error-unmatch -- path
git check-ignore -v --no-index -- path

Default sobre tracked: silencio, exit 1. Verificado: a.ts tracked + patrón posterior a.ts en .gitignore → default exit 1; --no-index.gitignore:5:a.ts y exit 0. Para sacarlo del index sin borrar disco: rm --cached, no este comando.

Untracked que ignorar: no hace falta clean para “comprobar”. Untracked a borrar: clean -n primero.

Una negación ! coincide y no excluye; -q sale 1

UI de GitHub vs clone local

GitHub Docs (Ignoring files): .gitignore en la raíz se commitea para compartirlo. Exclude global (core.excludesFile) y .git/info/exclude son de esa máquina. check-ignore -v te dice cuál ganó; la UI de GitHub no corre este comando sobre tu worktree.

Un patrón de directorio con / final casa el dir y sus hijos. Verificado: node_modules/node_modules y node_modules/pkg.js, misma línea. Un agente que pregunta solo por el dir no asume el contenido.

--stdin lee un path por línea; con -z, NUL. Buffering según GIT_FLUSH (git(1)). No cuelgues el pipe.

Verificado 2026-09-04 en esta máquina (Git 2.50.1 / Apple Git-155): .env con patrón .env.gitignore:2:.env exit 0. *.logdebug.log. scratch.tmp vía .git/info/exclude. Path inexistente → exit 1; con -v -n::\tdoes-not-exist. Varios paths: si uno está ignorado, exit 0 y solo se imprimen los que aplican.

Checklist

  • Worktree propio. git status -sb. Path nombrado, no el repo entero.
  • -v para ver fuente:línea:patrón. -q solo con un path.
  • Tracked: default no aplica. --no-index si el ticket es “por qué se trackeó”.
  • ! en -v = no ignorado. Confirma con -q (exit 1).
  • Cero -z sin --stdin, cero -n sin -v, cero add -f.
  • Ignore ≠ sandbox. El agente igual puede leer el file.

FAQ

¿check-ignore es lo mismo que ls-files -o -i? No. ls-files lista conjuntos. Este comando explica un path. -i en ls-files exige -c/-o y un --exclude*.

¿Por qué un tracked no sale? El man: no están sujetos a exclude. GitHub Docs: un file ya commiteado sigue en el árbol aunque agregues el patrón. --no-index debuggea el patrón; no destagea.

¿Exit 0 con -v y el path “se queda”? Patrón !. Coincidir ≠ excluido. -q y la forma sin -v siguen el “está ignorado”.

¿Puedo parsear -v por espacios? No. Separadores: dos : y un tab. Paths con espacio. Para lote: -z --stdin.

El curso instalar un agente cubre el loop local. Hub: comparativas y decisiones. check-ignore no es status: no resume XY; responde un pathname contra exclude.