W3docs

git merge

Informazioni sul comando git merge, come funziona e la differenza tra unione fast-forward e unione a 3 vie.

Il comando git merge unisce due o più linee di sviluppo. Quando finisci una funzionalità sul suo branch dedicato, git merge prende il lavoro da quel branch e lo incorpora nel branch su cui ti trovi attualmente, producendo un'unica cronologia combinata.

Questa pagina illustra cosa accade durante un'unione, la differenza tra un'unione fast-forward e un'unione a 3 vie, come forzare un commit di merge e come riconoscere e risolvere un conflitto di merge.

Funziona in stretto coordinamento con git branch (per creare ed eliminare branch), git checkout (per passare al branch ricevente) e git pull (per aggiornare prima di unire). Se preferisci una cronologia lineare senza commit di merge, consulta git rebase come alternativa.

Come funziona

L'uso principale di git merge è combinare due branch. Viene anche utilizzato per integrare più commit da un branch in un altro. Nell'illustrazione seguente, git merge prende le punte di due branch e trova un commit antenato comune tra di esse. Il commit base comune viene usato per creare un nuovo commit di merge che combina le modifiche di entrambi i branch. Qui abbiamo due branch: master e stage. Dobbiamo unire il branch stage nel branch master.

gitmerge

I commit di merge sono unici perché hanno due commit padre. Git combina automaticamente cronologie separate quando crea un nuovo commit di merge. Tuttavia, se entrambi i branch modificano le stesse righe, Git non riesce a combinarle automaticamente, causando un conflitto di merge.

gitmerge1

Processo di unione

Prima di avviare il processo di unione, segui questi passaggi:

  • Assicurati di essere sul branch corretto che riceverà l'unione. Esegui git checkout <branch ricevente> per passarci.
  • Aggiorna il branch di destinazione con le ultime modifiche remote. Esegui git pull per recuperare e integrare gli ultimi commit remoti.
  • Il passaggio finale è eseguire git merge <nome branch>, che specifica il branch da unire nel branch ricevente.

Unione fast-forward

Un'unione fast-forward avviene quando il percorso dal branch corrente al branch di destinazione è lineare. L'unione fast-forward combina le cronologie, poiché tutti i commit raggiungibili dal branch di destinazione sono disponibili attraverso il branch corrente. Ecco un esempio di unione fast-forward:

gitmerge2

Quando le due cronologie divergono, Git utilizza l'unione a 3 vie come alternativa. L'unione a 3 vie usa un commit dedicato per combinare due cronologie.

gitmerge3

Le unioni fast-forward sono tipicamente usate per funzionalità piccole o correzioni di bug, mentre le unioni a 3 vie sono usate per integrare funzionalità a lungo termine. I seguenti esempi utilizzano un'unione fast-forward:

git merge

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

Eseguiamo git branch -d per eliminare il branch stage, poiché stage è ora accessibile dal branch master.

