Close

Git merge

L'operazione di merge è il modo di Git di rimettere insieme una cronologia con fork. Il comando git merge permette di prendere le linee di sviluppo indipendenti create da git branch e integrarle in un unico branch.

Nota che tutti i comandi presentati di seguito sono sottoposti a merge nel branch corrente. Il branch corrente verrà aggiornato per riflettere il merge, ma quello di destinazione resterà completamente inalterato. Ancora una volta, questo significa che git merge viene spesso usato insieme a git checkout per selezionare il branch corrente e che git branch -d viene utilizzato per eliminare il branch di destinazione obsoleto.


Come funziona


git merge unirà più sequenze di commit in un'unica cronologia unificata. Nei casi d'uso più frequenti, git merge viene utilizzato per unire due branch. I seguenti esempi in questo documento si concentrano su questo schema di merge dei branch. In questi scenari, git merge prende due puntatori di commit, di solito le punte del branch, e cerca un commit di base comune tra di loro. Una volta trovato un commit di base comune, Git crea un nuovo "commit di merge" che unisce le modifiche di ogni sequenza di commit di merge in coda.

Supponiamo di avere un nuovo branch di funzioni basato sul branch main. Vogliamo eseguire il merge di questo branch di funzioni in main.

Eseguire il merge del branch di funzione in quello principale
Finestra della console
materiale correlato

Registro Git avanzato

Logo di Bitbucket
Scopri la soluzione

Impara a utilizzare Git con Bitbucket Cloud

Richiamando questo comando, verrà eseguito il merge del branch di funzioni specificato nel branch corrente, supponiamo il branch main. Git determinerà automaticamente l'algoritmo di merge (illustrato di seguito).

Nuovo nodo di commit di merge

I commit di merge sono unici rispetto ad altri commit per il fatto che hanno due commit principali. Quando si crea un commit di merge, Git tenterà di eseguire automaticamente il merge delle cronologie separate. Se rileva un dato modificato in entrambe le cronologie, Git non sarà in grado di unirle automaticamente. Questo scenario rappresenta un conflitto del controllo della versione e Git necessiterà dell'intervento dell'utente per continuare.

Preparazione al merge


Prima di eseguire un merge, ci sono un paio di passaggi di preparazione da effettuare per garantire che il merge proceda senza intoppi.

Verificare il branch di destinazione


Esegui git status per assicurarti che HEAD punti al branch di destinazione del merge corretto. Se necessario, esegui git checkout per passare al branch di destinazione. Nel nostro caso, eseguiremo git checkout main.

Recuperare i commit remoti più recenti


Assicurati che il branch di destinazione e quello che verrà sottoposto a merge siano aggiornati con le ultime modifiche remote. Esegui git fetch per eseguire un pull dei commit remoti più recenti. Una volta completato il recupero, assicurati che sul branch main siano presenti gli ultimi aggiornamenti eseguendo il comando git pull.

Esecuzione del merge


Una volta che sono stati effettuati i passaggi di "preparazione al merge" descritti in precedenza, è possibile avviare un merge eseguendo git merge , dove è il nome del branch che verrà sottoposto a merge con il branch di destinazione.

Merge con avanzamento rapido


Un merge con avanzamento rapido può verificarsi quando c'è un percorso lineare dalla punta del branch corrente al branch di destinazione. Invece di eseguire "effettivamente" il merge dei branch, tutto ciò che Git deve fare per integrare le cronologie è spostare (ovvero "effettuare un avanzamento rapido") la punta del branch corrente fino alla punta del branch di destinazione. Questa operazione unisce di fatto le cronologie, poiché tutti i commit raggiungibili dal branch di destinazione sono ora disponibili attraverso quello corrente. Ad esempio, un merge con avanzamento rapido di una funzione qualsiasi nel branch main avrebbe un aspetto simile al seguente:

I nodi del nodo della funzione che si trovano davanti al nodo principale si trovano sullo stesso nodo dopo l'avanzamento rapido

Tuttavia, non è possibile eseguire un merge con avanzamento rapido se i branch sono divergenti. Quando non c'è un percorso lineare verso il branch di destinazione, Git non ha altra scelta che unire le cronologie tramite un merge a 3 vie. I merge a 3 vie utilizzano un commit dedicato per legare le due cronologie. Questa nomenclatura deriva dal fatto che Git usa tre commit per generare il commit di merge: le punte dei due branch e il loro predecessore comune.

Diagramma dopo un merge a 3 vie

Sebbene sia possibile utilizzare una qualsiasi di queste strategie di merge, molti sviluppatori preferiscono i merge con avanzamento rapido (facilitati dalla riassegnazione) per piccole funzioni o correzioni di bug, riservando invece i merge a 3 vie all'integrazione di funzioni di più lunga esecuzione. In quest'ultimo caso, il commit di merge risultante funge da collegamento simbolico tra i due branch.

Il nostro primo esempio illustra un merge con avanzamento rapido. Il codice seguente crea un nuovo branch, vi aggiunge due commit, quindi lo integra nella riga principale tramite un merge con avanzamento rapido.

# Start a new feature
git checkout -b new-feature main
# Edit some files
git add <file>
git commit -m "Start a feature"
# Edit some files
git add <file>
git commit -m "Finish a feature"
# Merge in the new-feature branch
git checkout main
git merge new-feature
git branch -d new-feature

Questo è un flusso di lavoro comune per i branch di argomenti di breve durata che vengono utilizzati più come sviluppo isolato che come strumento organizzativo per le funzioni di più lunga esecuzione.

