Guía10 min

git revert para coding agents: commit nuevo que deshace, no reset

Resumen

git revert graba commits nuevos que invierten un parche ya existente. Exige working tree limpio. Merge: -m no se adivina. Conflicto: --abort, no --continue. GitHub Revert abre otro PR. Un agente no usa reset --hard para deshacer historia publicada. Man git-revert 2.50.1.

GitHub
Un commit C publicado se invierte con C′, un SHA nuevo; HEAD 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 revert no borra el commit malo. El man (Git 2.50.1 / Apple Git-155): “Given one or more existing commits, revert the changes that the related patches introduce, and record some new commits that record them.” El working tree tiene que estar limpio (sin modificaciones respecto a HEAD). El SHA original sigue en la historia.

No es reset (mueve HEAD; --hard pisa disco) ni restore (copia paths). git(1) lo parte en tres: revert = commit nuevo que deshace; restore = archivos, no mueve la rama; reset = mueve la punta. GitHub, con write, puede abrir un PR que revierte el merge commit; un coding agent usa el CLI y el sequencer.

Esta guía no sustituye worktrees ni PRs con gh. El contrato: cuándo un agente puede revertir, qué flags están prohibidos, y cómo abortar.

Qué hace (y qué no)

Un commit C ya está en main (o en cualquier punta publicada). git revert C aplica el inverso del diff de C y graba C′. Autor/committer = quien revierte. SHA distinto. C no desaparece.

El man contrapone explícitamente:

  • Tirar cambios sin commiteargit reset, en particular --hard. Eso no es revert.
  • Extraer un archivo como estaba en otro commit → git restore --source.

Si el parche inverso no aplica:

  1. La rama y HEAD se quedan en el último revert exitoso.
  2. El sequencer queda en curso (.git/sequencer).
  3. Paths en conflicto: marcadores <<<<<<< / >>>>>>>.
  4. --abort vuelve al estado pre-secuencia. --quit solo olvida el sequencer y no restaura.

No hay rewind de historia. No hay force-push. Es un parche inverso.

El diff de C se invierte y nace C′; C sigue en la historia

Lo que el agente sí / no corre

QuieroComandoTrampa
Deshacer un SHA publicadogit revert --no-edit <sha>--edit es el default en terminal; headless se cuelga del editor
Parar a mitadgit revert --abort--quit olvida el sequencer y no vuelve al estado previo
Seguir tras resolver a manogit add paths + git revert --continueHeadless no resuelve <<<<<<<
Saltar este commit del rangogit revert --skipSolo con secuencia en curso
Aplicar sin commiteargit revert -n <sha>Deja el inverso en index/disco. El index no tiene que coincidir con HEAD
Revertir un mergegit revert -m <n> <merge-sha>-m es el padre (desde 1). No se adivina

Prohibido en autónomo:

  • Revert con working tree sucio. El man lo exige limpio.
  • Revert de un merge commit sin -m <n> escrito en el ticket. El man: “Usually you cannot revert a merge because you do not know which side of the merge should be considered the mainline.” Revertir un merge declara que nunca querrás el árbol que trajo esa fusión; merges posteriores solo traen cambios que no son ancestros de ese merge. Eso no es “deshacer el PR”.
  • -X ours / -X theirs. Un agente no elige un lado.
  • Rangos (master~5..master~2) salvo ticket que nombre exactamente el conjunto. Default: un SHA.
  • --continue después de borrar marcadores a ciegas. Reporta git diff --name-only --diff-filter=U y --abort.
  • Revert sobre main local + push. El inverso va a una rama topic y un PR.
  • Confundir revert con reset --hard “para que main quede como antes”. Reset reescribe historia; en rama publicada eso pide force-push, que el agente no corre.
  • Revertir un revert en bucle. El man: sujetos tipo Reapply "Reapply "<original>". Si hay que reaplicar, un commit nuevo con mensaje propio, no revert del revert a ciegas.

--no-edit usa el mensaje automático (This reverts <sha>.). El man recomienda explicar por qué. Si el ticket trae la razón, --no-edit y luego git commit --amend solo si el commit aún no salió del worktree y no hay amend+force.

Receta (60 segundos)

Solo en un worktree propio, working tree limpio, SHA nombrado:

git status -sb                    # limpio; no revert in progress
git rev-parse --verify <sha>^{commit}
git revert --no-edit <sha>

Conflicto:

git diff --name-only --diff-filter=U
git revert --abort

Varios SHAs en orden, no un rango opaco:

git revert --no-edit abc123 def456

Cada uno genera su commit. Si el segundo falla, HEAD quedó en el primero.

GitHub (doc 200, 2026-09-03): el botón Revert de un PR ya mergeado abre otro PR que revierte el merge commit. Hace falta permiso write. Si no aparece, no hay write. Si el revert del PR pelea o el original no se mergeó en GitHub, la misma doc manda a git revert commit a commit. El agente no pulsa el botón; corre el man y abre el PR con gh.

Conflicto: aborta; no resuelvas marcadores a ciegas

Revert vs reset vs restore

ComandoHistoriaUso del agente
revert CCommit nuevo que deshace el diff de CDeshacer un commit/merge ya publicado, vía PR
reset --hard CMueve HEAD a C; pisa discoProhibido en autónomo. No es undo de producción
restore -- pathNo mueve la ramaDeshacer edits locales de un path

El ejemplo del man git revert HEAD~3 revierte un commit (el cuarto detrás de HEAD), no “los últimos tres”. git revert -n master~5..master~2 aplica el inverso de ese rango sin commitear. Un agente no traduce “quita lo de ayer” a HEAD~n.

Checklist

  • Worktree propio, git status -sb limpio, sin sequencer previo.
  • Un SHA (o lista explícita). Cero merges sin -m pedido por escrito.
  • --no-edit en headless. Razón del ticket en el cuerpo si el humano la dio.
  • Conflicto → --abort + paths. Cero --continue autónomo.
  • El commit nuevo va a una rama topic + PR. Cero revert sobre main.
  • No reset --hard ni force-push “para igualar”.
  • No revert-del-revert sin mensaje nuevo y ticket.

FAQ

¿Puedo revertir un merge con -m 1? El man lo permite: -m es el número de padre (desde 1) que cuentas como mainline, y replayea el inverso respecto a ese padre. Un agente no elige 1 vs 2. Si el ticket no dice el padre, no revierte el merge. El howto revert-a-faulty-merge (nota 1 del man) explica el efecto permanente en merges posteriores.

¿-n es más seguro? --no-commit aplica al index/disco y no crea commit. Útil para inspeccionar varios inversos juntos. Headless: no lo uses para “acumular y ya commiteo yo” sin git diff --cached revisado.

¿--skip vs --abort? Skip descarta este commit de la secuencia y sigue. Abort tira toda la secuencia y vuelve atrás. Con un solo SHA, abort.

¿El botón Revert de GitHub? Crea un PR nuevo del merge commit. Misma semántica que git revert -m 1 <merge> sobre la default branch, encapsulada en UI. Conflictos → commits sueltos con el CLI.

El curso instalar un agente cubre el loop local. Aislamiento: sandboxing. Revert no es sandbox ni undo de untracked (clean).

Verificado 2026-09-03 contra git-revert(1) y git(1) (Git 2.50.1 / Apple Git-155; man 2.54.0 2026-04-19) y GitHub Docs “Reverting a pull request” (HTTP 200).