git diff-index para coding agents: tree vs disco o index
git diff-index compara un tree-ish con el working tree o, con --cached, con el index. Sin tree-ish sale 129. Default raw, no parche. Cero -p autónomo. Distinto de git diff, diff-files y diff-tree. Git 2.50.1.
Por Marco Lee · Reportar un error
Continúa con un curso prácticogit diff-index compara un tree con el disco o con el index. El man (git-diff-index(1); git-scm.com/docs/git-diff-index HTTP 200, last-modified 2026-08-31; pie del man local Git 2.50.1.428.g0e8243; binario Git 2.50.1 / Apple Git-155): Compare a tree to the working tree or index. DESCRIPTION: Compare the content and mode of the blobs found in a tree object with the corresponding tracked files in the working tree, or with the corresponding paths in the index. SYNOPSIS: [-m] [--cached] [--merge-base] [<common-diff-options>] <tree-ish> [<path>...].
Sin <tree-ish> falla. Verificado 2026-09-06: git diff-index → usage, exit 129. Lo mismo con --cached solo. No es diff: el porcelain asume working tree vs index sin args. Aquí el tree es obligatorio.
No es status: status es porcelain XY. No es ls-files: ls-files lista, no compara. El man RAW OUTPUT FORMAT lo separa de sus hermanos: diff-index <tree-ish> = tree vs filesystem; diff-index --cached <tree-ish> = tree vs index; diff-files = index vs filesystem; diff-tree = dos trees. Untracked no aparece.
Contrato: no vuelques el raw ni el parche al LLM. Pregunta binaria = --quiet --exit-code. Lista = --name-only / --name-status + pathspec. Cero -p. Cero dump.
Qué hace (y qué no)
Default: raw, no patch. Una línea por path cambiado:
:100644 100644 <src-sha> 0000000 M a.txt
El man: el sha1 dst es 0{40} si a file on the filesystem is out of sync with the index. Verificado: unstaged dirty vs HEAD → status M, dst todo ceros, exit 0. --cached HEAD con el mismo unstaged → silencio, exit 0: el index aún coincide con el tree. Tras git add, --cached HEAD muestra M con ambos sha reales.
--quiet implica --exit-code. Verificado: dirty vs HEAD → exit 1; working tree igual al tree → 0. Hay diff ≠ error de comando. 1 = “hay diferencias”, 0 = “no hay”.
-h / sin tree: usage, 129. Tree inválido: unknown revision or path not in the working tree, 128.
-m: By default, files recorded in the index but not checked out are reported as deleted. This flag makes git diff-index say that all non-checked-out files are up to date. Verificado: rm a.txt vs HEAD → D; con -m → silencio. --quiet --exit-code sin -m = 1; con -m = 0. Sparse / skip-worktree no es un delete.
--merge-base: use the merge base between <tree-ish> and HEAD instead. <tree-ish> must be a commit. No es el three-dot de un PR. GitHub Docs About branches (/en/pull-requests/reference/branches, HTTP 200 tras 301 desde about-comparing-branches…, 2026-09-06) habla de la UI de PRs, no de este plumbing.

