
🐙 Errore git 'fatal: refusing to merge unrelated histories': cause e soluzione
Hai eseguito git pull e, invece delle modifiche attese, il terminale ti ha accolto con una riga rossa: fatal: refusing to merge unrelated histories. Il progetto non si è aggiornato, i commit non sono stati scaricati e tu sei lì a chiederti se hai rotto la repository.
No, non l'hai rotta. Git si rifiuta semplicemente di mescolare due cronologie indipendenti, e questo è un comportamento intenzionale, non un bug. In cinque minuti non solo capirai perché si verifica questo errore, ma imparerai anche a risolverlo in qualsiasi situazione: al primo push, dopo aver perso la cartella .git e quando unisci progetti diversi.
💡 Panoramica rapida:
- Quando Git rifiuta di unire branch non correlati e perché è corretto
- Il flag
--allow-unrelated-histories, una soluzione universale perpull,mergee primo push - Scenari passo passo: clonazione senza cronologia, nuova repository, rebase e force-push
- Cosa fare se il flag non aiuta e come evitare questo errore in futuro
Cosa significa l'errore e perché Git lo genera
Git traccia la cronologia attraverso una catena di commit. Ogni commit fa riferimento al suo genitore, costruendo un grafo che Git usa per capire cosa proviene da dove. Quando fai git merge, Git cerca un antenato comune tra due branch e calcola la differenza a partire da esso.
Ma a volte semplicemente non c'è un antenato comune. Due grafi di commit non si intersecano, come due progetti separati che non hanno mai saputo l'uno dell'altro. In una situazione del genere, Git si rifiuta di unire le cronologie alla cieca e restituisce:
1 fatal: refusing to merge unrelated histories
Questo non è un errore nel senso comune del termine. È una protezione: Git ti sta dicendo «Non capisco come queste due cronologie siano correlate, quindi non tiro a indovinare». La soluzione esiste ed è integrata in Git a partire dalla versione 2.9.0 (rilasciata a giugno 2016).
Due scenari tipici che portano all'errore
Primo scenario, **corruzione o cancellazione della cartella **.git. Hai clonato un progetto, hai lavorato con il codice, ma la cartella .git è stata eliminata (accidentalmente, da un antivirus o durante la copia senza file nascosti). Git perde tutta la cronologia locale e quando tenti git push o git pull tratta la tua directory di lavoro come un progetto completamente nuovo, non correlato alla repository remota.
Secondo scenario, una nuova repository incontra una esistente. Hai fatto git init, hai aggiunto diversi commit in locale, poi hai provato a collegare una repository remota che ha già una sua cronologia. Git vede due grafi di commit indipendenti e si rifiuta di mescolarli. Questo accade spesso quando inizi un progetto da zero, poi decidi di caricarlo su GitHub sopra una repository esistente, o quando trasferisci codice da un progetto a un altro.
Entrambi gli scenari si risolvono con lo stesso meccanismo, ma prima di applicarlo dovresti capire cosa vuoi ottenere esattamente: unire due cronologie in una o sostituire completamente una cronologia con un'altra.
Soluzione: il flag --allow-unrelated-histories
La chiave per risolvere il problema è il flag --allow-unrelated-histories. Dice esplicitamente a Git: «So che questi branch non hanno un antenato comune e voglio consapevolmente unirli». Il flag funziona con entrambi i comandi principali, git pull e git merge.
**Per **git pull (il caso più comune):
1 git pull origin main --allow-unrelated-histories
Sostituisci main con il nome del tuo branch se è diverso (master, develop, ecc.). Git creerà un commit di merge che collega le due cronologie indipendenti. Probabilmente si aprirà un editor per il messaggio di commit, descrivi perché stai unendo le cronologie, salva e chiudi l'editor.
**Per **git merge (quando i branch sono locali):
1 git merge feature-branch --allow-unrelated-histories
Dopo il merge riuscito, Git ti chiederà di fare push del risultato. Non dimenticare di farlo:
1 git push origin main
Sfumatura importante: --allow-unrelated-histories non elimina i conflitti di merge. Se entrambi i branch hanno file con gli stessi nomi, Git ti chiederà comunque di risolvere i conflitti manualmente, il flag gestisce solo la connessione delle cronologie, non il contenuto dei file.
Scenari passo passo per diverse situazioni
Situazione 1: primo push su una repository remota non vuota
Hai creato un progetto in locale (git init → commit) e su GitHub c'è già una repository con README.md e .gitignore. Un git push diretto non funzionerà perché il branch remoto contiene commit che tu non hai.
Sequenza corretta:
Prima fai pull della cronologia remota e la unisci con la tua locale:
1 git pull origin main --allow-unrelated-histories
Risolvi i conflitti se ce ne sono (di solito conflitti su README.md), fai un commit di merge, poi:
1 git push origin main
Situazione 2: ripristino dopo la perdita di.git
La cartella .git è stata eliminata, ma la directory di lavoro è intatta. Puoi ripristinare la connessione alla repository remota senza perdere le modifiche non committate:
1 git init 2 git remote add origin <repository-url> 3 git fetch origin 4 git reset --mixed origin/main
Il comando git reset --mixed sincronizza l'indice di Git con il branch remoto, ma mantiene intatti tutti i tuoi file di lavoro. Dopodiché, aggiungi le modifiche e fai un nuovo commit:
1 git add . 2 git commit -m "Recovery after losing .git" 3 git push origin main
Questo approccio è preferibile a --allow-unrelated-histories perché non crea un commit di merge artificiale e mantiene pulita la cronologia.
Situazione 3: rebase con cronologie non correlate
Anche il comando git rebase può generare questo errore, specialmente quando si usa il flag --preserve-merges (ora sostituito da --rebase-merges). Soluzione: aggiungi --allow-unrelated-histories:
1 git rebase --rebase-merges --allow-unrelated-histories main
Ma fai attenzione: il rebase riscrive la cronologia e se qualcun altro sta lavorando con questo branch, creerai problemi. Per i branch condivisi, preferisci sempre merge.
Cosa fare se il flag non aiuta
A volte --allow-unrelated-histories funziona senza errori, ma il risultato non è quello che volevi.
Problema: il commit di merge appesantisce la cronologia. Se hai unito due grandi progetti, il grafo dei commit diventa difficile da leggere. In questo caso, considera un'alternativa: trasferire i file con conservazione della cronologia tramite git format-patch e git am:
1 git format-patch --root -o patches/ HEAD 2 git am patches/*.patch
Problema: dopo il merge il progetto non compila. Unire cronologie non correlate può portare a file di configurazione duplicati, conflitti di dipendenze o versioni di pacchetti incompatibili. Dopo --allow-unrelated-histories controlla sempre: dipendenze (npm install / composer install), file di configurazione (.env, config/), percorsi e import nel codice. Meglio dedicare cinque minuti alla verifica ora che affrontare build fallite in CI più tardi.
Problema: hai cambiato idea. Puoi annullare un merge di cronologie non correlate nel modo standard: git reset --hard HEAD~1 (se non hai ancora fatto push del risultato) o git revert -m 1 HEAD (se hai già fatto push).
Come evitare l'errore in futuro
Tre semplici regole che ti risparmieranno questo errore nel lavoro quotidiano.
Non eliminare .git senza assoluta necessità. Se devi copiare il codice senza cronologia, usa git archive o copia i file escludendo consapevolmente la cartella nascosta .git, non accidentalmente.
Non creare una nuova repository dentro una esistente. Se devi estrarre parte del codice in un progetto separato, usa git subtree split o git filter-branch (ora si consiglia git filter-repo). Questi strumenti conserveranno la cronologia dei file necessari e Git saprà da dove provengono.
Prima di git init in una cartella con codice, controlla sempre se c'è già una repository lì: git status. Se Git risponde fatal: not a git repository, puoi inizializzare. Se mostra lo stato, sei già dentro una repository esistente e git init non serve qui.
Per chi inizia a lavorare con Git, consigliamo la nostra guida "Guida a Git per principianti", che illustra passo passo le chiavi SSH, la creazione di repository e il flusso di lavoro completo su GitHub. E se Git non è ancora installato, inizia con la guida "Come installare Git su Windows".
⁉️🤔 Domande frequenti
Quali versioni di Git supportano --allow-unrelated-histories?
Il flag è apparso in Git 2.9.0 (giugno 2016) ed è presente in tutte le versioni successive. Se la tua versione di Git è più vecchia, aggiornala: il comando
git --versionmostrerà la versione corrente egit update-git-for-windows(su Windows) o il gestore di pacchetti del tuo sistema la aggiornerà all'ultima release. Il modo più semplice per controllare la versione di Git è il comandogit --versionnel terminale. A metà 2026, il branch corrente è la 2.48+. Se sei su Windows e Git è stato installato molto tempo fa, scarica un installer aggiornato da git-scm.com, l'aggiornamento automatico nelle vecchie versioni funzionava in modo instabile.
Posso usare il flag direttamente con git push?
No,
git pushnon accetta--allow-unrelated-histories. Il push non crea un merge, invia solo commit esistenti. L'errore "unrelated histories" durante il push significa che il tuo branch locale e quello remoto hanno diverguto a livello di cronologia. Soluzione: primagit pull --allow-unrelated-histories, risolvi i conflitti e solo dopo faigit push. Formalmente--allow-unrelated-historiesfunziona congit fetch+git mergee congit pull(che internamente fa fetch + merge). Il push rimane un'operazione separata che esegui dopo il merge riuscito. Non cercare di aggirare il problema con--force, perderesti i commit di altre persone sulla repository remota.
Cosa è meglio per una cronologia pulita: merge o rebase?
Per collegare cronologie non correlate, sicuramente
merge. Il rebase in questo contesto crea più problemi di quanti ne risolva: tenta di riapplicare i commit di un branch sopra un altro, ma senza un antenato comune questo porta a conflitti su ogni commit. Il merge con--allow-unrelated-historiesfa esattamente ciò che serve: crea un punto di connessione tra i due grafi, dopodiché la cronologia è unificata. Eccezione: quando vuoi intenzionalmente riscrivere la cronologia e sai esattamente cosa stai facendo. Ad esempio, quando trasferisci codice da una repository a un'altra con pulizia dai vecchi commit. In questo casogit rebase --allow-unrelated-historiespuò avere senso, ma per il lavoro quotidiano scegli il merge.
Ho perso la cartella .git, ma ho modifiche non committate. Le perderò?
No, non le perderai. La cartella
.gitstessa contiene solo la cronologia e i metadati di Git, non i tuoi file di lavoro. Tutti i file modificati, nuovi e persino non committati rimarranno intatti nella directory di lavoro. La procedura di ripristino è descritta nella "Situazione 2" qui sopra:git init→git remote add→git fetch→git reset --mixed. Punto chiave: usa esattamente--mixed, non--hard. Il flag--mixedresetta l'indice ma conserva tutte le modifiche nei file. Se non sei sicuro, fai una copia di backup dell'intera cartella del progetto prima del ripristino, ci vorranno dieci secondi ed eliminerai completamente il rischio di perdita di dati in qualsiasi situazione anomala.
L'errore si verifica durante la clonazione tramite IDE. È lo stesso problema?
Sì, lo stesso. Alcuni IDE (ad esempio PHPStorm, Visual Studio, vecchie versioni di IntelliJ) quando creano un progetto da un template inizializzano una nuova repository Git, poi tentano di collegare un remoto. Questo è esattamente il secondo scenario dell'inizio dell'articolo. La soluzione è la stessa: apri un terminale nella cartella del progetto ed esegui
git pull origin main --allow-unrelated-histories. Dopo il merge manuale, l'IDE rileverà automaticamente il nuovo stato, ti basta aggiornare la finestra del progetto o cliccare Refresh nel pannello Git.
Bisogna temere l'errore "unrelated histories"?
No. Questo è uno degli errori Git più sicuri: non corrompe i dati, non elimina file e non impedisce di continuare a lavorare. Il flag --allow-unrelated-histories non è un espediente o una soluzione di fortuna, ma una funzionalità documentata aggiunta appositamente dagli sviluppatori di Git per i casi in cui vuoi consapevolmente collegare due cronologie indipendenti.
Una volta padroneggiato questo comando, ottieni uno strumento potente: ora puoi unire progetti con qualsiasi grado di isolamento, trasferire codice tra repository e ripristinare il lavoro dopo aver perso .git, e tutto questo senza panico e senza ricreare la repository da zero. Se Git ti ha insegnato qualcosa oggi, è che "fatal" nei suoi messaggi non significa "fatale per il progetto", significa «Non tiro a indovinare, dimmi esplicitamente cosa fare».