Il comando git merge con l'opzione --no-ff viene eseguito se hai bisogno di un commit di merge durante un'unione fast-forward per unire il branch specificato nel branch corrente, generando sempre un commit di merge (anche nel caso di un'unione fast-forward):

git merge --no-ff

git merge --no-ff <branch>

Unione a 3 vie

Questo scenario richiede un'unione a 3 vie quando il branch master avanza mentre il branch stage è ancora in sviluppo. Viene utilizzato quando i membri del team lavorano simultaneamente su una funzionalità di grandi dimensioni:

the git merge command

# Start the stage
git checkout -b stage master
# Edit some files
git add <file>
git commit -m "Start with the stage"
# Edit some files
git add <file>
git commit -m "Finish with the stage"
# 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 stage branch
git merge stage
git branch -d stage

Nell'esempio precedente, stage sarebbe una funzionalità più grande che richiede molto tempo per essere sviluppata, motivo per cui utilizziamo un'unione a 3 vie. Se la tua funzionalità è piccola, è preferibile usare un'unione fast-forward per evitare commit non necessari che ingombrano la cronologia del progetto.

Opzioni utili per il merge

Questi flag modificano il comportamento di git merge:

OpzioneCosa fa
--no-ffCrea sempre un commit di merge, anche quando è possibile un fast-forward. Mantiene il branch della funzionalità visibile nella cronologia.
--ff-onlyEsegue l'unione solo se è possibile un fast-forward; altrimenti interrompe. Utile negli script per rifiutare un commit di merge.
--squashCombina tutti i commit del branch in un unico insieme di modifiche in staging (da committare manualmente). Nessun commit di merge e nessun secondo genitore.
--abortInterrompe un merge in conflitto e ripristina il branch allo stato precedente all'unione.
-m "<msg>"Imposta il messaggio del commit di merge direttamente invece di aprire un editor.

Un merge con squash è utile quando un branch di funzionalità ha molti piccoli commit "work in progress" che non si vogliono nella cronologia principale:

git merge --squash

git checkout master
git merge --squash stage
git commit -m "Add stage feature"

Risoluzione dei conflitti

Quando si uniscono due branch, se la stessa parte dello stesso file viene modificata, si verificano conflitti di merge perché Git non riesce a determinare quale versione utilizzare. Quando ciò accade, Git si ferma prima di creare il commit di merge per consentirti di risolvere il conflitto. Il processo di merge di Git utilizza un flusso di lavoro modifica/stage/commit per risolvere i conflitti di merge. Quando si verifica un conflitto, l'esecuzione di git status mostrerà i file che devono essere risolti. L'immagine seguente apparirà quando le stesse parti del file example.txt sono state modificate:

git status

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

Se decidi di non procedere con l'unione, puoi annullarla in qualsiasi momento eseguendo git merge --abort.

Come vengono presentati i conflitti

In caso di conflitti, Git modifica il contenuto dei file interessati con marcatori visivi su entrambi i lati del contenuto in conflitto. I conflitti possono verificarsi solo durante un'unione a 3 vie — un'unione fast-forward non genera mai conflitti, perché il branch ricevente non aveva nuovi commit propri con cui scontrarsi.

I marcatori principali sono <<<<<<<, ======= e >>>>>>>. Aiutano a individuare le sezioni in conflitto nei file.

git conflicts

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

Per risolvere il conflitto, apri il file, elimina le tre righe dei marcatori (<<<<<<<, =======, >>>>>>>), e modifica il testo rimanente nella versione che vuoi mantenere. Quindi esegui git add <file> sul file in conflitto per marcarlo come risolto, e poi esegui git commit per creare il commit di merge.

Un esempio completo

La sessione seguente crea due branch che modificano la stessa riga, li unisce, incontra un conflitto, lo risolve e completa l'unione. Puoi incollare questi comandi in qualsiasi directory vuota per riprodurlo esattamente.

reproduce a conflict and resolve it

git init demo && cd demo
echo "line one" > file.txt
git add file.txt
git commit -m "Initial commit"

# Create a branch and change the line there
git checkout -b stage
echo "change from stage" > file.txt
git commit -am "Edit on stage"

# Change the same line on master
git checkout master
echo "change from master" > file.txt
git commit -am "Edit on master"

# Merge stage into master -> conflict
git merge stage
# Auto-merging file.txt
# CONFLICT (content): Merge conflict in file.txt
# Automatic merge failed; fix conflicts and then commit the result.

Dopo aver modificato file.txt per mantenere la versione desiderata, completa il merge:

git add file.txt
git commit -m "Merge stage, keep resolved line"
git branch -d stage

Verifica di un merge

Dopo l'unione, conferma il risultato con git log. I flag --graph e --oneline disegnano la topologia del branch in modo che un commit di merge (con due genitori) sia facile da individuare:

git log --oneline --graph

Se decidi che un merge completato è stato un errore, git reset può riportare il branch al commit precedente al merge.

Pratica

Pratica
Quali sono le caratteristiche principali e i processi coinvolti nel comando 'git merge'?
Quali sono le caratteristiche principali e i processi coinvolti nel comando 'git merge'?
Was this page helpful?