Lo que el agente sí / no corre
| Quiero | Comando | Trampa |
|---|---|---|
| ¿El worktree coincide con HEAD? | git diff-index --quiet --exit-code HEAD | sin --quiet imprime raw |
| ¿El index coincide con HEAD? | git diff-index --cached --quiet --exit-code HEAD | sin --cached mira el disco |
| Lista de paths sucios vs un commit | --name-only HEAD -- <path> | -p es el parche |
| Untracked | status porcelain | diff-index no los ve |
| Diff de un PR | diff A...B o gh pr diff | --merge-base no es la UI |
| Index vs disco, sin tree | no este verbo | eso es diff-files; aquí el tree es obligatorio |
Prohibido en autónomo:
-p/-u/--patch. El default raw ya es denso. El parche cabe en el contexto y se va.- Sin
<tree-ish>. 129. No “adivines HEAD”. - Dump del raw al prompt. Parsea
--name-only/--name-statuso el exit de--quiet. -mpara “ocultar deletes”. Esconde paths no chequeados. En sparse es mentira útil solo si un humano lo pidió.--cachedcreyendo que ves unstaged.--cachedno considera el on-disk file at all (man). Unstaged desaparece.--find-copies-harder/-C/-Mautónomos. El man de-C: very expensive en proyectos grandes.--ext-diff/ textconv. Plumbing no corre textconv por default; no lo enciendas para “ver el binario”.- Encadenar read-tree + diff-index
-mpara fingir un working tree limpio.
El porcelain de diff cubre el caso “quiero ver el cambio”. Este verbo existe para scripts que necesitan raw estable y un exit code. Un tick de agente pregunta si hay diff, no cómo se ve el hunk.
Receta (60 segundos)
Solo en un worktree propio:
git status -sb
git diff-index --quiet --exit-code HEAD
git diff-index --name-only HEAD -- src/foo.ts
Tres líneas. status enseña untracked que este verbo no ve. --quiet --exit-code HEAD responde 0/1. --name-only + -- limita el pathspec. Cero -p. Cero repo entero al modelo.
Si el ticket pide “el diff del PR”, usa diff base...HEAD --stat o gh pr diff --name-only, no --merge-base a ciegas.
Trampas que ya vimos
- “Sin args es como git diff.” No. 129 y usage. El tree-ish no es opcional.
- “Exit 1 es fallo.” Con
--quiet --exit-code, 1 = hay diferencias. El comando funcionó. - “
--cachedmuestra lo sucio.” Muestra index vs tree. Unstaged no existe para--cached. Verificado: dirty unstaged +--cached HEAD→ silencio. - dst
0000000no es delete. En raw, dst ceros +M= working tree out of sync. Delete esDy mode dst000000. - Untracked invisible.
echo extra > b.txtno aparece. Quien quiso untracked pedía status-u. -m“limpia” un rm.rm a.txtesD;-mlo declara up to date. Sparse-checkout vive de ese bit. No lo uses para “arreglar” el exit.--merge-base= three-dot de GitHub. No. Es merge-base(<tree-ish>, HEAD) contra el working tree/index. La UI de PRs es otro contrato.- Pathspec sin
--. Un path que también es ref: ambiguous argument, 128. Siempre--antes de files. - Creer que escribe. diff-index es read-only. No toca index ni disco. El inverso de materializar es checkout-index.
Checklist
- Worktree propio, no el checkout del humano.
- Tree-ish explícito (
HEADo un SHA). Cero invocación vacía. - Pregunta 0/1 →
--quiet --exit-code. No parsees el raw a ojo. - Lista →
--name-onlyo--name-status+-- <path>. - Untracked: status, no este verbo.
- Cero
-p. Cero dump al LLM. -
--cachedsolo si comparas el index. - Cero
-mautónomo. Cero-C/-M/--find-copies-harder. - Diff de PR: porcelain diff o
gh, no este plumbing.
FAQ
¿diff-index mueve HEAD? No. Solo lee un tree y compara. Index y working tree no cambian.
¿Por qué el default es raw? Repeatability en scripts: una línea por path, NUL con -z, status A/C/D/M/R/T/U/X. El parche es para humanos o para git apply, no para el prompt.
¿Cuándo sí -p? Cuando un humano pide el hunk en un path acotado. Nunca autónomo sobre el árbol.
¿Y diff-files / diff-tree? diff-files no toma tree (index vs disco). diff-tree compara dos trees. Este verbo es el que exige un tree contra disco o index.
¿Dónde encaja esto? En el hub de comparativas y decisiones, junto a diff y status. Si estás armando el primer agente, empieza por el curso.

De la guía a la práctica
Pi agent (Pi.dev): instala tu agente de coding
Lleva tus convenciones de trabajo a Pi.dev: instalación, instrucciones, sesiones y operación segura.
Ver el curso gratisContenido gratis, sin registro. Los servicios externos pueden tener costos.
Avisos cuando actualicemos cursos y guías
Recibe actualizaciones por correo. Es opcional: puedes seguir leyendo y abrir cualquier curso sin suscribirte.
Lecturas relacionadas
Sigue explorando Coding Agents y otras piezas para builders.



