git difftool para coding agents: GUI humana, no el diff
Resumen
git difftool es un frontend de git diff que abre vim, FileMerge o VS Code. Sin diff.tool avisa y prueba fallbacks. Cero -y/--gui/--dir-diff autónomo. Distinto de diff, diff-files, diff-index y mergetool. Git 2.50.1.

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 difftool abre un programa gráfico o un editor para ver el mismo conjunto que diff. El man (git-difftool(1); git-scm.com/docs/git-difftool HTTP 200, last-modified 2026-08-31; pie del man local Git 2.50.1.428.g0e8243, 2025-07-22; binario Git 2.50.1 / Apple Git-155): Show changes using common diff tools. DESCRIPTION: frontend to git diff and accepts the same options and arguments. SYNOPSIS: git difftool [<options>] [<commit> [<commit>]] [--] [<path>...].
Contrato para un coding agent: no lo lances. Es GUI (opendiff, vscode, meld) o un Vim interactivo. Necesita TTY y, casi siempre, DISPLAY. Ante un diff, usa --stat, --name-only o --quiet --exit-code. No -y. No --gui. No --dir-diff. No --extcmd que vuelque $LOCAL/$REMOTE al contexto. No diff.tool global.
No es diff: diff imprime texto. Aquí el texto no llega: llega FileMerge. No es diff-files ni diff-index ni diff-tree: esos son plumbing raw. No es git mergetool: mergetool corre después de un merge con UU y escribe MERGED. difftool no resuelve conflictos.
Qué hace (y qué no)
Sin cambios, sale 0 y no imprime nada. Verificado 2026-09-06 en un worktree limpio: git difftool → vacío, exit 0. --tool-help lista tools y sale 0. En este Mac: disponibles opendiff, vimdiff/vimdiff1-3, vscode. El resto (meld, kdiff3, nvimdiff, gvimdiff, bc4…) aparece como valid, but not currently available. El pie: Some of the tools listed above only work in a windowed environment. --tool-help es diagnóstico, no una invitación a elegir tool y dispararlo.
Sin diff.tool, avisa y prueba fallbacks. Verificado en un archivo dirty, stdin cerrado: This message is displayed because 'diff.tool' is not configured. Luego: 'git difftool' will now attempt to use one of the following tools: opendiff kompare emerge vimdiff nvimdiff. Prompt: Viewing (1/1): 'f.txt' / Launch 'opendiff' [Y/n]?. Exit 0 si no contestas (EOF). No asumas que “no configurado” = no-op.
--tool=notatool con cambios reales falla. Verificado dirty + -y: error: difftool.notatool.cmd not set for tool 'notatool', fatal: external diff died, stopping at f.txt, exit 128. El mismo tool sin -y sobre dos commits ya hechos pregunta Launch 'notatool' [Y/n]? y con EOF sale 0: Git ni valida el cmd hasta que alguien dice que sí. --dir-diff --tool=notatool → el mismo error de cmd, warning: failed: 1, exit 1. Códigos distintos, mismo verbo prohibido.

