CommunityProgramación y desarrollogithub.com

resolución de conflictos git

Resuelve conflictos de fusión, rebase, cherry-pick, revert o stash-pop de forma correcta: entiende lo que cada lado intentaba, combínalos en lugar de elegir uno, verifica que la compilación funciona y continúa la operación.

¿Qué es resolución de conflictos git?

Este skill para agentes de IA (como Claude Code, Cursor o Codex) está diseñado para manejar conflictos de merge, rebase, cherry-pick, revert y stash-pop en Git. En lugar de resolver simplemente borrando los marcadores `<<<<<<<` eligiendo un lado arbitrariamente (lo que descarta trabajo de alguien), el agente entiende el contexto de cada operación (sabiendo que en rebase `--ours` y `--theirs` están invertidos respecto a un merge), muestra el conflicto completo incluyendo el ancestro común con `zdiff3`, y combina los cambios de ambos lados según la intención. También verifica que no queden marcadores de conflicto, compila y ejecuta pruebas rápidas, y luego continúa la operación con el comando adecuado (`git rebase --continue`, etc.). Es útil siempre que el usuario se encuentre con conflictos de contenido, mensajes "both modified" o "deleted by us/them", o pida "arreglar conflictos". Incluye reglas para no usar `--ours`/`--theirs` indiscriminadamente, y para detenerse y preguntar cuando la resolución no es clara, evitando daños irreversibles.

Compatible con~Claude Code~Codex CLI~Cursor
npx skills add https://github.com/roselletabuena/skills/tree/HEAD/plugins/git-workflows/skills/git-conflict-resolution

Installed? Explore more Programación y desarrollo skills: steipete/bluebubbles, steipete/eightctl, steipete/blucli · View all 6 →

Preguntar en tu IA favorita

Abre un nuevo chat con esta habilidad de agente ya precargada.

Documentación

Resolución de conflictos

Un conflicto significa que Git encontró dos cambios en el mismo lugar y se niega a adivinar. Una resolución es una decisión sobre la intención, y la opción segura por defecto es conservar la intención de ambos lados. Resolver borrando un lado hace desaparecer los marcadores pero empeora el problema: la compilación sigue pasando, y el cambio de un colega desaparece.

1. Saber en qué operación estás — ours y theirs dependen de ello

git status                  # "rebase in progress" / "You have unmerged paths" / "cherry-pick in progress"
OperaciónLado --ours / HEADLado --theirs
mergela rama en la que estásla rama que se fusiona
rebasela rama sobre la que estás haciendo rebase (upstream)tu propio commit que se está reproduciendo
cherry-pick, revert, stash popla rama en la que estásel commit que se aplica

La fila de rebase es la trampa. Durante git rebase main, "ours" es main y "theirs" es el trabajo del propio usuario, lo contrario que en un merge. git checkout --theirs archivo en un rebase conserva tu cambio y descarta el de upstream. Vuelve a leer esta tabla antes de usar cualquiera de las dos banderas.

2. Ver el conflicto completo, no solo los marcadores

git diff --name-only --diff-filter=U        # archivos sin fusionar
git status                                   # el tipo: ambos modificados / eliminado por nosotros / ambos agregados
git config merge.conflictStyle zdiff3        # muestra también el ancestro común (git 2.35+; usa diff3 en versiones anteriores)
git checkout --conflict=zdiff3 -- <archivo>  # vuelve a mostrar UN archivo con la base visible (descarta las ediciones ya hechas)

Con la base visible, los marcadores tienen tres partes: tu lado, el original, su lado. La mayoría de los conflictos aparentes se vuelven obvios cuando puedes ver de qué cambió cada lado.

Para entender por qué cambió cada lado:

git log --merge -p -- <archivo>                 # commits de ambos lados que tocan el archivo (merge o rebase en curso)
git show REBASE_HEAD                          # durante un rebase: el commit que se está reproduciendo
git show :1:<archivo>  :2:<archivo>  :3:<archivo>     # base, "ours", "theirs" como archivos completos

Lee los mensajes de commit. Una resolución que no puedas explicar en una frase por lado es una suposición.

