Introducción
La merge base de dos commits es su mejor ancestro común: la base que Git usa para los merges three-way. Elegir la base correcta es lo que hace que los merges "automáticos" realmente funcionen.
Encontrándola
git merge-base A B
git merge-base --all A B # todos los mejores ancestros comunes
git merge-base --octopus A B C
git merge-base --is-ancestor X Y # exit 0 si X es ancestro de Y
git merge-base --fork-point main feature
Definición
Un ancestro común C de A y B es un "mejor" ancestro común si ningún otro ancestro común de A y B es descendiente de C. La mayoría de pares tienen un único mejor ancestro común. Cuando el grafo contiene merges entrecruzados, pueden existir varios; eso es lo que reporta --all.
Cómo lo usa el merge three-way
Dados commits A y B con merge base M, Git para cada archivo:
- Lee el archivo en M, A y B.
- Si solo un lado cambió, toma ese lado.
- Si ambos lados cambiaron de forma idéntica, toma cualquiera.
- Si ambos lados cambiaron de forma diferente, ejecuta un merge de texto three-way o emite marcadores de conflicto.
Estrategias recursive y ort
Cuando existen varias merge bases, la estrategia recursive las mergea primero, produciendo una base virtual, y la usa para el merge three-way final. La estrategia ort (predeterminada desde 2.33) hace lo mismo con una implementación más rápida y eficiente en memoria.
git merge -s ort feature
git merge -s recursive feature
git merge -s resolve feature # solo una merge base, sin recursión
Fork point
Para rebase, Git a menudo necesita saber dónde un branch topic se separó de un branch base. --fork-point consulta el reflog de la base para encontrar el punto más reciente en el que topic y base compartieron historial:
git rebase --fork-point main feature
git merge-base --fork-point main feature
Ejemplo trabajado
A---B---C main
\
D---E feature
git merge-base main feature # B
Un merge de main en feature hace three-way usando B como la base.
Inspeccionando por qué un merge tiene conflictos
git merge-base HEAD feature
git diff <base> HEAD -- file
git diff <base> feature -- file
Este par de diffs es exactamente lo que ve el merge de Git.
Errores comunes
Asumir que siempre hay exactamente una merge base; los historiales entrecruzados producen varias. Tratar --fork-point como sustituto de --onto; resuelven problemas diferentes. Elegir --strategy=ours cuando querías --strategy-option=ours; el primero descarta sus cambios completamente. Finalmente, recalcular la merge base a mano desde la salida de git log y equivocarte; usa git merge-base en lugar de adivinar a ojo.