Guía9 min

git apply para coding agents: pega el parche, no crea el commit

Resumen

git apply pega un diff en archivos y/o el index. No crea commit: eso es git am. --check primero. Sin --index no toca el índice ni exige un repo. Cero --unsafe-paths, --reject o --3way autónomo. Git 2.50.1.

GitHub
Un parche se aplica al working tree; HEAD no avanza

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 apply pega un parche. El man (git-apply(1); git-scm.com/docs/git-apply HTTP 200, last-modified 2026-08-31, last updated in 2.55.0; pie del man local Git 2.54.0, 2026-04-19; binario Git 2.50.1 / Apple Git-155) lee un diff y lo aplica a archivos. HEAD no se mueve. No hay commit. El man: This command applies the patch but does not create a commit. Para commits desde mailbox usa git am (el reverso de format-patch, HTTP 200).

Eso no es cherry-pick. Cherry-pick copia un commit (SHA nuevo). apply copia un diff. Tampoco add: sin --index / --cached el índice no cambia.

Contrato: --check primero, working tree propio, cero --unsafe-paths / --reject / --3way autónomo, cero tratar 0 como commit.

Tres destinos, un parche

Sin --index ni --cached, el man aplica solo a archivos y no exige un repo. Con --index, índice y working tree. Con --cached, solo el índice.

PreguntaComandoQué pasa
¿Aplicaría limpio?git apply --check file.patchsilencio 0 / does not apply 1. No escribe
¿Qué tocaría?git apply --stat file.patchdiffstat. No escribe
Pegar en discogit apply file.patchworking tree; índice intacto
Pegar disco + índicegit apply --index file.patchambos; exige que ya coincidan
Solo índicegit apply --cached file.patchworking tree intacto
Deshacer el mismo diffgit apply -R file.patchreverse

--stat, --numstat, --summary y --check apagan apply. El man: para pegar después de mirar, añade --apply.

--index no es “más seguro”. El man: espera que índice y working tree sean idénticos (contenido y modo). Si no, error aunque el parche aplicaría a cada uno por separado.

Verificado 2026-09-04 (Git 2.50.1 / Apple Git-155), repo de un archivo f.txt (line1 / line2 / line3) y un diff que cambia line2line2-changed:

  • --check limpio → 0. --statf.txt \| 2 +-. git apply0, git status -sb = M f.txt, git log sigue en c1, git diff --cached vacío.
  • Ya aplicado: --checkpatch does not apply, 1.
  • --index con árbol limpio → 0, status M f.txt (staged). --index con working tree sucio → does not match index, 1.
  • --cached0, status MM si el working tree ya difería.
  • -R tras un apply limpio → 0, working tree vuelve.
  • Parche vacío: No valid patches in input (allow with "--allow-empty"), 128. --allow-empty0.
  • --ours sin --3wayrequire --3way, 128.
  • --whitespace=error con trailing space en la línea nueva → 1 line adds whitespace errors, 128. El default (warn) avisa y pega.
  • --include='nope*'0 y no toca nada: con --include, un path que no matchea se ignora.
  • --directory=sub sin sub/f.txtNo such file or directory, 1. Con el destino creado → 0.
  • Fuera de un repo: git apply file.patch0 y reescribe el archivo. El man lo dice; verificado.
  • Path ../outside.txt: default invalid path '../outside.txt', 128. --unsafe-paths0 y escribe fuera. El man: es para “better GNU patch”, no para un agente.

--binary es no-op: el man, Currently, we always allow binary patch application. Un git diff --binary se pegó con 0 sin el flag.

--check no escribe; apply sin --index deja el índice intacto

Lo que el agente sí / no corre

QuieroComandoTrampa
¿Este diff pega?git apply --check -- "$patch"git apply a ciegas
Pegar en el worktreegit apply -- "$patch"--index “por si acaso”
Ver el diffstatgit apply --stat -- "$patch"volcar el parche al LLM
Deshacergit apply -R -- "$patch" o restore--reject
Convertir en commitadd paths + git commitcreer que apply ya commitó
Serie con mensajegit am (otro comando)apply en un .mbox

Prohibido en autónomo:

  • --unsafe-paths. El man rechaza paths fuera del working area as a mistake (or a mischief). Verificado: con el flag escribe ../outside.txt. Nunca.
  • --reject. El default es atómico: si un hunk falla, no toca el árbol. --reject pega lo que puede y deja *.rej. Verificado: f.txt.rej, 1. Eso no es un apply limpio.
  • --3way / --ours / --theirs / --union. --3way implica --index (salvo --cached) y puede dejar conflict markers. Resolución a ciegas no.
  • --directory, -p N o --include/--exclude “para que pase”. Cambian dónde pega. Si el dest no existe, 1.
  • Tratar 0 como “ya está en HEAD”. Verificado: tras apply, el log no avanza.
  • git apply sobre main del checkout principal. Solo worktree propio.
  • Volcar el parche, el .rej o git diff entero al LLM. status -sb + --stat.

El parche se genera con diff, no con apply. Un agente que “inventa el hunk” y lo pega está un paso más allá de este comando.

Receta (60 segundos)

Solo en un worktree propio:

git status -sb
git apply --check -- "$patch" || exit 1
git apply -- "$patch"
git status -sb
git diff --stat

Si --check es 1: no --reject, no -C0, no --unidiff-zero. El man desalienta diffs sin contexto. Reporta el error y para.

Si el árbol queda mal: restore paths, no reset --hard.

Cierre = add de paths + commit + PR. Cero push a main. Cero --unsafe-paths.

0 no es commit; HEAD sigue donde estaba

apply vs am vs cherry-pick

apply pega bytes. git am parte un mailbox, aplica y committea con autor/mensaje (SEE ALSO del man). cherry-pick copia un objeto commit del grafo. Tres verbos, tres destinos.

Un agente que “aplica el PR” con git apply de un git diff no replica el commit de GitHub: pierde autor, mensaje y SHA. Si el ticket es “trae el commit”, cherry-pick o am de un format-patch. Si el ticket es “pega este diff en el worktree”, este comando.

--index cuando el siguiente paso es commit y el árbol ya está limpio. Si el working tree no coincide con el índice, el man falla a propósito. Entonces: restore o aplica solo al disco y add paths.

Checklist

  • Worktree propio. git status -sb. Un parche por comando.
  • --check primero. 0 = pega. 1 = para. Cero --reject.
  • Default: git apply -- "$patch". --index solo si el índice debe cambiar y ya coincide.
  • Cero --unsafe-paths / --3way / --directory / -p autónomo.
  • 0 no es commit. status -sb + diff --stat.
  • Cierre = add paths + PR, no push a main.

FAQ

¿git apply crea un commit? No. El man lo dice. Verificado: el log no avanza. Commit es am o commit después de add.

¿Hace falta un repo? No, sin --index/--cached. Verificado fuera de Git: pega el archivo y sale 0. --intent-to-add sí exige repo; si no, el man lo ignora.

¿--unsafe-paths “solo si el patch lo pide”? No. Default 128 en ../outside.txt. Con el flag escribe fuera. Nunca en autónomo.

El curso instalar un agente cubre el loop local. Hub: comparativas y decisiones. apply no es cherry-pick: pega el diff, no el commit.