
🐙 Erro do Git 'fatal: refusing to merge unrelated histories': causas e solução
Executou git pull e, em vez das alterações esperadas, o terminal cumprimentou-o com uma linha vermelha: fatal: refusing to merge unrelated histories. O projeto não foi atualizado, os commits não foram recebidos e você ficou a pensar se teria corrompido o repositório.
Não, não o corrompeu. O Git simplesmente se recusa a misturar dois históricos independentes, e este é um comportamento intencional, não um bug. Em cinco minutos, não só vai perceber porque é que este erro ocorre, como também aprenderá a corrigi-lo em qualquer situação: no primeiro push, após perder a pasta .git e ao fundir projetos díspares.
💡 Visão geral rápida:
- Quando o Git se recusa a fundir ramos não relacionados e porque é que isto está correto
- A flag
--allow-unrelated-histories, uma solução universal parapull,mergee primeiro push - Cenários passo a passo: clonagem sem histórico, novo repositório, rebase e force-push
- O que fazer se a flag não ajudar e como evitar este erro no futuro
O que significa o erro e porque é que o Git o emite
O Git rastreia o histórico através de uma cadeia de commits. Cada commit referencia o seu pai, construindo um grafo que o Git usa para perceber o que veio de onde. Quando faz git merge, o Git procura um ancestral comum entre dois ramos e calcula a diferença a partir dele.
Mas, por vezes, simplesmente não existe um ancestral comum. Dois grafos de commits não se intersectam, como dois projetos separados que nunca souberam da existência um do outro. Nessa situação, o Git recusa-se a fundir os históricos às cegas e emite:
1 fatal: refusing to merge unrelated histories
Isto não é um erro no sentido habitual. É uma proteção: o Git está a dizer-lhe: «Não percebo como é que estes dois históricos estão relacionados, por isso não vou adivinhar.» A solução existe e está incorporada no Git a partir da versão 2.9.0 (lançada em junho de 2016).
Dois cenários típicos que levam ao erro
Primeiro cenário, **corrupção ou eliminação da pasta **.git. Clonou um projeto, trabalhou com o código, mas a pasta .git foi eliminada (acidentalmente, por um antivírus ou ao copiar sem ficheiros ocultos). O Git perde todo o histórico local e, ao tentar git push ou git pull, trata o seu diretório de trabalho como um projeto completamente novo, não relacionado com o repositório remoto.
Segundo cenário, um novo repositório encontra um já existente. Fez git init, adicionou vários commits localmente e depois tentou ligar um repositório remoto que já tem o seu próprio histórico. O Git vê dois grafos de commits independentes e recusa-se a misturá-los. Isto acontece frequentemente quando começa um projeto de raiz e depois decide carregá-lo para o GitHub por cima de um repositório existente, ou ao transferir código de um projeto para outro.
Ambos os cenários são resolvidos pelo mesmo mecanismo, mas antes de o aplicar, deve perceber exatamente o que pretende alcançar: fundir dois históricos num só ou substituir completamente um histórico pelo outro.
Solução: a flag --allow-unrelated-histories
A chave para corrigir isto é a flag --allow-unrelated-histories. Ela diz explicitamente ao Git: «Eu sei que estes ramos não têm um ancestral comum e quero conscientemente fundi-los.» A flag funciona com ambos os comandos principais, git pull e git merge.
**Para **git pull (o caso mais comum):
1 git pull origin main --allow-unrelated-histories
Substitua main pelo nome do seu ramo, se for diferente (master, develop, etc.). O Git criará um commit de merge que liga os dois históricos independentes. É provável que um editor se abra para a mensagem do commit; descreva porque está a fundir os históricos, guarde e feche o editor.
**Para **git merge (quando os ramos são locais):
1 git merge feature-branch --allow-unrelated-histories
Após um merge bem-sucedido, o Git irá sugerir que faça push do resultado. Não se esqueça de o fazer:
1 git push origin main
Nuance importante: --allow-unrelated-histories não elimina conflitos de merge. Se ambos os ramos tiverem ficheiros com os mesmos nomes, o Git continuará a pedir-lhe para resolver os conflitos manualmente; a flag apenas trata da ligação dos históricos, não do conteúdo dos ficheiros.
Cenários passo a passo para diferentes situações
Situação 1: primeiro push para um repositório remoto não vazio
Criou um projeto localmente (git init → commits) e no GitHub já existe um repositório com README.md e .gitignore. Um git push direto não funcionará porque o ramo remoto contém commits que você não tem.
Sequência correta:
Primeiro, faça pull do histórico remoto e funda-o com o seu local:
1 git pull origin main --allow-unrelated-histories
Resolva os conflitos, se existirem (normalmente conflitos no README.md), faça um commit de merge e depois:
1 git push origin main
Situação 2: recuperação após perder a.git
A pasta .git foi eliminada, mas o diretório de trabalho está intacto. Pode restaurar a ligação ao repositório remoto sem perder as alterações não commitadas:
1 git init 2 git remote add origin <repository-url> 3 git fetch origin 4 git reset --mixed origin/main
O comando git reset --mixed sincroniza o índice do Git com o ramo remoto, mas mantém todos os seus ficheiros de trabalho intactos. Depois disto, adicione as alterações e faça um novo commit:
1 git add . 2 git commit -m "Recovery after losing .git" 3 git push origin main
Esta abordagem é preferível ao --allow-unrelated-histories porque não cria um commit de merge artificial e mantém o histórico limpo.
Situação 3: rebase com históricos não relacionados
O comando git rebase também pode emitir este erro, especialmente ao usar a flag --preserve-merges (agora substituída por --rebase-merges). A solução é adicionar --allow-unrelated-histories:
1 git rebase --rebase-merges --allow-unrelated-histories main
Mas tenha cuidado: o rebase reescreve o histórico e, se mais alguém estiver a trabalhar com este ramo, irá criar-lhes problemas. Para ramos partilhados, prefira sempre o merge.
O que fazer se a flag não ajudar
Por vezes, o --allow-unrelated-histories funciona sem erros, mas o resultado não é o que pretendia.
Problema: o commit de merge polui o histórico. Se fundiu dois projetos grandes, o grafo de commits torna-se difícil de ler. Neste caso, considere uma alternativa: transferir ficheiros com preservação do histórico via git format-patch e git am:
1 git format-patch --root -o patches/ HEAD 2 git am patches/*.patch
Problema: após o merge, o projeto não compila. Fundir históricos não relacionados pode levar a ficheiros de configuração duplicados, conflitos de dependências ou versões de pacotes incompatíveis. Após --allow-unrelated-histories, verifique sempre: dependências (npm install / composer install), ficheiros de configuração (.env, config/), caminhos e imports no código. É melhor gastar cinco minutos na verificação agora do que lidar com builds a falhar no CI mais tarde.
Problema: mudou de ideias. Pode reverter um merge de históricos não relacionados da forma padrão: git reset --hard HEAD~1 (se ainda não tiver feito push do resultado) ou git revert -m 1 HEAD (se já tiver feito push).
Como evitar o erro no futuro
Três regras simples que o pouparão a este erro no trabalho diário.
Não elimine a pasta .git sem necessidade absoluta. Se precisar de copiar código sem histórico, use git archive ou copie os ficheiros excluindo conscientemente a pasta oculta .git, e não acidentalmente.
Não crie um novo repositório dentro de um já existente. Se precisar de extrair parte do código para um projeto separado, use git subtree split ou git filter-branch (atualmente, recomenda-se o git filter-repo). Estas ferramentas preservarão o histórico dos ficheiros necessários e o Git saberá de onde eles vieram.
Antes de executar git init numa pasta com código, verifique sempre se já existe lá um repositório: git status. Se o Git responder fatal: not a git repository, pode inicializar. Se mostrar o estado, já está dentro de um repositório existente e o git init não é necessário aqui.
Para quem está a começar a trabalhar com o Git, recomendamos o nosso guia "Git guide for beginners", que aborda passo a passo as chaves SSH, a criação de repositórios e o fluxo de trabalho completo no GitHub. E se o Git ainda não estiver instalado, comece pelo guia "How to install Git on Windows".
⁉️🤔 Perguntas frequentes
Que versões do Git suportam o --allow-unrelated-histories?
A flag surgiu no Git 2.9.0 (junho de 2016) e está presente em todas as versões subsequentes. Se a sua versão do Git for mais antiga, atualize-a: o comando
git --versionmostrará a versão atual e ogit update-git-for-windows(no Windows) ou o gestor de pacotes do seu sistema atualizará para a versão mais recente. A forma mais fácil de verificar a versão do Git é o comandogit --versionno terminal. Em meados de 2026, o ramo atual é o 2.48+. Se estiver no Windows e o Git tiver sido instalado há muito tempo, transfira um instalador novo de git-scm.com; a atualização automática em versões antigas funcionava de forma instável.
Posso usar a flag diretamente com o git push?
Não, o
git pushnão aceita--allow-unrelated-histories. O push não cria um merge, apenas envia commits existentes. O erro "unrelated histories" no push significa que o seu ramo local e o remoto divergiram ao nível do histórico. Solução: primeirogit pull --allow-unrelated-histories, resolva os conflitos e só depoisgit push. Formalmente, o--allow-unrelated-historiesfunciona comgit fetch+git mergee comgit pull(que internamente faz fetch + merge). O push continua a ser uma operação separada que se realiza após um merge bem-sucedido. Não tente contornar isto com--force; perderá os commits de outras pessoas no repositório remoto.
O que é melhor para um histórico limpo: merge ou rebase?
Para ligar históricos não relacionados, definitivamente o
merge. O rebase neste contexto cria mais problemas do que resolve: tenta reaplicar commits de um ramo em cima de outro, mas, sem um ancestral comum, isto leva a conflitos em cada commit. O merge com--allow-unrelated-historiesfaz exatamente o que é necessário: cria um ponto de ligação entre os dois grafos, após o qual o histórico fica unificado. Exceção: quando pretende intencionalmente reescrever o histórico e sabe exatamente o que está a fazer. Por exemplo, ao transferir código de um repositório para outro com limpeza de commits antigos. Neste caso,git rebase --allow-unrelated-historiespode fazer sentido, mas para o trabalho diário escolha o merge.
Perdi a pasta .git, mas tenho alterações não commitadas. Vou perdê-las?
Não, não as perderá. A pasta
.gitem si contém apenas o histórico e os metadados do Git, não os seus ficheiros de trabalho. Todos os ficheiros modificados, novos e até mesmo não commitados permanecerão intactos no diretório de trabalho. O procedimento de recuperação está descrito na "Situação 2" acima:git init→git remote add→git fetch→git reset --mixed. Ponto-chave: use exatamente--mixed, não--hard. A flag--mixedrepõe o índice, mas preserva todas as alterações nos ficheiros. Se não tiver a certeza, faça uma cópia de segurança de toda a pasta do projeto antes da recuperação; isto demorará dez segundos e eliminará completamente o risco de perda de dados em qualquer situação atípica.
O erro ocorre ao clonar através de um IDE. É o mesmo problema?
Sim, exatamente o mesmo. Alguns IDEs (por exemplo, PHPStorm, Visual Studio, versões mais antigas do IntelliJ), ao criar um projeto a partir de um modelo, inicializam um novo repositório Git e depois tentam ligar um remoto. Este é exatamente o segundo cenário do início do artigo. A solução é a mesma: abra um terminal na pasta do projeto e execute
git pull origin main --allow-unrelated-histories. Após o merge manual, o IDE detetará o novo estado automaticamente; basta atualizar a janela do projeto ou clicar em Refresh no painel do Git.
Deve temer o erro "unrelated histories"?
Não. Este é um dos erros mais seguros do Git: não corrompe dados, não elimina ficheiros e não impede a continuação do trabalho. A flag --allow-unrelated-histories não é uma muleta ou uma solução de recurso, mas uma funcionalidade documentada, adicionada especificamente pelos programadores do Git para os casos em que se pretende conscientemente ligar dois históricos independentes.
Ao dominar este comando, ganha uma ferramenta poderosa: agora pode fundir projetos com qualquer grau de isolamento, transferir código entre repositórios e restaurar o trabalho após perder a .git, e tudo isto sem pânico e sem recriar o repositório de raiz. Se o Git lhe ensinou algo hoje, foi que "fatal" nas suas mensagens não significa "fatal para o projeto", significa "não vou adivinhar, diga-me explicitamente o que fazer".



