Guía9 min

git status para coding agents: porcelain, XY, no el long

Resumen

git status lista index vs HEAD, worktree vs index y untracked. El long no es API. Un agente parsea --porcelain=v1 -z; para humanos, -sb. XY es dos letras, no un párrafo. GitHub status checks no son git status. Git 2.50.1.

GitHub
Tres columnas de estado Git: index, worktree y untracked; el agente lee porcelain, no el long

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 status no es un párrafo para el LLM. El man (git-status(1), Git 2.50.1 / Apple Git-155; git-scm.com/docs/git-status HTTP 200): muestra paths con diff index vs HEAD, worktree vs index, y untracked que no ignora gitignore(5). El long es plantilla de commit: “subject to change at any time”. Un agente que lo vuelca al prompt mezcla color, traducciones y diffs.

Esta guía no sustituye add ni gitignore. El contrato: qué forma corre un agente, qué XY significa, y qué no es un status check de GitHub.

Long vs short vs porcelain

El man (OUTPUT): el long es para humanos. -s / --short es compacto. --porcelain[=<version>] es para scripts: estable entre versiones de Git y sin color.status ni status.relativePaths. Default del porcelain: v1.

git status -sb                 # humano: short + rama/upstream
git status --porcelain=v1      # script: LF, paths desde la raíz del repo
git status --porcelain=v1 -z   # script: NUL; sin quoting C

-z implica porcelain v1 si no hay otro formato. En -z, el -> de un rename desaparece, el orden es to luego from, y los nombres no se entrecomillan. Un parser que parte por espacio sobre -s se rompe con un path con espacio.

-b antepone ## <branch> <tracking>. --ahead-behind (default true) pone conteos vs upstream. Eso no es pull: status no trae objetos.

Index, worktree y untracked: porcelain v1, no el long

Qué es XY

En short/porcelain v1, cada path es <xy> <path> o <xy> <orig> -> <path>. Fuera de conflicto: X = index, Y = worktree. Untracked: ??. Ignored solo con --ignored: !!.

XYSignificado (man, tabla Short Format)
Mworktree cambió; index intacto
M index actualizado; worktree igual al index
MMindex y worktree distintos del HEAD y entre sí
A añadido al index
D borrado del index
??untracked
UUunmerged, ambos modificados
AAunmerged, ambos añadidos
DU / UDunmerged, borrado por un lado

U en cualquier lado = no resuelto. Un agente no commitea ni hace add masivo sobre U. Restaurar unstaged es restore, no adivinar el path desde el long.

Submódulos (short, no porcelain v1): M HEAD distinto, m contenido modificado, ? untracked dentro. Porcelain v1 reporta el submódulo sucio como M, no m/?.

Lo que el agente sí / no corre

QuieroComandoTrampa
¿Hay sucio? (humano)git status -sbgit status long al LLM
Parsear pathsgit status --porcelain=v1 -zpartir -s por espacios
¿Untracked?porcelain; ??-uno y luego “el árbol está limpio”
¿Ignored listado?--ignoredasumir que !! sale siempre
CI de un PRchecks de GitHubconfundir con git status

Prohibido en autónomo:

  • Volcar git status / -v / -vv al prompt. -v es git diff --cached; dos veces, también el unstaged. Es el parche entero.
  • Parsear color. Porcelain apaga color.status.
  • Tratar paths del long como relativos a la raíz. El man: el long es relativo al cwd; porcelain v1 es relativo a la raíz del repo.
  • git add . “porque status era largo”. Paths salen de porcelain, no de un glob.
  • -uall en un monorepo para “ver todo”. Default -unormal lista el directorio untracked, no cada archivo. status.showUntrackedFiles cambia el default; un agente pasa -u explícito.
  • Confundir status checks de un PR (GitHub Docs, HTTP 200, Status checks: commits pending/success/failure/error vía API/gh) con el working tree. Un check rojo no se arregla con git status.

-- + pathspecs. Sin --, un path que coincide con un ref es ref.

Receta (60 segundos)

Solo en un worktree propio:

git status -sb
git status --porcelain=v1 -z | tr '\0' '\n'

Si sale ??, decide path a path (add); no clean -fdx. Si hay U, para: conflicto, no commit. Integrar remoto es pull --ff-only tras un fetch, no un status.

Humano: -sb. Script: --porcelain=v1 -z. Cero -vv

Scripts y seguridad

Porcelain v1 no respeta status.relativePaths. Un agente que corre status desde src/ y luego git add foo.ts añade src/foo.ts mal si copió el path del long. Copia del porcelain.

-z es el único formato seguro con espacios, quotes y renames. Un split por LF + espacio miente en R old -> new file.ts.

--ignored=matching lista paths que matchean ignore, no el contenido de un dir ignored. No uses eso para borrar: clean -n primero.

gitignore no es sandbox (sandboxing): status no lista ignored salvo --ignored, pero el agente puede leerlos del disco.

Checklist

  • Worktree propio. Humano: git status -sb. Script: --porcelain=v1 -z.
  • XY: X index, Y worktree. ?? untracked. U = parar.
  • Cero long / -v / -vv al LLM. Cero color.
  • Add por paths del porcelain. Cero git add ..
  • Status checks de GitHub ≠ git status.
  • Cero push a main. PR con gh.

FAQ

¿git status es estable para un parser? No el long. El man: porcelain v1 no cambia por versión ni por config de color/paths.

¿-s y --porcelain son lo mismo? Casi el XY; porcelain apaga color, fija paths a la raíz, y -z cambia quoting y renames.

¿Por qué no veo ignored? El man: ignored no se listan sin --ignored. !! no sale en el default.

¿Un check rojo en el PR es git status sucio? No. GitHub Docs (Status checks): es CI sobre el commit. El working tree local puede estar limpio.

El curso instalar un agente cubre el loop local. Hub: comparativas y decisiones. Status no es sandbox ni clean.

Verificado 2026-09-03 contra git-status(1) (Git 2.50.1 / Apple Git-155), git-scm.com/docs/git-status (HTTP 200) y GitHub Docs “Status checks” (HTTP 200, /pull-requests/reference/status-checks).