Conflitti di merge Git
I sistemi di controllo della versione riguardano la gestione dei contributi tra più autori distribuiti (di solito sviluppatori). A volte più sviluppatori possono provare a modificare lo stesso contenuto. Se lo sviluppatore A tenta di modificare il codice che lo sviluppatore B sta modificando, potrebbe verificarsi un conflitto. Per ridurre il verificarsi di conflitti, gli sviluppatori lavorano in branch isolati separati. La responsabilità principale del comando git merge
è quella di unire branch separati e risolvere eventuali modifiche in conflitto.
Cosa sono i conflitti di merge
I conflitti si verificano generalmente quando due persone hanno modificato le stesse righe in un file o se uno sviluppatore ha eliminato un file mentre un altro sviluppatore lo stava modificando. In questi casi, Git non è in grado di determinare automaticamente la versione corretta. I conflitti riguardano solo lo sviluppatore che esegue il merge, il resto del team ne rimane all'oscuro. Git contrassegnerà il file come in conflitto e interromperà il processo di merge. È quindi responsabilità degli sviluppatori risolvere il conflitto.
Tipi di conflitti di merge
Un merge può entrare in uno stato di conflitto in due punti separati: all'avvio e durante il processo di merge. Di seguito è riportata un'analisi su come affrontare ciascuno di questi scenari di conflitto.
Git non riesce ad avviare il merge
Il merge non verrà avviato se Git rileva modifiche nella directory di lavoro o nell'area di staging del progetto corrente. Git non riesce ad avviare il merge perché queste modifiche in sospeso potrebbero essere sovrascritte dai commit sottoposti a merge. Ciò non è causato dai conflitti con altri sviluppatori, ma dal conflitto con modifiche locali in sospeso. Occorre stabilizzare lo stato locale tramite git stash
, git checkout
, git commit
o git reset
. Un errore di merge all'avvio genererà il seguente messaggio di errore:
error: Entry '<fileName>' not uptodate. Cannot merge. (Changes in working directory)
Errore di Git durante il merge
Un errore DURANTE un merge indica un conflitto tra il branch locale corrente e il branch che si sta sottoponendo a merge. Questo indica un conflitto con il codice di un altro sviluppatore. Git farà del suo meglio per eseguire il merge dei file, ma ti lascerà la libertà di risolvere manualmente i conflitti nei file interessati. Un errore che si verifica durante il merge genererà il seguente messaggio:
materiale correlato
Registro Git avanzato
Scopri la soluzione
Impara a utilizzare Git con Bitbucket Cloud
error: Entry '<fileName>' would be overwritten by merge. Cannot merge. (Changes in staging area)
Creazione di un conflitto di merge
Per acquisire familiarità con i conflitti di merge, nella sezione successiva verrà simulato un conflitto che sarà esaminato e risolto. Per eseguire la simulazione di esempio, sarà utilizzata un'interfaccia Git a riga di comando simile a Unix.
$ mkdir git-merge-test
$ cd git-merge-test
$ git init .
$ echo "this is some content to mess with" > merge.txt
$ git add merge.txt
$ git commit -am"we are commiting the inital content"
[main (root-commit) d48e74c] we are commiting the inital content
1 file changed, 1 insertion(+)
create mode 100644 merge.txt
Questo esempio di codice esegue una sequenza di comandi che portano a termine le seguenti operazioni:
- Creare una nuova directory denominata
git-merge-test,
passare a quest'ultima e inizializzarla come nuovo repository Git. - Creare un nuovo file di testo
merge.txt
con del contenuto. - Aggiungere
merge.txt
al repository ed eseguirne il commit.
Ora abbiamo un nuovo repository con un branch main
e un file merge.txt
con del contenuto. Quindi, creiamo un nuovo branch da utilizzare come merge in conflitto.
$ git checkout -b new_branch_to_merge_later
$ echo "totally different content to merge later" > merge.txt
$ git commit -am"edited the content of merge.txt to cause a conflict"
[new_branch_to_merge_later 6282319] edited the content of merge.txt to cause a conflict
1 file changed, 1 insertion(+), 1 deletion(-)
La sequenza di comandi della procedura consente di ottenere il risultato seguente:
- creare ed estrarre un nuovo branch chiamato
new_branch_to_merge_later
- sovrascrivere il contenuto in
merge.txt
- eseguire il commit dei nuovi contenuti
Con questo nuovo branch: new_branch_to_merge_later
abbiamo creato un commit che sovrascrive il contenuto di merge.txt
git checkout main
Switched to branch 'main'
echo "content to append" >> merge.txt
git commit -am"appended content to merge.txt"
[main 24fbe3c] appended content to merge.tx
1 file changed, 1 insertion(+)
Questa catena di comandi estrae il branch main
, aggiunge il contenuto a merge.txt
e ne esegue il commit. Questa operazione mette ora il repository di esempio in uno stato in cui sono presenti 2 nuovi commit: uno nel branch main
e uno nel branch new_branch_to_merge_later
. Adesso, eseguiamo git merge new_branch_to_merge_later
e vediamo cosa succede.
$ git merge new_branch_to_merge_later
Auto-merging merge.txt
CONFLICT (content): Merge conflict in merge.txt
Automatic merge failed; fix conflicts and then commit the result.
BOOM 💥. Viene visualizzato un conflitto. Grazie Git per averci informato!
Come identificare i conflitti di merge
Come abbiamo visto nell'esempio della procedura, Git genererà un messaggio di output descrittivo per informarci che si è verificato un CONFLITTO. Possiamo ottenere ulteriori informazioni eseguendo il comando git status
$ 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
L'output di git status
indica che ci sono percorsi non sottoposti a merge a causa di un conflitto. Il file merge.text
ora appare in uno stato modificato. Esaminiamo il file e vediamo cosa è stato modificato.
$ cat merge.txt
<<<<<<< HEAD
this is some content to mess with
content to append
=======
totally different content to merge later
>>>>>>> new_branch_to_merge_later
Qui abbiamo usato il comando cat
per visualizzare il contenuto del file merge.txt.
Possiamo vedere alcune nuove aggiunte inusuali
<<<<<<< HEAD
=======
>>>>>>> new_branch_to_merge_later
Pensiamo a queste nuove righe come a "divisori dei conflitti". La riga =======
è il "centro" del conflitto. Tutti i contenuti tra il centro e la riga <<<<<<< HEAD
sono i contenuti che si trovano nel branch principale corrente a cui punta il riferimento HEAD
. Oppure, tutti i contenuti tra il centro e >>>>>>> new_branch_to_merge_later
sono i contenuti presenti nel branch di merge.
Come risolvere i conflitti di merge utilizzando la riga di comando
Il modo più diretto per risolvere un conflitto di merge è modificare il file in conflitto. Apri il file merge.txt
nel tuo editor preferito. Per il nostro esempio, rimuoviamo semplicemente tutti i divisori dei conflitti. Il contenuto modificato di merge.txt
dovrebbe quindi avere il seguente aspetto:
this is some content to mess with
content to append
totally different content to merge later
Una volta che il file è stato modificato, usa git add merge.txt
per preparare per il commit il nuovo contenuto sottoposto a merge. Per finalizzare il merge, crea un nuovo commit eseguendo:
git commit -m "merged and resolved the conflict in merge.txt"
Git vedrà che il conflitto è stato risolto e crea un nuovo commit di merge per finalizzare il merge.
Comandi Git utili per risolvere i conflitti di merge
Strumenti generali
git status
Il comando status è utilizzato di frequente quando si lavora con Git e durante un merge aiuta a identificare i file in conflitto.
git log --merge
L'invio dell'argomento --merge
al comando git log
produrrà un log con un elenco di commit in conflitto tra i branch di merge.
git diff
diff
aiuta a trovare le differenze tra gli stati di un repository o dei file. Questo comando è utile per prevedere e prevenire i conflitti di merge.
Strumenti per quando Git non riesce ad avviare un merge
git checkout
Il comando checkout
può essere utilizzato per annullare le modifiche ai file o per modificare i branch
git reset --mixed
Il comando reset
può essere usato per annullare le modifiche alla directory di lavoro e all'area di staging.
Strumenti per quando sorgono conflitti Git durante un merge
git merge --abort
L'esecuzione di git merge
con l'opzione --abort
consente di uscire dal processo di merge e far tornare il branch allo stato in cui si trovava prima del merge.
git reset
git reset
può essere usato durante un conflitto di merge per ripristinare i file in conflitto a uno stato accettabile noto
Riepilogo
I conflitti di merge possono essere un'esperienza spaventosa. Fortunatamente, Git offre efficaci strumenti per aiutare a gestire e risolvere i conflitti. Git è in grado di gestire la maggior parte dei merge in autonomia grazie alle funzioni di merge automatico. Un conflitto si verifica quando due branch separati hanno apportato modifiche alla stessa riga di un file o quando un file è stato eliminato in un branch ma modificato nell'altro. Molto probabilmente si verificheranno conflitti quando si lavora in team.
Esistono molti strumenti che aiutano a risolvere i conflitti di merge. In Git sono disponibili molti strumenti da riga di comando di cui abbiamo parlato in questo documento. Per informazioni più dettagliate su questi strumenti, visita le pagine individuali relative a git log, git reset, git status, git checkout e git reset. Oltre a Git, molti strumenti di terze parti offrono funzioni semplificate di supporto per i conflitti di merge.
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.