Introduzione
La merge base di due commit è il loro miglior antenato comune: la fondazione che Git usa per i merge a tre vie. Scegliere la base giusta è ciò che fa funzionare davvero i merge "automatici".
Trovarla
git merge-base A B
git merge-base --all A B # tutti i migliori antenati comuni
git merge-base --octopus A B C
git merge-base --is-ancestor X Y # exit 0 se X è antenato di Y
git merge-base --fork-point main feature
Definizione
Un antenato comune C di A e B è un "miglior" antenato comune se nessun altro antenato comune di A e B è discendente di C. La maggior parte delle coppie ha un singolo miglior antenato comune. Quando il grafo contiene merge incrociati, possono esistere diversi; questo è ciò che --all riporta.
Come il merge a tre vie la usa
Dati i commit A e B con merge base M, Git per ogni file:
- Legge il file in M, A e B.
- Se solo un lato è cambiato, prendi quel lato.
- Se entrambi i lati sono cambiati identicamente, prendi uno dei due.
- Se entrambi i lati sono cambiati diversamente, esegui un merge testuale a tre vie o emetti marker di conflitto.
Strategie recursive e ort
Quando esistono più merge base, la strategia recursive le mergia prima, producendo una base virtuale, e usa quella per il merge a tre vie finale. La strategia ort (default da 2.33) fa lo stesso con un'implementazione più veloce ed efficiente in memoria.
git merge -s ort feature
git merge -s recursive feature
git merge -s resolve feature # solo una merge base, nessuna ricorsione
Fork point
Per il rebase, Git spesso ha bisogno di sapere dove un branch tematico ha lasciato un branch di base. --fork-point consulta il reflog della base per trovare il punto più recente in cui il topic e la base hanno condiviso storia:
git rebase --fork-point main feature
git merge-base --fork-point main feature
Esempio funzionante
A---B---C main
\
D---E feature
git merge-base main feature # B
Un merge di main in feature esegue un merge a tre vie usando B come base.
Ispezionare perché un merge confligge
git merge-base HEAD feature
git diff <base> HEAD -- file
git diff <base> feature -- file
Questa coppia di diff è esattamente ciò che vede il merge di Git.
Errori comuni
Assumere che ci sia sempre esattamente una merge base; le storie incrociate ne producono diverse. Trattare --fork-point come sostituto di --onto; risolvono problemi diversi. Scegliere --strategy=ours quando intendevi --strategy-option=ours; il primo scarta interamente le loro modifiche. Infine, ricalcolare la merge base a mano dall'output di git log e sbagliare; usa git merge-base piuttosto che andare a occhio.