Close

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:

Finestra della console
materiale correlato

Registro Git avanzato

Logo di Bitbucket
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.

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