Full Stack

Unificare le branch in Git con git merge

Autore

Manuel Ricci

Siamo arrivati infine al comando git merge, più volte menzionato nelle lezioni precedenti. In questa lezione vedremo come si usa, quali sono le sue peculiarità e, nel caso di conflitti, come risolverli. Preparatevi, perché sarà una lezione bella tosta.

Cos’è git merge?

Dopo aver visto git branch e come funziona il sistema di ramificazione in Git in generale è giusto comprendere come si possa integrare quanto fatto su una branch isolata in una unica. git merge è il comando che serve a svolgere questo compito.

Prepariamoci per fare il primo merge

branch master con qualche commit

La situazione nella quale ci troviamo ora è più o meno quella descritta nell’immagine qui sopra, una repo con già qualche commit nella cronologia.

Supponiamo di voler implementare una nuova feature nel nostro sito web e quindi dovremo:

  1. Creare una nuova branch
  2. Creare un nuovo file o modificarne uno esistente e salvare le modifiche nella repo.

Fin qui nulla di nuovo. Tutto ciò che è stato fatto è stato già visto nelle lezioni precedenti.

branch con due puntatori di branch

Con la creazione della nuova branch, verrà creato un nuovo puntatore che punterà alla medesima commit della branch principale (qui HEAD è stato omesso, ma sappiamo che indica la branch sulla quale ci troviamo).

branch iss53 avanti rispetto a master

In seguito alla commit del punto due, la situazione è simile a questa. La branch che abbiamo creato per la nuova feature è andata avanti rispetto alla branch principale, ma nella nostra situazione ipotetica arriva una richiesta.

Ci viene richiesto di mettere a posto un bug in produzione urgentemente, quindi:

  1. Tornare sulla branch principale
  2. Creare una nuova branch
  3. Sistemare il problema e fare la commit
  4. Ritornare sulla branch principale
  5. Unificare la branch creata al punto 2 con la principale
  6. Eliminare la branch creata al punto 2

hotfix e iss53 sono più avanti di master

Arrivati al punto 4 delle precedenti istruzioni, la situazione è simile a quanto riportato nell’immagine qui sopra.

hotfix e master sono unificate

Dopo il merge (punto 5), invece, la situazione è più simile a questo. I puntatori delle due branch che sono state unificate puntano alla commit alla quale precedentemente puntava solo il puntatore della branch creata appositamente per risolvere il bug.

Cos’è il fast-forward in Git?

1Updating d24bd1a..6d0608e
2Fast-forward
3 readme.md | 2 +-
4 1 file changed, 1 insertion(+), 1 deletion(-)

Nell’output del comando git merge si può leggere Fast-forward, ma cos’è esattamente? Significa che Git, non essendoci divergenze, procede con lo spostamento del puntatore della branch alla quale vogliamo integrare le modifiche avanti nella cronologia, unificando il tutto. Questo è il fast-forward che intende.

Possiamo infine eliminare la branch che abbiamo creato appositamente per risolvere il bug, dato che a questo punto è superflua (punto 6) e procedere oltre.

Procediamo con il secondo merge

Dobbiamo completare la nostra feature lasciata in sospeso, quindi procediamo:

  1. Torniamo nella branch della nuova feature
  2. Facciamo una nuova commit sul file creato o modificato in precedenza
  3. Torniamo sulla branch principale
  4. Unifichiamo la branch principale con quella con la nuova feature

la branch iss53 è avanti di due commit

La situazione è questa. Ora… Quando sarà il momento di unificare, Git non farà il fast-forward, questo perché la storia è diverta e l’antenato diretto non è comune alle due commit Git performerà un merge a tre vie. In pratica userà i due snapshot alla quale puntano le due branch e l’antenato comune, quello che si trova immediatamente prima alla divergenza.

commit che verranno usate per il merge a tre vie

Al posto di spostare il puntatore in avanti come visto con il fast-forward, Git creerà un nuovo snapshot, risultato dell’unione di tutti e tre gli elementi menzionati in precedenza e una nuova commit che punta ad esso. Questa nuova commit viene chiamata merge commit perché ha come commit precedente più commit.

1tree 2b8399065e99a636ca57097f57adb1f324a37a81
2parent e5c3ffe5816a26a84eb97babf0bb94c4fd051d30
3parent 236cf04f3fc314facd1ae4e315a1b671f499fcbc
4author Manuel Ricci <manuel@webtea.it> 1689876833 +0200
5committer Manuel Ricci <manuel@webtea.it> 1689876833 +0200
6
7Merge branch 'awesome_feature'