Tieni inoltre presente che Git non restituirà errori con il comando git branch -d, dal momento che la nuova funzione è ora accessibile dal branch principale.

Nel caso in cui sia necessario un commit di merge durante un merge con avanzamento rapido per scopi di mantenimento dei record, puoi eseguire git merge con l'opzione --no-ff.

git merge --no-ff <branch>

Questo comando esegue il merge del branch specificato nel branch corrente, ma genera sempre un commit di merge (anche nel caso dei merge con avanzamento rapido). Ciò è utile per documentare tutti i merge che si verificano nel repository.

Merge a 3 vie


Il prossimo esempio è molto simile, ma richiede un merge a 3 vie perché il branch main progredisce mentre la funzione è in corso. Si tratta di uno scenario comune per le funzioni di grandi dimensioni o quando più sviluppatori lavorano contemporaneamente a un progetto.

Start a new feature
git checkout -b new-feature main
# Edit some files
git add <file>
git commit -m "Start a feature"
# Edit some files
git add <file>
git commit -m "Finish a feature"
# Develop the main branch
git checkout main
# Edit some files
git add <file>
git commit -m "Make some super-stable changes to main"
# Merge in the new-feature branch
git merge new-feature
git branch -d new-feature

Nota che è impossibile per Git eseguire un merge con avanzamento rapido, poiché non c'è modo di spostare main su new-feature senza il backtracking.

Nella maggior parte dei flussi di lavoro, new-feature è una funzione molto più ampia che ha impiegato molto tempo in fase di sviluppo, motivo per cui nel frattempo sono comparsi nuovi commit su main. Se il branch di funzioni fosse effettivamente piccolo come quello nell'esempio precedente, probabilmente sarebbe meglio riassegnarlo su main ed eseguire il merge con avanzamento rapido. In questo modo, i commit di merge superflui non ingombrerebbero la cronologia del progetto.

Risoluzione dei conflitti


Se i due branch di cui stai cercando di eseguire il merge hanno modificato entrambi la stessa parte dello stesso file, Git non sarà in grado di capire quale versione usare. Quando si verifica una situazione del genere, Git si arresta subito prima del commit di merge, in modo che tu possa risolvere i conflitti manualmente.

L'aspetto fantastico del processo di merge di Git è che utilizza il noto flusso di lavoro di modifica/preparazione per il commit/commit per risolvere i conflitti di merge. Quando si verifica un conflitto di merge, esegui il comando git status per visualizzare i file che devono essere risolti. Ad esempio, se entrambi i branch hanno modificato la stessa sezione di hello.py, vedrai un output simile al seguente:

On branch main
Unmerged paths:
(use "git add/rm ..." as appropriate to mark resolution)
both modified: hello.py

Come vengono presentati i conflitti


Quando Git rileva un conflitto durante un merge, modificherà il contenuto dei file interessati con indicatori visivi che contrassegnano entrambi i lati del contenuto in conflitto. Questi indicatori visivi sono: <<<<<<<, ======= e >>>>>>>. È utile cercare questi indicatori nel progetto durante un merge per individuare le posizioni in cui devono essere risolti i conflitti.

here is some content not affected by the conflict
<<<<<<< main
this is conflicted text from main
=======
this is conflicted text from feature branch
>>>>>>> feature branch;

Generalmente il contenuto prima dell'indicatore ======= è il branch di destinazione, mentre la parte successiva è il branch di merge.

Dopo aver identificato le sezioni in conflitto, puoi correggere il merge a tuo piacimento. Quando sei pronto per terminare il merge, tutto ciò che devi fare è eseguire git add sui file in conflitto per dire a Git che è stato risolto. Quindi, esegui un normale git commit per generare il commit di merge. È esattamente la stessa procedura di quando si esegue il commit di una snapshot normale, il che significa che è facile per gli sviluppatori gestire i propri merge.

Nota che i conflitti di merge si verificano solo in caso di merge a 3 vie. Non è possibile avere modifiche in conflitto nei merge con avanzamento rapido.

Riepilogo


In questo documento viene fornita una panoramica del comando git merge. Il merge è un processo essenziale quando si lavora con Git. Abbiamo parlato della meccanica interna alla base di un merge e delle differenze tra i merge con avanzamento rapido e i merge autentici a tre vie. Alcuni dei concetti principali più importanti sono:

1. Il merge di Git unisce sequenze di commit in una cronologia unificata di commit.

2. Ci sono due modalità principali in cui Git esegue i merge: con avanzamento rapido e a tre vie.

3. Git può eseguire automaticamente il merge dei commit a meno che non ci siano modifiche in conflitto in entrambe le sequenze di commit.

Questo documento integra e fa riferimento ad altri comandi Git come: git branch, git pull e git fetch. Visita le pagine individuali corrispondenti per ulteriori informazioni.


Condividi l'articolo
Argomento successivo

Letture consigliate

Aggiungi ai preferiti queste risorse per ricevere informazioni sui tipi di team DevOps e aggiornamenti continui su DevOps in Atlassian.

Le persone collaborano utilizzando una parete piena di strumenti

Blog di Bitbucket

Illustrazione su Devops

Percorso di apprendimento DevOps

Funzione Demo Den per demo con esperti Atlassian

Come Bitbucket Cloud funziona con Atlassian Open DevOps

Iscriviti alla nostra newsletter DevOps

Thank you for signing up