Cuando trabajamos con Git, las fusiones suelen ser sencillas si los cambios se hacen en archivos diferentes o en partes distintas del código. Sin embargo, la cosa se complica cuando modificamos el mismo archivo en distintas ramas. Git, por suerte, es bastante inteligente y realiza las fusiones línea a línea, lo que le permite integrar cambios en un mismo archivo siempre que no afecten a las mismas líneas.
Para ilustrar esto, imaginemos que tenemos una rama principal, master, y creamos una rama nueva llamada feature-comercial-text para añadir un texto comercial que nos ayude a incrementar las ventas. En esta rama escribimos un mensaje sobre la tradición de la empresa en la venta de jarrones chinos y la satisfacción de los clientes. Mientras tanto, el cliente nos pide cambiar el mensaje superior de la pantalla para que sea más enfático, así que creamos otra rama llamada fix-texto-superior desde master y modificamos esa parte del texto.
Cuando integramos primero la rama fix-texto-superior en master, Git lo resuelve fácilmente con un fast-forward porque master no había cambiado antes. Luego, al integrar feature-comercial-text, Git utiliza un merge recursivo, ya que ambos cambios afectan al mismo archivo pero en líneas diferentes, por lo que no hay conflicto.
Pero, ¿qué pasa si modificamos la misma línea en dos ramas diferentes? Para verlo, creamos una rama fix-octubre donde cambiamos la fecha de apertura a 15 de octubre y otra rama fix-gramatica donde corregimos la gramática de la frase que anuncia la inauguración del sitio web. Ambas modificaciones afectan a la misma línea del archivo index.html.
Al intentar fusionar estas dos ramas en master, Git detecta un conflicto porque no puede decidir automáticamente cuál de las dos versiones es la correcta. En este caso, Git marca el archivo en conflicto insertando delimitadores especiales que muestran ambas versiones del texto:
<<<<<<< HEAD
Estamos a punto de inaugurar el sitio web el 1 de octubre.
=======
Vamos a inaugurar el sitio web el 1 de octubre.
>>>>>>> fix-gramatica
Aquí, HEAD representa la versión actual en master y fix-gramatica la versión de la rama que intentamos fusionar. Nuestra tarea es elegir qué texto queremos conservar, o incluso combinar ambos, y eliminar estos símbolos para dejar el archivo limpio.
Por ejemplo, podemos decidir quedarnos con una frase que combine lo mejor de ambas versiones:
Vamos a inaugurar el sitio web el 1 de octubre.
Después de resolver el conflicto, añadimos el archivo con git add index.html y hacemos el commit para finalizar la fusión. Git reconoce que el conflicto ha sido resuelto y completa el merge.
Aunque los conflictos pueden parecer intimidantes al principio, en realidad son una oportunidad para revisar y decidir manualmente cómo debe quedar el código cuando dos cambios chocan. Es raro que ocurran en código muy serio, ya que normalmente se procura que dos personas no trabajen en la misma línea simultáneamente, pero cuando suceden, saber cómo resolverlos es fundamental para mantener un flujo de trabajo ordenado y efectivo.
En próximos ejemplos podemos explorar conflictos más complejos, pero por ahora, entender cómo Git maneja fusiones línea a línea y cómo resolver conflictos básicos nos prepara para trabajar con ramas limpias y sincronizadas sin miedo a perder cambios importantes.