CONTATTACI

Guide per aspiranti programmatori

sviluppatore php seduto alla scrivania a lavorare al pc
Lezione 42 / 52

Risolvere un merge conflict in Git

Abbiamo accennato, in precedenza, alla possibilità che durante l’esecuzione di un git pull, git merge o git rebase in Git si possano verificare dei conflitti che impediscono a Git di portare a termine automaticamente l’operazione.

Un conflitto nell’accezione dei version control system è una situazione per la quale il sistema sta provando a integrare due diverse history che hanno entrambe apportato modifiche alle stesse righe di un file.

Il processo di merge può andare in uno stato di conflitto in due diversi momenti:

  • all’avvio del merge – avviene quando ci sono modifiche nella working copy o nella staging area; tali modifiche “pending” non possono essere gestite da Git e sarà compito dello sviluppatore “pulire” il proprio spazio di lavoro con git stash, git checkout, git commit o git reset
  • durante il merge – in tal caso il conflitto è effettivamente tra il branch in uso e quello che si sta mergiando, conflitto che riguarda modifiche apportate nei commit dei due branch.

NOTA: come visto nella precedente sezione, nel merge portiamo le modifiche presenti in un branch dentro al branch attualmente presente nella working copy. Nel seguito di questa sezione indicheremo tali branch rispettivamente come “incoming” e “current”.

Proviamo a fare qualche “esercizio” di merge conflict in Git. Proviamo a realizzare il caso in cui vogliamo riportare sul branch main delle modifiche fatte da noi su un branch, nella situazione in cui un altro sviluppatore web ha aggiunto un commit sul branch main successivamente alla creazione del nostro branch di sviluppo.

Merge conflict

Merge conflict

Creiamo un repository a cui aggiungiamo un file con un commit (con l’opzione –author per simulare meglio chi ha committato cosa).

$ mkdir git-merge-test
$ cd git-merge-test
$ git init .
$ echo "initial content to edit later" > merge.txt
$ git add merge.txt
$ git commit -m "initial content" --author="Someone <someone@example.com>"
[main (root-commit) 0a99708] initial content
Author: Someone <someone@example.com>
1 file changed, 1 insertion(+)
create mode 100644 merge.txt

Creiamo un nuovo branch, apportiamo modifiche al file e salviamo tali modifiche in un commit.

$ git checkout -b merge-me
Switched to a new branch 'merge-me'

$ echo "new content to merge later" > merge.txt
$ git commit -am "edited the content for conflict" --author "Me <me@example.com>"
[merge-me 15416df] edited the content for conflict
Author: Me <me@example.com>
1 file changed, 1 insertion(+), 1 deletion(-)

Torniamo sul branch main e aggiungiamo una nuova riga di testo al file, sempre poi salvando in un commit.

$ git checkout main
Switched to branch 'main'

$ echo "content added to previous" >> merge.txt
$ git commit -am "appended content to merge.txt" --author="Frank <frank@example.com>"
[main 90640eb] appended content to merge.txt
Author: Frank <frank@example.com>
1 file changed, 1 insertion(+)

Proviamo, quindi, a fare merge delle modifiche nel branch merge-me (incoming) nel branch main (current)

$ git merge merge-me
Auto-merging merge.txt
CONFLICT (content): Merge conflict in merge.txt
Automatic merge failed; fix conflicts and then commit the result.

$ git status
On branch main
You have unmerged paths.
 (fix conflicts and run "git commit")
 (use "git merge --abort" to abort the merge)

Unmerged paths:
 (use "git add <file>..." to mark resolution)
    both modified:  merge.txt

no changes added to commit (use "git add" and/or "git commit -a")

Provando ad eseguire git merge viene segnalata la presenza di un conflitto. Il processo di merge si interrompe, lasciando la propria copia in uno stato di attesa di risoluzione.

Risolvere un merge conflict in Git

Con il comando git status possiamo evidenziare la presenza di un conflitto durante l’esecuzione di un merge. Vediamo come scoprire maggiori dettagli su cosa esattamente è cambiato tra le due versioni della history e come intervenire.

Nell’esempio di conflitto “forzato” sappiamo che il problema è nel file merge.txt, che ha ricevuto modifiche nelle stesse righe in entrambi i branch.

Nel momento in cui il merge si è interrotto, nel file in conflitto ci sono le modifiche provenienti da entrambe le versioni del file:

$ cat merge.txt
<<<<<<< HEAD
initial content to edit later
content added to previous
=======
new content to merge later
>>>>>>> merge-me

Di particolare interesse sono i marker di conflitto inseriti da Git che ci permettono di sapere che:

  • la righe tra <<<<<<< e ======= contengono le righe in conflitto nel file come erano nel commit del branch “current”
  • le righe tra ======= e >>>>>>> contengono le righe in conflitto nel file come erano nel commit del branch “incoming”.

Ci sono tre modi per risolvere i conflitti in un file e procedere con il merge, che ovviamente possono e debbono essere scelti caso per caso:

  • accettare in toto le modifiche che erano già nel branch “current” (nel nostro caso main) con git checkout –ours merge.txt
  • accettare in toto le modifiche che vengono dal branch “incoming” (nel nostro caso new_branch_to_merge_later) con git checkout –their merge.txt
  • modificare il file in modo che contenga un contenuto corretto e in linea con entrambe le modifiche, dichiarare che è stato risolto il conflitto con git add merge.txt e proseguire con il merge tramite un commit.

