Usar ramas

Git merge

 

La fusión es la forma que tiene Git de volver a unir un historial bifurcado. El comando git merge permite tomar las líneas independientes de desarrollo creadas por git branch e integrarlas en una sola rama.

Ten en cuenta que todos los comandos presentados a continuación se fusionan en la rama actual. La rama actual se actualizará para reflejar la fusión, pero la rama de destino no se verá afectada en absoluto. Una vez más, esto significa que git merge se suele utilizar junto con git checkout para seleccionar la rama actual y git branch -d para eliminar la rama de destino obsoleta.

Funcionamiento

git merge combinará varias secuencias de confirmaciones en un historial unificado. En los casos de uso más frecuentes, git merge se utiliza para combinar dos ramas. Los ejemplos siguientes del presente documento se centrarán en este patrón de fusión de ramas. En estos casos, git merge toma dos punteros de confirmación, normalmente los extremos de la rama, y encuentra una confirmación base común entre ellos. Una vez que Git encuentra una confirmación base, crea una "confirmación de fusión" nueva que combina los cambios de cada secuencia de confirmación de fusión puesta en cola.

Supongamos que tenemos una rama de funcionalidad nueva que se basa en la rama master. Ahora, queremos fusionar esa rama de funcionalidad con la master.

Al invocar este comando, la rama de funcionalidad especificada se fusionará con la rama actual, la cual asumiremos que es la master. Git determinará el algoritmo de fusión automáticamente (véase más adelante).

Las confirmaciones de fusión son únicas con respecto a otras confirmaciones en el hecho de que tienen dos confirmaciones principales. Al crear una confirmación de fusión, Git tratará de fusionar automáticamente los historiales independientes. Sin embargo, si encuentra datos que se han cambiado en ambos historiales, no podrá combinarlos de ese modo. En ese caso, se crea un conflicto de control de versiones y Git solicitará la intervención del usuario para poder continuar. 

Preparación para fusionar

Antes de ejecutar una fusión, hay un par de pasos de preparación que llevar a cabo con el fin de garantizar que la fusión se realice sin problemas.

Confirmación de la rama de recepción

Ejecuta git status para asegurarte de que HEAD apunta a la rama de fusión-recepción correcta. En caso necesario, ejecuta git checkout <receiving> para cambiar a la rama de recepción. En nuestro caso, ejecutaremos git checkout master.

Recuperación de las últimas confirmaciones remotas

Asegúrate de que la rama de recepción y la rama de fusión están actualizadas con los últimos cambios remotos. Ejecuta git fetch para extraer las últimas confirmaciones remotas. Una vez que la recuperación se haya completado, asegúrate de que la rama master tenga las últimas actualizaciones mediante la ejecución del comando git pull.

Fusión

Una vez adoptados los pasos comentados anteriormente de "preparación para la fusión", es posible iniciar una fusión mediante la ejecución de git merge <branch name> donde <branch name> es el nombre de la rama que se fusionará con la rama de recepción.

Fusión con avance rápido

Puede que se produzca una fusión con avance rápido cuando hay un proceso lineal desde el extremo de la rama actual hasta la rama de destino. En lugar de fusionar “realmente” las ramas, todo lo que Git tiene que hacer para integrar los historiales es mover (es decir, realizar un “avance rápido”) el extremo de la rama actual al extremo de la rama de destino. De este modo, combina de manera eficaz los historiales, ya que todas las confirmaciones alcanzables desde la rama de destino están ahora disponibles a través de la rama actual. Por ejemplo, una fusión con avance rápido de alguna rama de funcionalidad en una master se vería de la siguiente manera:

Sin embargo, no es posible una fusión con avance rápido si las ramas han divergido. Cuando no hay un proceso lineal hacia la rama de destino, Git no tiene más opción que combinarlas mediante una fusión de 3 vías. Las fusiones de 3 vías utilizan una confirmación específica para unir dos historiales. Esta fusión recibe su nombre del hecho de que Git utiliza tres confirmaciones para generar la confirmación de fusión: los dos extremos de la rama y su predecesor común.


Aunque se pueden utilizar cualquiera de estas estrategias de fusión, a muchos desarrolladores les gusta utilizar las fusiones con avance rápido (facilitadas a través del comando rebasing) para funcionalidades pequeñas o correcciones de errores, mientras que se reservan las fusiones de 3 vías para la integración de funcionalidades con una ejecución de mayor duración. En este último caso, la confirmación de fusión resultante sirve como una unión simbólica de las dos ramas.

Nuestro primer ejemplo muestra una fusión con avance rápido. El código a continuación crea una rama nueva, le añade dos confirmaciones y, seguidamente, la integra en la línea principal con una fusión con avance rápido.

# Start a new feature
git checkout -b new-feature master
# Edit some files
git add <file>
git commit -m "Start a feature"
# Edit some files
git add <file>
git commit -m "Finish a feature"
# Merge in the new-feature branch
git checkout master
git merge new-feature
git branch -d new-feature

