git merge para coding agents: commit de fusión, no rebase ni -X ours
Resumen
git merge une historias. Fast-forward mueve HEAD; si no, crea un commit con dos padres. Un agente no mergea con working tree sucio, no resuelve -X ours/theirs y aborta ante conflicto. Man git-merge y GitHub Docs.

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 merge une dos o más historias en la rama actual. El man (Git 2.50.1 / Apple Git-155): incorpora los commits nombrados desde que divergieron. git pull lo usa por debajo. No reescribe SHA: o hace fast-forward (mueve el puntero) o crea un commit de fusión con dos padres.
Con topic = A—B—C encima de E, y master = D—E—F—G, git merge topic deja H con padres G y C. Antes, ORIG_HEAD apunta a G.
GitHub Docs: el botón Merge pull request usa --no-ff. Un coding agent que “limpia” con rebase + force no es este flujo. Ante conflicto, GitHub desactiva el merge hasta que alguien elija el contenido final.
Esta guía no sustituye worktrees ni PRs con gh. El contrato: cuándo un agente puede mergear, qué flags están prohibidos, y cómo abortar.
Fast-forward vs true merge
El man parte el comando en tres salidas:
| Caso | Qué pasa | Commit de fusión |
|---|---|---|
| Named commits ya son ancestros de HEAD | Sale con Already up to date. | No |
HEAD es ancestro del named commit (--ff, default) | HEAD + index apuntan al named commit | No |
| Historias divergieron | Commit nuevo con ambos padres (ort, default para un head) | Sí |
--no-ff: siempre crea el commit de fusión, aunque se pudiera fast-forward. Es lo que GitHub hace al mergear un PR.
--ff-only: si no es fast-forward, rehúsa y sale ≠ 0. Útil para “solo actualizar tracking”, no para integrar un topic.
--no-commit: para el merge antes de crear el commit, para inspeccionar. El man: un fast-forward no se detiene con --no-commit (no hay merge commit). Si el agente necesita “no mover la rama todavía”, usa --no-ff --no-commit.

Lo que el agente sí / no corre
| Quiero | Comando | Trampa |
|---|---|---|
Traer origin/main a mi topic | git fetch origin && git merge origin/main | Merge con dirty tree. El man lo desaconseja |
| Parar a mitad | git merge --abort | --quit deja index y disco como están |
| Seguir tras resolver | git add paths + git merge --continue | --continue llama a commit solo si hay merge interrumpido |
| Integrar el PR en main | gh pr merge, no git merge en main local | Merge local a main + push salta review |
| Aceptar el mensaje auto | --no-edit o GIT_MERGE_AUTOEDIT=no | --edit abre editor. Headless no es ese flujo |
Prohibido en autónomo:
- Merge con cambios uncommitted no triviales. PRE-MERGE CHECKS: si el index no coincide con HEAD, aborta; si untracked/edits solapan paths que el merge actualizaría, aborta. El warning: “Running git merge with non-trivial uncommitted changes is discouraged.”
--aborta veces no reconstruye esos edits. -X ours/-X theirs. El man:-X oursresuelve hunks en conflicto a favor de “ours”; el resto del otro árbol sí entra. No es-s ours, que tira el otro árbol entero. Un agente no elige un lado.-s ours, octopus (git merge a b),--allow-unrelated-histories. Sin ancestro común el default rehúsa; no hay config para activarlo.--squash. Deja el árbol como un merge pero no escribeMERGE_HEAD; el siguiente commit no es de fusión.--commitcon--squashfalla.--no-verify. Saltapre-mergeycommit-msg. Default es correrlos.--autostash“por si acaso”. El man: el apply final puede pelear.git mergetool. Interactivo.- Resolver marcando a ciegas
<<<<<<</=======/>>>>>>>. GitHub: “You must resolve all merge conflicts before you can merge a pull request.” Default del agente:--aborty reportar paths (git diff --name-only --diff-filter=U).
--abort ≡ git reset --merge si hay MERGE_HEAD (salvo MERGE_AUTOSTASH, que re-aplica el stash). Ver reset. --quit olvida el merge y no limpia.
Receta (60 segundos)
Solo en un worktree propio, working tree limpio:
git status -sb # no dirty; no merge in progress
git fetch origin
git merge origin/main --no-edit
Conflicto:
git diff --name-only --diff-filter=U
git merge --abort
--abort: “reconstruct the pre-merge state.” Si arrancaste sucio, puede no devolver esos edits. Por eso el status primero.
Tras un merge limpio: push normal a la rama del PR. Cero --force. El merge commit es historia hacia adelante.
Si el ticket es “actualizar main”: no. Abre o actualiza el PR; el humano (o gh pr merge) integra con --no-ff.
Conflictos en un archivo: stages 1/2/3 en el index (git ls-files -u). Stage 1 = ancestro, 2 = HEAD, 3 = MERGE_HEAD. El working tree trae marcadores. ort (default) también escribe AUTO_MERGE. El agente no pisa stages a mano.

Merge vs rebase vs GitHub
- merge: commit nuevo (o FF). SHA viejos siguen. Eso va a un PR.
- rebase: reaplica y cambia SHA. Otra guía; no es el default para una rama ya pusheada.
- GitHub merge commit:
--no-ff. Squash and merge aplana; Rebase and merge reescribe. Un agente no elige squash/rebase del PR salvo orden escrita.
git pull sin args = fetch + merge del upstream configurado. Un agente nombra origin/main. Sin upstream, el merge sin <commit> no tiene a quién unir.
Checklist
-
status -sblimpio. Cero merge a medias (MERGE_HEAD). - Fetch primero. Upstream explícito (
origin/main). - Conflicto →
--abort+ lista de paths. Cero-X ours/theirs. - Cero
--squash,-s ours, octopus,--no-verify,--autostash. - Cero merge a
mainlocal. Integración = PR. - Push normal. Cero force.
-
--quitno es abortar.
FAQ
¿git merge sin args? Une el upstream de branch.<name>.merge. Sin upstream, aborta. Nombra el ref.
¿--no-ff siempre? En un topic que solo quiere ponerse al día con main, el default --ff basta si no divergiste. Si divergiste, sale true merge. En el botón de GitHub, sí: --no-ff.
¿Puedo dejar marcadores y commitear? No. El merge no termina hasta git add de cada path en conflicto + --continue. Commitear marcadores rompe el build.
¿merge.conflictStyle=diff3? Añade ||||||| con el ancestro. Útil para un humano. Un agente que aborta no lo necesita.
¿Hooks? pre-merge y commit-msg corren. --no-verify los salta. No lo uses.
El curso instalar un agente cubre el loop local. Merge no reescribe SHA; no es sandbox ni permiso para tocar main.
Verificado 2026-09-03 contra git-merge(1) (Git 2.50.1 / Apple Git-155), GitHub Docs About merge conflicts y About pull request merges (HTTP 200).
Lecturas relacionadas
Sigue explorando Coding Agents y otras piezas para builders.

git status para coding agents: porcelain, XY, no el long

Reusable workflows: workflow_call, no copies el YAML entre repos

schedule (cron) en GitHub Actions: UTC, no cada minuto
