Introduzione
Un merge combina due linee di sviluppo. Il caso più comune è riportare un feature branch in main. Questa pagina illustra un merge pulito, un fast-forward e un merge con conflitti.
Preparazione
git switch -c feature/greeting
echo "hello world" > greeting.txt
git add greeting.txt
git commit -m "Add greeting"
git switch main
git merge feature/greeting
Se main non si è mosso da quando il branch è stato creato, Git fa fast-forward: sposta semplicemente il puntatore di main alla punta di feature/greeting. Nessun merge commit viene creato.
Veri merge a tre vie
Se entrambi i branch hanno nuovi commit, Git crea un merge commit con due parent:
git switch main
echo "main change" >> notes.txt
git commit -am "Update notes on main"
git merge feature/greeting
# Merge made by the 'ort' strategy.
Il primo parent del merge commit è il HEAD precedente di main; il secondo è la punta del branch mergiato.
Forzare un merge commit
Per preservare visibilmente la storia anche quando il fast-forward è possibile:
git merge --no-ff feature/greeting -m "Merge feature/greeting"
Conflitti
Se entrambi i lati hanno modificato le stesse righe, Git si ferma e scrive marker di conflitto:
<<<<<<< HEAD
line from main
=======
line from feature
>>>>>>> feature/greeting
Risolvi modificando il file, poi:
git add notes.txt
git status
git commit # usa il messaggio di merge preparato
Annullare
Se cambi idea a metà merge:
git merge --abort
Questo ripristina la working tree allo stato pre-merge.
Ispezionare il risultato
git log --oneline --graph --decorate -n 10
Il grafico mostra la forma a diamante creata dal merge.
Ispezionare un merge
I merge commit hanno due parent, quindi i diff necessitano di gestione esplicita. git show su un merge mostra di default un "combined diff" che evidenzia solo le modifiche che confliggono con entrambi i parent:
git show HEAD # combined diff
git show -m HEAD # diff contro ogni parent separatamente
git show --first-parent HEAD # solo contro il primo parent
git log --merges --oneline # solo merge commit
git log --no-merges --oneline # escludendo i merge commit
Per archeologia del codice, --first-parent su un branch di lunga vita rivela la storia di integrazione: quando ogni feature è atterrata, in ordine cronologico del trunk.
Errori comuni
Modificare i file durante un merge ma dimenticare di fare git add, così git commit si lamenta ancora di path non risolti. Esegui sempre git status dopo aver modificato. Risolvere cancellando i marker di conflitto ma lasciando testo stantio da un lato; build e test prima di committare il merge. Usare --no-ff su ogni merge in un repo a movimento veloce, inquinando la storia con merge commit vuoti. Infine, farsi prendere dal panico al prompt ed eseguire git reset --hard a metà merge; git merge --abort è più sicuro perché conosce ORIG_HEAD.