Se trata de un flujo de trabajo común para las ramas temáticas transitorias que se utilizan más como un desarrollo aislado que como una herramienta de organización para funcionalidades con una ejecución de mayor duración.

Ten en cuenta también que Git no debería quejarse sobre el comando git branch -d, ya que ahora es posible acceder a la funcionalidad nueva desde la rama maestra.

En caso de necesitar una confirmación de fusión durante una fusión con avance rápido para mantener registros, es posible ejecutar git merge con la opción --no-ff.

git merge --no-ff <branch>

Este comando fusiona la rama especificada en la rama actual, pero siempre genera una confirmación de fusión (incluso si se trata de una fusión con avance rápido). Esto resulta útil para documentar todas las fusiones que tienen lugar en tu repositorio.

Fusión de 3 vías

El siguiente ejemplo es muy similar, pero requiere una fusión de 3 vías porque la rama master avanza mientras la funcionalidad está en curso. Este es un caso habitual con funcionalidades grandes o cuando hay varios desarrolladores trabajando en un proyecto simultáneamente.

Start a new feature
git checkout -b new-feature master
# Edit some files
git add <file>
git commit -m "Start a feature"
# Edit some files
git add <file>
git commit -m "Finish a feature"
# Develop the master branch
git checkout master
# Edit some files
git add <file>
git commit -m "Make some super-stable changes to master"
# Merge in the new-feature branch
git merge new-feature
git branch -d new-feature

Ten en cuenta que es imposible que Git lleve a cabo una fusión con avance rápido, ya que no hay forma de mover la rama master a la de new-feature sin retroceder.

Para la mayoría de los flujos de trabajo, la rama de new-feature sería mucho más grande y tardaría mucho más tiempo en desarrollarse, por lo que, mientras tanto, las nuevas confirmaciones aparecerían en la rama master. Si tu rama de funcionalidad fuera en realidad tan pequeña como la del ejemplo anterior, probablemente sería mejor que la cambiases de base a la rama master haciendo una fusión con avance rápido. Esto evitaría que confirmaciones de fusión superfluas desordenasen el historial del proyecto.

Resolución de conflicto

Si las dos ramas que tratas de fusionar han cambiado la misma parte del mismo archivo, Git no podrá averiguar qué versión utilizar. Cuando esto ocurre, Git se detiene justo antes de la confirmación de fusión para que puedas resolver los conflictos manualmente.

La mayor parte del proceso de fusión de Git consiste en utilizar el conocido flujo de trabajo de edición, preparación y confirmación para resolver los conflictos de fusión. Cuando se observa un conflicto de fusión, la ejecución del comando git status muestra qué archivos se deben resolver. Por ejemplo, si se modificaron ambas ramas en la misma sección de hello.py, se vería algo parecido a esto:

On branch master
Unmerged paths:
(use "git add/rm ..." as appropriate to mark resolution)
both modified: hello.py

Cómo se presentan los conflictos

Cuando Git se encuentra un conflicto durante una fusión, editará el contenido de los archivos afectados con indicadores visuales que marquen ambos extremos del contenido conflictivo. Estos marcadores visuales son: <<<<<<<, ======= y >>>>>>>. Es útil buscar un proyecto para estos indicadores durante una fusión con el fin de encontrar dónde hay que resolver los conflictos.

here is some content not affected by the conflict
<<<<<<< master
this is conflicted text from master
=======
this is conflicted text from feature branch
>>>>>>> feature branch;

Normalmente, el contenido que se encuentra delante del marcador ======= es la rama de recepción y el de la parte de detrás es la rama de fusión.

Una vez identificadas las secciones conflictivas, puedes entrar y arreglar la fusión a tu gusto. Cuando estés listo para terminar la fusión, todo lo que tienes que hacer es ejecutar git add en los archivos conflictivos para indicar a Git que se han resuelto. Seguidamente, ejecutas un git commit normal para generar la confirmación de fusión. El proceso es exactamente el mismo que el de la confirmación de una captura normal, lo que significa que es fácil para los desarrolladores habituales gestionar sus propias fusiones.

Ten en cuenta que los conflictos de fusión solo se producirán en el caso de una fusión de 3 vías. Los cambios conflictivos en una fusión de avance rápido no son posibles. 

Resumen

Este documento es un resumen del comando git merge. La fusión es un proceso esencial cuando se trabaja con Git. Hemos hablado de los mecanismos internos que hay detrás de una fusión y de las diferencias entre una fusión con avance rápido y una de 3 vías auténtica. Algunas de las principales conclusiones son:
 

  1. La fusión de Git combina secuencias de confirmaciones en un historial unificado de confirmaciones.
  2. Hay dos formas principales en las que Git puede fusionar: fusión con avance rápido y fusión de 3 vías.
  3. Git puede fusionar confirmaciones automáticamente a menos que haya cambios que generen conflictos en ambas secuencias de confirmaciones.

Este documento ha integrado y hecho referencia a otros comandos de Git como: git branch, git pull y git fetch. Para obtener más información sobre ellos, visita sus respectivas páginas. 

¿Listo para probar las ramas?

Prueba este tutorial interactivo.

Comienza ahora