Inoltre, sempre parlando di merge a tre vie, vediamo che subito dopo il merge, Git ci dice:

1Merge made by the 'ort' strategy.
2 feature.txt | 3 +++
3 1 files changed, 3 insertions(+)
4 create mode 100644 feature.txt

Quel merge made by the ‘ort’ strategy, cosa significa? Fa riferimento ad una delle sei strategie di merging presenti in Git. Nello specifico le strategie sono:

  • recursive
  • ort
  • resolve
  • octopus
  • ours
  • subtree

Ort è un acronimo che sta per Ostensibly Recursive’s Twin ed è il sostituto dell’algoritmo recursive, nonché strategia di default quando si unifica una branch.

Per saperne di più consiglio di dare un’occhiata alle strategie di merging nella documentazione ufficiale

situazione finale post merge a tre vie

A questo punto ci troveremo come nell’immagine qui sopra e possiamo quindi procedere con la rimozione della branch della nuova feature.

Come risolvere un conflitto in Git

Prima di procedere oltre dobbiamo fare una piccola modifica al nostro file di configurazione di git. Essendoci diverse variabili da impostare a sto giro è meglio aprire il file direttamente nell’editor con il comando

1$ git config --global -e

In questo modo verrà aperto l’editor di default di Git e potremo procedere con l’inserimento di alcune nuove variabili. Nello specifico queste:

1[core]
2      editor = code --wait
3  [merge]
4      tool = vscode
5  [mergetool "vscode"]
6       cmd = code --wait --merge $REMOTE $LOCAL $BASE $MERGED
7  [diff]
8      tool = vscode
9  [difftool "vscode"]
10      cmd = code --wait --diff $LOCAL $REMOTE

Queste informazioni sono reperibili qui e qui

Salvato il file e chiuso l’editor, Visual Studio Code sarà il tool predefinito per la gestione dei conflitti durante il merging. Mettiamolo alla prova.

Creare un conflitto

Per poter risolvere un conflitto dobbiamo prima provocarlo, in questo modo:

  1. Creare una nuova branch
  2. Fare una commit
  3. Tornare sulla branch principale
  4. Fare una commit modificando lo stesso file modificato precedentemente

Al punto 4 la risposta di Git dovrebbe essere simile a questa:

1Auto-merging hello.txt
2CONFLICT (content): Merge conflict in hello.txt
3Automatic merge failed; fix conflicts and then commit the result.

Qualcosa è andato storto e Git non può farcela da solo, dobbiamo intervenire manualmente.

Anche il comando git status ci dirà che c’è un problema e ci inviterà a risolvere il problema

1$ git status
2On branch main
3You have unmerged paths.
4  (fix conflicts and run "git commit")
5  (use "git merge --abort" to abort the merge)
6
7Unmerged paths:
8  (use "git add <file>..." to mark resolution)
9        both modified:   hello.txt
10
11no changes added to commit (use "git add" and/or "git commit -a")

Risolvere il conflitto

A questo punto possiamo eseguire il comando git mergetool che aprirà Visual Studio Code per risolvere il conflitto. Decidiamo il da farsi:

  • accettare le modifiche di una o dell’altra branch scartando quelle dell’altra
  • integrare tutte e due
  • riscrivere tutto

L’importante è risolvere il conflitto.

Una volta risolto, possiamo aggiungere la modifica in staging e salvarla creando la merge commit. Voilà, conflitto risolto e salvato.

Conclusioni

Merge è un comando essenziale quando si lavora con Git e arrivati a questo punto non dovrebbe crearvi grossi problemi. Nella prossima lezione parliamo sempre di merging, ma vediamo un’altro comando chiamato rebase.

Caricamento...

Diventiamo amici di penna? ✒️

Iscriviti alla newsletter per ricevere una mail ogni paio di settimane con le ultime novità, gli ultimi approfondimenti e gli ultimi corsi gratuiti puubblicati. Ogni tanto potrei scrivere qualcosa di commerciale, ma solo se mi autorizzi, altrimenti non ti disturberò oltre.

Se non ti piace la newsletter ti ricordo la community su Discord, dove puoi chiedere aiuto, fare domande e condividere le tue esperienze (ma soprattutto scambiare due meme con me). Ti aspetto!

Ho in previsione di mandarti una newsletter ogni due settimane e una commerciale quando capita.