3. Resolver combinando

  • Ambos lados editaron las mismas líneas por razones diferentes: escribe la versión que haga ambas cosas. Por ejemplo, un lado añadió un parámetro tax_rate y el otro un parámetro discount: la función resuelta toma ambos y aplica ambos.
  • Un lado movió o renombró, el otro editó: aplica la edición en la nueva ubicación. No conserves el archivo antiguo y el nuevo.
  • Eliminado por un lado, modificado por el otro: esto es una decisión real, no mecánica. Averigua por qué se eliminó; si la modificación sigue siendo relevante, debe trasladarse; de lo contrario, gana la eliminación. Pregunta al usuario si no está claro.
  • Archivos generados y archivos de bloqueo (package-lock.json, poetry.lock, go.sum, instantáneas, salida compilada): no los fusiones manualmente. Toma cualquier lado y luego vuelve a generar con la herramienta (npm install, poetry lock, go mod tidy, el comando de instantánea).
  • Archivos binarios: no hay fusión posible; elige un lado deliberadamente (ten en cuenta la tabla anterior) y dílo.

El texto puede fusionarse limpiamente y seguir estando mal: si un lado renombró una función y el otro añadió una llamada al nombre antiguo, Git no ve conflicto. Por eso el paso 4 incluye compilar.

Las banderas generales ocultan decisiones. git checkout --ours ., -X ours / -X theirs (que resuelven cada fragmento conflictivo hacia un lado) y -s ours (que descarta la otra rama por completo) descartan trabajo sin mirarlo. Úsalas solo cuando el usuario haya pedido exactamente eso y sepa lo que se está descartando.

4. Verificar, luego continuar

git diff --check                              # falla si quedan marcadores de conflicto o errores de espacio en blanco
grep -rnE '^(<<<<<<<|=======|>>>>>>>)' .      # cinturón y tirantes, en archivos que git diff-check no revisa
# compilar y ejecutar las pruebas relevantes más rápidas
git add <archivos-resueltos>

Continúa con el comando correspondiente. Añade GIT_EDITOR=true donde se abriría un editor, ya que un editor se cuelga en una terminal no interactiva:

git merge --continue            # o: git commit --no-edit
GIT_EDITOR=true git rebase --continue
GIT_EDITOR=true git cherry-pick --continue

Un rebase reproduce commits uno a uno, por lo que puede detenerse de nuevo en el siguiente commit. Repite el bucle. Resuelve en el primer commit donde aparezca un conflicto; los posteriores pueden ser el mismo conflicto reproduciéndose.

Si las pruebas fallan después de resolver, el fallo es información sobre la resolución. No continúes ignorándolo ni "lo arregles" editando las pruebas hasta que sepas qué comportamiento de qué lado está protegiendo la prueba.

5. Cuándo detenerse y preguntar

Detente en lugar de adivinar cuando:

  • ambos lados cambiaron la lógica de negocio de formas incompatibles (dos reglas fiscales diferentes, dos políticas de reintento diferentes);
  • no puedes decir en una frase por qué cada lado hizo su cambio;
  • la resolución hace que falle una prueba y la causa no está clara.

Indica las dos intenciones, di qué elegirías y por qué, y deja que el usuario decida. Todo antes de --continue es reversible: git merge --abort, git rebase --abort, git cherry-pick --abort devuelven el árbol a su estado inicial.

Conflictos repetidos

Para un rebase largo donde el mismo conflicto se repite, o una rama que se fusiona y abandona repetidamente:

git config rerere.enabled true      # registra cada resolución y la reproduce la próxima vez
git rerere diff                      # lo que registró
git rerere forget-path <archivo>        # descarta una resolución registrada que era incorrecta

rerere reaplica una resolución sin preguntar, por lo que una mala se propaga. Después de un conflicto resuelto por rerere, sigue verificando el resultado.

Cuando una rama tiene mucha vida y está muy desactualizada, fusionar el tronco una vez normalmente significa una ronda de conflictos; hacer rebase los reproduce por commit. Esa elección es del usuario.

Barreras de seguridad

  • Nunca resuelvas tomando un lado por completo para que desaparezcan los conflictos. El otro lado es el trabajo de alguien.
  • No abortes un rebase que el usuario te pidió terminar solo porque sea tedioso; aborta solo si va mal, y dilo.
  • No hagas push después de resolver a menos que te lo pidan. Un rebase necesita un force-push; sigue git-safe-history-rewrite.
  • Informa sobre cada archivo en conflicto: qué hizo cada lado, qué conservaste y cualquier cosa que no pudieras verificar.

Individual skills in this repo

This repo contains 2 individual skills — each has its own dedicated page.

Skills relacionados