GitHub Docs (/en/pull-requests/how-tos/review-pull-requests/reviewing-proposed-changes-in-a-pull-request, HTTP 200; la URL vieja …/collaborating-with-pull-requests/reviewing-changes-in-pull-requests/… 301). El review de un PR es el diff en la web, no FileMerge en tu Mac. Un agente que “revisa” abriendo VS Code no deja comentario en el PR.
Flags que un agente no toca
| Flag / config | Man | Agente |
|---|---|---|
-t / --tool=<tool> | Usa ese programa. Built-ins: emerge, kompare, meld, vimdiff… | Cero. Abre GUI o vim |
--tool-help | Lista tools válidos | Sí, solo lectura |
-y / --no-prompt | No pregunta antes de cada archivo | Cero autónomo. En este Mac lanza FileMerge |
--prompt | Pregunta para poder saltar el path. Default; pisa -y | Cero |
-g / --gui | Lee diff.guitool en vez de diff.tool | Cero. Quiere DISPLAY |
--no-gui | Fuerza diff.tool | Cero |
-d / --dir-diff | Copia a un temp y hace un diff de directorio. never prompts | Cero. Árboles temporales |
-x / --extcmd=<command> | Ignora defaults; corre <command> $LOCAL $REMOTE | Cero. El payload va al stdout |
--trust-exit-code | Propaga el exit del tool | Cero. Default ignora errores del tool |
--[no-]symlinks | En --dir-diff, symlink al worktree o copia. Default copies en Windows | Cero autónomo |
--rotate-to / --skip-to | Reordena o salta paths | Cero. Path ausente → 128 |
Verificado 2026-09-06:
-y --extcmdconprintf:$LOCALes un blob temporal;$REMOTEen un dirty es el path del worktree. Dos commits: ambos temporales. Exit 0.--dir-diff -y --extcmd /bin/echo: imprime…/git-difftool.*/left/y…/right/. Exit 0. Unprintfcon espacios no es un ejecutable: cannot run … No such file or directory, warning: failed: -1, exit 1.-y --trust-exit-code --extcmd false→ fatal: external diff died, stopping at f.txt, 128. El mismo--extcmd falsesin trust → 0. El default traga el fallo del tool.--gui+--extcmdjuntos: options '--gui' and '--extcmd' cannot be used together, 128.-y --prompt --extcmd /bin/echosigue preguntando.-yno gana.--no-index -y --extcmdentre dos archivos distintos: imprime$LOCAL $REMOTEy sale 1 (el 1 es dediff --no-indexcuando hay diferencias, no un crash).--rotate-to/--skip-tocon un path que no está en el diff: fatal: No such path 'g.txt' in the diff, 128.HEAD HEAD: 0, vacío.
Custom tool: difftool.<tool>.cmd corre en shell con LOCAL (pre-image temporal) y REMOTE (post-image). $MERGED y $BASE existen por compatibilidad con mergetool y valen lo mismo que $MERGED = archivo comparado. Un cmd que cat esos temporales filtra el parche al LLM. Prohibido.
Config que no pisa un agente
El man incluye el bloque de git-config(1) (git-scm.com/docs/git-config HTTP 200, last-modified 2026-08-31). difftool cae a las variables de mergetool si las suyas no existen.
diff.tool/diff.guitool: cuál programa. overrides the value configured in merge.tool / merge.guitool. Un agente no hacegit config --global diff.tool. Eso es config local, y global queda fuera.difftool.<tool>.path/.cmd: path o comando custom.difftool.trustExitCode: equivalente a--trust-exit-code. Default ignora.difftool.prompt: prompt por archivo.difftool.guiDefault:true≡--gui;automiraDISPLAY. Defaultfalse: hace falta--guiexplícito.
vimdiff espera un humano que salga con :qa. Un agente no abre Vim para “ver el diff”.
Flujo seguro
- status porcelain. ¿Hay cambios?
- Pregunta binaria:
git diff --quiet --exit-code. 0 = limpio, 1 = hay diff. Hay diff ≠ error de comando. - Lista:
git diff --name-only/--name-status+ pathspec. Resumen:--stat. Cero-pal LLM. - No
git difftool. No-y. No--dir-diff. No--extcmd cat. - Review de PR: el diff de GitHub, no FileMerge. Un comentario en el PR no nace de
$LOCAL. - Si el humano pide GUI, él lanza difftool. Tú reportas paths.

Checklist:
-
diff.toolno lo seteas tú. - Cero
-y,--gui,--dir-diff,--tool=vimdiffautónomo. - Cero
--extcmdque imprima LOCAL/REMOTE. -
--tool-helpsí; lanzar el tool no. - Conflicto
UU= mergetool del humano o abortar. difftool no lo cierra. - El 1 de
--no-indexo de--quiet --exit-codeno es un crash.
FAQ
¿Puedo usar difftool en CI? No. No hay DISPLAY ni humano. CI usa git diff --exit-code y deja el job rojo.
¿Es lo mismo que el diff de VS Code / Cursor? El tool vscode de --tool-help requires a graphical session. El agente CLI no es esa sesión. No lo dispares con -y.
¿Y si el humano ya tiene diff.tool=opendiff? Sigue sin lanzarlo. FileMerge espera un clic. Lo verificado aquí: -y sin tool configurado sí llega a FileMerge y no vuelve. Tu trabajo es --stat y parar.
¿--dir-diff es más seguro porque no pregunta? Al revés. El man: This mode never prompts before launching the diff tool. Copia el árbol a un temp y abre el GUI de golpe.
¿mergetool y difftool son el mismo binario? No. git-mergetool(1) (HTTP 200, last-modified 2026-08-31): Run merge conflict resolution tools. difftool es frontend de diff. Ver el hub de comparativas si estás eligiendo verbo.
¿--extcmd sirve para un “diff seguro”? No para el agente. $LOCAL es un archivo temporal con el contenido completo. Imprimirlo es volcar el parche. Usa git diff --stat.
Si estás armando el agente desde cero, el curso de instalar un agente cubre el loop y las tools. Esta guía es la regla cuando el diff ya existe: no lo abras en una GUI.
Lecturas relacionadas
Sigue explorando Coding Agents y otras piezas para builders.

git stripspace para coding agents: limpia el mensaje, no el parche

git interpret-trailers para coding agents: parse, no reescribir el mensaje

git patch-id para coding agents: huella del diff, no del SHA
