Revertir Commit de Fusion en Git: Una Guía Con Ejemplos

Podemos comprometer una aplicación fusionando código problemático, ya sea por integrar accidentalmente trabajo inacabado en la rama principal o por pasar por alto un error crítico que se filtró en las pruebas automatizadas.

En este artículo, te guiaré a través del proceso de usar git revert para deshacer de manera segura una fusión, asegurando que el historial de commits permanezca intacto y se preserve la integridad del proyecto.

Cómo Funciona git revert

Podemos pensar en git revert como la versión de Git del comando deshacer. Sin embargo, el comando git revert no elimina commits ni salta a un estado anterior de la rama. En su lugar, crea un nuevo commit que revertirá los cambios de un commit específico.

La sintaxis para revertir un commit con el hash <commit_hash> es:

git revert <commit_hash>

Podemos listar los commits junto con sus identificadores de hash usando el comando git log. La salida de git log lista los commits de más reciente a más antiguo, así:

Por ejemplo, para revertir el commit que implementa la función de resta, usaríamos el siguiente comando:

git revert 7ba24a3e62d4d37182428ccfaa070baa222b1151

Usando git revert podemos deshacer los cambios de un commit específico sin afectar el historial de commits.

Tenga en cuenta que git revert no es mágico, y dependiendo del historial de commits, puede resultar en un conflicto que tiene que ser resuelto manualmente.

Ventajas de git revert Frente a Cambios Manuales

¿Por qué es útil git revert si podemos necesitar resolver un conflicto manualmente? ¿No sería más fácil simplemente deshacer los cambios manualmente? Veamos sus ventajas:

  • Preserva el historial: git revert crea un nuevo commit que deshace los cambios de un commit especificado mientras preserva todo el historial de commits. Esto ayuda a mantener un historial transparente de cambios y reversales.
  • Reversión atómica: Asegura que las reversaciones sean atómicas y consistentes. Cuando eliminamos y comprometemos cambios manualmente, hay un riesgo de error humano.
  • Conciencia de conflictos: Asegura que seamos alertados a través de conflictos si hay integraciones o cambios dependientes del commit original. Esto puede parecer inconveniente, pero protege contra efectos secundarios no deseados.
  • Metadatos: El nuevo commit creado por git revert incluye metadatos y un mensaje de commit que describe contextualmente lo que fue revertido, ayudando en la comprensión futura. Sin git revert, este contexto podría perderse.

Revertir una Fusión en Diferentes Escenarios

En esta sección, aprendemos cómo deshacer una fusión. A modo de ejemplo, asumimos que estamos fusionando una rama llamada feature en la rama main ejecutando el comando desde la rama main:

git merge feature

Lo que aprendamos aquí puede aplicarse a cualquier par de ramas reemplazando los nombres appropriately.

Revertir una fusión que no tiene un commit asociado

El comando git merge no siempre crea un nuevo commit. Un commit se crea solo si la rama main se ha desviado de la rama feature. Porque git revert requiere un commit para operar, no podemos usarlo en este caso.

Las ramas main y feature se desvían cuando se crean nuevos commits en main que no son ancestros de la rama feature. En otras palabras, se crearon nuevos commits en main después de que se creó feature.

Si las ramas no se han desviado, al ejecutar el comando git merge feature en la rama principal, Git utilizará un fast-forward para fusionar. Esto significa que mueve el HEAD de la rama main al HEAD de la rama feature.

Podemos observar que esto ocurrió mirando el resultado del git merge:

Para deshacer tal fusión, solo necesitamos mover el HEAD de la rama main a donde estaba. Para esto, nosotros:

  1. Identificamos el HEAD anterior usando el git reflog
  2. Restablece el HEAD al anterior usando git reset --hard <previous_head>, reemplazando <previous_head> con el HEAD anterior.

La salida de git reflog se verá algo como esto:

Podemos identificar el HEAD anterior mirando la línea que dice “checkout: moving from feature to main” (escribe feature y main porque esos son los nombres de nuestras ramas). 

En este caso, el HEAD anterior es fe59838. Para mover el HEAD de la rama principal hacia atrás y deshacer la fusión, usamos el comando:

git reset --hard fe59838

Revertir una fusión que tiene un commit asociado

Si las ramas main y feature han divergido, entonces al fusionar dos ramas, se crea un nuevo commit, llamado commit de fusión. 

El commit de fusión aplica los cambios de una rama a otra. En este caso, los cambios en feature se aplican a la rama main.

Para revertir los cambios en la rama main, usamos git revert en el commit de fusión. Esto creará un nuevo commit que deshace los cambios introducidos en la rama main con la fusión, restaurando efectivamente el estado de la rama principal al que tenía antes de la fusión.

Primero, necesitamos identificar el hash del commit de fusión. Podemos hacer esto utilizando el comando git log:

Debido a que el commit de fusión tiene dos padres, la sintaxis de git revert es ligeramente diferente. Necesitamos usar la opción -m 1 para especificar que queremos revertir los cambios relativos a la rama main:

git revert -m 1 b8dab2c8611e324ed0d273133987415350e6d10d

Resolución de Conflictos al Revertir un Commit

En algunos casos, pueden surgir conflictos al revertir un commit, especialmente si el commit que se revierte entra en conflicto con cambios posteriores en el código base. En tales casos:

  1. Git pausará la reversión: Necesitamos resolver los conflictos manualmente. Git marcará los archivos en conflicto y requerirá intervención.
  2. Resolver los conflictos: Abrimos cada archivo en conflicto, resolvemos los conflictos marcados por Git, y guardamos los cambios.
  3. Stage los archivos resueltos: git add <ruta-del-archivo>
  4. Continuar con la reversión: git revert --continue

Conclusión

Usar git revert para deshacer commits de fusión asegura que cada cambio y corrección esté documentado dentro del historial de commits.

Además, entender los escenarios adecuados para aplicar git reset frente a git revert nos permite tomar mejores decisiones, especialmente cuando se considera flujos de trabajo colaborativos o cambios locales exclusivamente.

Puedes leer más sobre este tema en la sección de preguntas frecuentes a continuación. Si deseas aprender más sobre Git, te recomiendo estos recursos:

Source:
https://www.datacamp.com/tutorial/git-revert-merge