Guía9 min

git diff para coding agents: working tree, index, A...B

Resumen

git diff compara dos extremos, no un rango. Sin args es working tree vs index. --cached es el index vs HEAD. A...B es merge-base…tip (el diff de un PR en GitHub). Un agente no vuelca el parche entero al LLM. Git 2.50.1.

GitHub
Tres capas de Git: working tree, index y HEAD; git diff elige dos extremos

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 diff no es “muéstrame el PR”. El man (Git 2.50.1 / Apple Git-155; git-scm.com/docs/git-diff HTTP 200, man 2.55.0 del 2026-06-29): compara dos extremos — working tree, index, trees, blobs o dos paths en disco. Las notaciones A..B y A...B no son rangos de gitrevisions(7).

Sin args: working tree vs index (lo que aún no está en add). --cached / --staged: index vs HEAD (lo que iría en el próximo commit). HEAD: working tree vs último commit. Esta guía no sustituye PRs con gh. El contrato: qué forma corre un agente, qué flags están prohibidas, y cómo no inundar el contexto.

Tres capas, tres diffs

El man (EXAMPLES):

git diff            # (1) working tree vs index — unstaged
git diff --cached   # (2) index vs HEAD — staged; --staged es sinónimo
git diff HEAD       # (3) working tree vs HEAD — staged + unstaged
git diff AUTO_MERGE # (4) lo que ya resolviste de un conflicto textual

AUTO_MERGE lo escribe la estrategia ort al chocar. Un agente en conflicto lee eso; no inventa el merge.

-- antes de paths. git diff HEAD -- ./src/foo.ts no se confunde si existe una rama src.

Working tree, index y HEAD: cada git diff elige dos

Dos puntos vs tres puntos

El man (Comparing branches):

FormaEquivale aQué ves
git diff topic mastertips de ambastodo lo que las separa
git diff topic..masterlo mismono es un rango de log
git diff topic...mastergit diff $(git merge-base topic master) masterlo que master introdujo desde el ancestro

A...B = merge-base(A, B) → B. GitHub Docs (HTTP 200, 2026-09-03, About comparing branches in pull requests): los PRs muestran three-dot. Two-dot (A..B) cambia cuando avanza la base aunque el topic no se haya tocado; three-dot se queda en “qué introduce el PR”.

Un agente que resume “el diff de mi rama vs main” corre git diff origin/main...HEAD --stat, no git diff origin/main HEAD. HEAD..origin/main (two-dot invertido) parece que borra el trabajo local: es el tip de main contra HEAD, no el parche del topic.

--merge-base A = git diff $(git merge-base A HEAD). --cached --merge-base A aplica lo mismo al index.

Lo que el agente sí / no corre

QuieroComandoTrampa
¿Hay unstaged?git diff --name-statusgit diff crudo al LLM
¿Qué commitaria?git diff --cached --stat--cached sin paths en un index sucio
¿El PR introduce?git diff origin/main...HEAD --statorigin/main..HEAD (two-dot)
¿Hay diff? (script)git diff --quietexit 1 = hay cambios; 0 = idéntico
Dos archivos fuera de Gitgit diff --no-index a bimplica --exit-code

Prohibido en autónomo:

  • Volcar git diff / git diff HEAD sin --stat / --name-status / paths al prompt. El parche de un refactor come la ventana.
  • git diff origin/main (un commit) como “el PR”: eso es working tree vs tip de main, mezcla unstaged + historia ajena.
  • -w / --ignore-all-space “para que salga menos”. El man: ignora todo whitespace al comparar líneas. Esconde bugs.
  • --check y --exit-code juntos. El man: --check no es compatible con --exit-code. --check ya sale ≠0 si hay whitespace/conflict markers.
  • --no-index sobre el checkout del humano para “comparar con /tmp”. Worktree propio (worktrees).
  • --binary al LLM. El man emite un diff binario aplicable; no es texto de review.
  • Tratar exit 1 de --quiet / --exit-code como fallo de Git. El man: como diff(1) — 1 = hay diferencias, 0 = no.

--name-only lista paths (a menudo quoted). --name-status añade A|C|D|M|R|T|U. --numstat da altas/bajas parseables. Un agente que decide “tocar o no” usa --name-status, no el parche.

Receta (60 segundos)

Solo en un worktree propio:

git status -sb
git diff --name-status
git diff --cached --stat
git diff origin/main...HEAD --stat

Si --quiet sale 1, hay unstaged. Si --cached --quiet sale 1, hay staged. Integrar remoto es pull --ff-only, no un diff.

Paths al add salen de --name-status, no de un git add . “porque el diff era largo”.

A...B es merge-base→tip; A..B son dos tips

Scripts y seguridad

--exit-code: 1 si hay diff, 0 si no. --quiet implica --exit-code y apaga helpers externos cuyo código no es de confianza (diff.trustExitCode).

--no-index compara dos paths del filesystem e implica --exit-code. El man: se puede omitir --no-index si al menos un path está fuera del working tree, o si no estás en un repo. Un agente pasa --no-index explícito y nombra paths; no deja que Git adivine.

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

No pipes de git diff a git apply en el checkout del humano. Restaurar un archivo es restore, no reaplicar el parche.

Checklist

  • Worktree propio, git status -sb.
  • Unstaged = git diff --name-status. Staged = git diff --cached --stat.
  • “Qué introduce mi rama” = git diff origin/main...HEAD --stat (three-dot).
  • Cero dump de parche al LLM. Cero -w. Cero --binary.
  • --quiet / --exit-code: 1 es “hay diff”, no crash.
  • --check solo, nunca junto a --exit-code.
  • Add por paths. Cero push a main.

FAQ

¿git diff es el PR? No. GitHub Docs: el PR es three-dot (A...B). git diff sin args es unstaged.

¿A..B vs A...B? El man: A..B = tips; A...B = merge-base(A,B) → B. Two-dot se mueve cuando avanza la base.

¿--cached vs --staged? Sinónimos. El man lo dice en la forma contra el index.

¿Puedo git diff HEAD..origin/main para “ver qué me falta”? Eso es two-dot del tip remoto contra HEAD. Tras un fetch, para inspeccionar commits usa git log. Para el parche que introducirías en un PR: origin/main...HEAD.

El curso instalar un agente cubre el loop local. Hub: comparativas y decisiones. Diff no es sandbox (sandboxing) ni deshacer unstaged (restore).

Verificado 2026-09-03 contra git-diff(1) (Git 2.50.1 / Apple Git-155), git-scm.com/docs/git-diff (HTTP 200, man 2.55.0) y GitHub Docs “About comparing branches in pull requests” (HTTP 200).