Merge è un'operazione in Git che combina le modifiche da un ramo all'altro, creando un commit di fusione (merge commit). Git supporta diverse strategie: fast-forward (storia lineare), three-way merge (con creazione di un merge commit) e squash merge (compressione di tutti i commit in uno). Secondo git-scm.com, 2025, il merge rimane il meccanismo di integrazione del codice più utilizzato nello sviluppo Git di squadra.
Punti chiave
Merge (fusione) è un'operazione fondamentale in Git che combina le modifiche da un ramo (source) a un altro (target). Come risultato della fusione, il ramo target riceve tutti i commit dal ramo source che non erano ancora presenti in esso. A seconda della situazione, Git può eseguire il merge in tre modi diversi.
Il principale valore del merge è preservare la storia: il merge commit registra il fatto della fusione dei rami, conservando informazioni su quando e quali rami sono stati fusi. Ciò facilita l'audit delle modifiche, la ricerca di regressioni e la comprensione della cronologia dello sviluppo. Nei progetti grandi, il merge commit è il metodo standard di integrazione del codice.
Secondo GitLab Flow, i merge commit sono utilizzati nel 73% dei team che lavorano con Git. Gli approcci alternativi (rebase, squash) sono preferiti da team orientati a una storia lineare. La scelta della strategia dipende dalla dimensione del team, dalla frequenza dei rilasci e dalle convenzioni accettate nel progetto.
Merge è necessario quando uno sviluppatore ha terminato di lavorare su una funzionalità e vuole integrarla in develop o main. Uno scenario tipico: uno sviluppatore ha creato un ramo feature da develop, ci ha lavorato per diversi giorni, e durante questo tempo sono apparsi nuovi commit di altri membri del team in develop. Prima della fusione, è necessario combinare le modifiche — e per questo si usa il merge.
Senza merge, è impossibile lavorare collaborativamente su un unico codice in Git. Ogni volta che due sviluppatori apportano modifiche simultanee a una stessa base di codice, i loro rami divergono. Il merge è l'unico modo per riunire queste modifiche senza perdita di dati.
Git supporta tre tipi di merge, ciascuno progettato per il proprio scenario. La scelta del tipo di fusione influisce sulla storia dei commit, sulla facilità di rollback e sulla leggibilità del log.
Fast-forward si verifica quando il ramo target non ha avuto nuovi commit dalla creazione del ramo source. In questo caso, Git sposta semplicemente il puntatore del ramo target in avanti, all'ultimo commit del ramo source. La storia rimane lineare, senza merge commit.
# Fast-forward merge: develop non è cambiato dalla creazione di feature
git checkout develop
git merge feature/new-login
# Risultato: il puntatore develop si è spostato alla fine di feature
# Nessun merge commit è stato creato
Fast-forward è conveniente per rami di breve durata dove uno sviluppatore ha lavorato da solo. Ma questo approccio ha uno svantaggio: si perde l'informazione che il ramo è esistito — tutti i commit sembrano fatti direttamente in develop.
Three-way merge viene eseguito quando entrambi i rami hanno nuovi commit dopo il punto di divergenza. Git crea un merge commit separato con due genitori, che registra il fatto della fusione dei rami. Questo approccio è raccomandato per i rami feature nello sviluppo di squadra.
# Three-way merge forzato con il flag --no-ff
git checkout develop
git merge --no-ff feature/new-login
# Un merge commit è stato creato con il messaggio predefinito
# Puoi impostare il tuo messaggio tramite -m
git merge --no-ff feature/new-login -m "Merge feature/new-login into develop"
Il flag --no-ff garantisce la creazione di un merge commit, anche se il fast-forward è possibile. Questa è una buona pratica per preservare le informazioni di ramificazione in un progetto.
Squash merge comprime tutti i commit del ramo source in uno e lo applica al target. La storia della funzionalità viene persa — un singolo commit con tutte le modifiche finisce nel ramo. Questo è conveniente quando i commit dettagliati in un ramo feature non aggiungono valore alla storia generale.
# Squash merge: tutti i commit di feature sono compressi in uno
git checkout develop
git merge --squash feature/experimental
git commit -m "feat: experimental login flow (squashed)"
Squash è adatto per bozze, rami sperimentali e situazioni in cui è importante mantenere una storia pulita. Lo svantaggio è che la connessione con i commit originali viene persa, rendendo più difficile il rollback delle modifiche individuali.
Ours e Theirs sono due strategie speciali di merge in Git. Ours ignora completamente le modifiche dal ramo source, mantenendo solo ciò che è nel target. Theirs, al contrario, accetta la versione del ramo source in qualsiasi conflitto. Queste strategie sono utili quando si fondono grandi quantità di codice quando si sa in anticipo quale versione deve prevalere.
Il meccanismo di merge in Git si basa sul confronto di tre punti: l'antenato comune (merge base), lo stato del ramo source e lo stato del ramo target. Git trova il merge base — l'ultimo commit comune a entrambi i rami — e calcola quali modifiche sono avvenute in ciascun ramo dopo la divergenza.
Git utilizza un algoritmo di fusione a tre vie che considera non solo le due versioni del file confrontate, ma anche il loro antenato comune. Grazie a ciò, Git può risolvere automaticamente situazioni in cui le modifiche in un ramo non influenzano le aree modificate dell'altro — anche se entrambi i file sono stati modificati.
Consideriamo uno scenario: due sviluppatori lavorano su file diversi in uno stesso ramo feature. Il primo ha modificato LoginActivity.kt, il secondo ha modificato ProfileFragment.kt. Quando fondono le loro modifiche, Git vede che le modifiche hanno interessato file diversi ed esegue il merge automaticamente, senza intervento umano.
Se entrambi gli sviluppatori hanno modificato LoginActivity.kt, ma in metodi diversi — Git gestirà anche questo automaticamente, fondendo le modifiche riga per riga. Un conflitto sorge solo se entrambi hanno modificato le stesse righe o se uno ha cancellato codice che l'altro ha modificato.
Un conflitto di merge si verifica quando Git non può fondere automaticamente le modifiche perché entrambi i rami hanno modificato le stesse righe in modo diverso. In questo caso, Git segna le aree in conflitto nei file e attende la risoluzione manuale dallo sviluppatore.
Le aree in conflitto vengono contrassegnate con marcatori speciali: <<<<<<< HEAD mostra il codice del ramo target, ======= è il separatore, >>>>>>> source-branch mostra il codice del ramo source. Lo sviluppatore deve scegliere manualmente quale versione mantenere o combinarle.
# 1. Eseguire il merge e vedere il conflitto
git merge feature/new-login
# Output: CONFLICT (content): Merge conflict in LoginActivity.kt
# 2. Visualizzare l'elenco dei file con conflitti
git status
# both modified: src/ui/login/LoginActivity.kt
# 3. Risolvere il conflitto: modificare il file, rimuovere i marcatori
# 4. Aggiungere il file risolto e completare il merge
git add src/ui/login/LoginActivity.kt
git merge --continue
# o: git commit (senza --continue)
Esistono strumenti per risolvere i conflitti: git mergetool apre un merger visuale (Meld, Beyond Compare, VS Code). Molti sviluppatori preferiscono risolvere i conflitti nell'IDE — IntelliJ IDEA e Android Studio forniscono uno strumento integrato con confronto a tre pannelli che semplifica notevolmente questo processo.
Suggerimenti per risolvere i conflitti: comprendere sempre cosa fa ciascun lato del conflitto, non eliminare il codice altrui senza comprenderne la logica, e se il conflitto è troppo complesso — coinvolgere gli autori di entrambi i rami in una risoluzione congiunta.
La scelta tra Merge e Rebase è una delle decisioni architetturali più comuni in Git. Entrambi gli approcci combinano le modifiche, ma lo fanno in modo diverso: merge preserva la storia di ramificazione, rebase riscrive la storia rendendola lineare.
Molti team utilizzano un approccio ibrido: rebase per aggiornare il ramo feature con develop (git rebase develop), e poi merge con il flag --no-ff per registrare la fusione. Questo dà una storia pulita all'interno della funzionalità e punti di fusione informativi a livello di develop.
Domande frequenti
Senza --no-ff Git esegue un fast-forward merge se possibile — sposta semplicemente il puntatore del ramo. Con --no-ff Git crea sempre un merge commit, preservando le informazioni di ramificazione. Raccomandato per i rami feature nello sviluppo di squadra.
Usa git mergetool o lo strumento integrato dell'IDE. Se il conflitto coinvolge decine di file — i rami potrebbero essersi discostati troppo. In questo caso, discuti il piano di fusione con il team, possibilmente suddividendolo in più fasi.
Sì: git merge --abort annulla il merge se non è ancora stato completato (conflitto). Se il merge è già stato completato — usa git reset --hard HEAD~1 o git revert -m 1 <merge-commit> per un rollback sicuro.
Raccomandato per il lavoro di squadra. Il merge commit registra il fatto della fusione, contiene riferimenti a entrambi i rami e semplifica la comprensione della storia. Per rami personali o sperimentali, squash merge o fast-forward sono accettabili.
Git non può fondere automaticamente i file binari — seleziona una versione per intero. Per i file binari (immagini, .aab, .apk) si raccomanda di minimizzare le modifiche parallele e utilizzare Git LFS per file grandi.
Riepilogo
Svilupperemo un'applicazione mobile chiavi in mano
IT Sectr crea applicazioni iOS e Android per startup e aziende dal 2017. Ti consulteremo e ti proporremo la soluzione migliore.
Leggi anche