Se volessimo procedere con questa ultima opzione, dovremmo modificare il file fino a raggiungere un contenuto adeguato e poi:

$ cat merge.txt
new content to merge later
content added to previous

$ git status
On branch main
You have unmerged paths.
 (fix conflicts and run "git commit")
 (use "git merge --abort" to abort the merge)

Unmerged paths:
 (use "git add <file>..." to mark resolution)
    both modified:  merge.txt

no changes added to commit (use "git add" and/or "git commit -a")

$ git add merge.txt

$ git status
On branch main
All conflicts fixed but you are still merging.
 (use "git commit" to conclude merge)

Changes to be committed:
modified:  merge.txt

Una volta effettuato il commit, la history del nostro repository sarà la seguente:

$ git log --pretty=format:'%h %s (%an)' --date=short --graph
*  c9802c8 merged content due conflict (Me)
|\
| * 15416df edited the content for conflict (Me)
* | 90640eb appended content to merge.txt (Frank)
|/
* 0a99708 initial content (Someone)

Notare che in questo caso, il nostro commit iniziale sul branch è rimasto intatto (ce lo dice il fatto che abbia ancora lo stesso hash, 15416df) e le modifiche necessarie a risolvere il conflitto sono state incluse nel commit di merge.

Possiamo, infatti, confrontare la differenza tra gli ultimi due commit sul branch in uso con

$ git diff HEAD^1
diff --git a/merge.txt b/merge.txt
index c560b6f..732761b 100644
--- a/merge.txt
+++ b/merge.txt
@@ -1,2 +1,2 @@
-initial content to edit later
+new content to merge later
content added to previous

Contattaci senza impegno per informazioni sul corso

Pagamento rateale

Valore della rata: A PARTIRE DA 115 €/mese.

Esempio di finanziamento 

Importo finanziato: € 2440 in 24 rate da € 115 – TAN fisso 9,55% TAEG 12,57% – importo totale del credito € 2841.

Il costo totale del credito comprende: interessi calcolati al TAN indicato, oneri fiscali (imposta di bollo sul contratto 16,00 euro*) addebitati sulla prima rata, costo mensile di gestione pratica € 3,90, spesa di istruttoria € 0,00, spesa per invio rendicontazione periodica cartacea € 0,98 (o spesa per invio rendicontazione periodica cartacea € 0,00), imposta di bollo su rendicontazione periodica € 0,00. Modalità di rimborso obbligatoria: addebito diretto su c/c. La scadenza delle rate è determinata dal giorno della liquidazione del contratto; la data di scadenza delle rate è prevista il giorno 15 del mese. L’importo di ciascuna rata comprende una quota di capitale crescente e interessi decrescente secondo un piano di ammortamento “alla francese”. Offerta valida dal 01/01/2024 al 31/12/2024.

Messaggio pubblicitario con finalità promozionale. Per le informazioni precontrattuali richiedere sul punto vendita il documento “Informazioni europee di base sul credito ai consumatori” (SECCI) e copia del testo contrattuale. Salvo approvazione di Sella Personal Credit S.p.A. Aulab S.r.l. opera quale intermediario del credito NON in esclusiva.

*In fase di richiesta del finanziamento verrà proposta la facoltà di selezionare, in alternativa all’imposta di bollo sul contratto di 16,00 euro, l’imposta sostitutiva, pari allo 0,25% dell’importo finanziato.

Pagamento rateale

Valore della rata: A PARTIRE DA 210 €/mese.

Esempio di finanziamento  

Importo finanziato: € 4500 in 24 rate da € 210,03 – TAN fisso 9,68% TAEG 11,97% – importo totale del credito € 5146,55.

Il costo totale del credito comprende: interessi calcolati al TAN indicato, oneri fiscali (imposta di bollo sul contratto 16,00 euro*) addebitati sulla prima rata, costo mensile di gestione pratica € 3,90, spesa di istruttoria € 0,00, spesa per invio rendicontazione periodica cartacea € 0,98 (o spesa per invio rendicontazione periodica cartacea € 0,00), imposta di bollo su rendicontazione periodica € 0,00. Modalità di rimborso obbligatoria: addebito diretto su c/c. La scadenza delle rate è determinata dal giorno della liquidazione del contratto; la data di scadenza delle rate è prevista il giorno 15 del mese. L’importo di ciascuna rata comprende una quota di capitale crescente e interessi decrescente secondo un piano di ammortamento “alla francese”. Offerta valida dal 01/01/2024 al 31/12/2024.

Messaggio pubblicitario con finalità promozionale. Per le informazioni precontrattuali richiedere sul punto vendita il documento “Informazioni europee di base sul credito ai consumatori” (SECCI) e copia del testo contrattuale. Salvo approvazione di Sella Personal Credit S.p.A. Aulab S.r.l. opera quale intermediario del credito NON in esclusiva.

* In fase di richiesta del finanziamento verrà proposta la facoltà di selezionare, in alternativa all’imposta di bollo sul contratto di 16,00 euro, l’imposta sostitutiva, pari allo 0,25% dell’importo finanziato.

Contattaci senza impegno per informazioni sul corso

Scopriamo insieme se i nostri corsi fanno per te. Compila il form e aspetta la chiamata di uno dei nostri consulenti.