--:--:--

Git push rejected non-fast-forward: como integrar o remoto sem perder commits

Publicado em 2026-08-29T20:14:00Z · atualizado em 2026-08-29T19:14:27+00:00

O erro **rejected non-fast-forward** aparece quando o Git se recusa a mover uma branch remota para o seu commit porque esse movimento descartaria commits que já existem no servidor. Em geral, outra pessoa enviou mudanças depois do seu últim

Históricos local e remoto divergindo a partir de um commit comum
Imagem de apoio ao tema do artigo.

Git push rejected non-fast-forward: como integrar o remoto sem perder commits

O erro rejected non-fast-forward aparece quando o Git se recusa a mover uma branch remota para o seu commit porque esse movimento descartaria commits que já existem no servidor. Em geral, outra pessoa enviou mudanças depois do seu último fetch, ou a branch remota foi atualizada por automação. A rejeição é uma proteção, não corrupção do repositório.

A saída segura é preservar o estado local, atualizar a visão do remoto, comparar os históricos e escolher conscientemente entre rebase e merge. git push --force não deve ser o primeiro reflexo: ele pode remover trabalho compartilhado. Este guia usa um laboratório local com dois clones, mostra como recuperar conflitos e explica quando --force-with-lease é apropriado.

Históricos local e remoto divergindo a partir de um commit comum Legenda: o push comum só avança a referência remota quando o commit atual contém o histórico já publicado.

Leia a rejeição completa

Uma mensagem típica é:

! [rejected] main -> main (non-fast-forward)
error: failed to push some refs
hint: Updates were rejected because the tip of your current branch is behind

Confirme qual origem, branch local e branch remota estão envolvidas:

git status -sb
git remote -v
git branch -vv
git rev-parse --show-toplevel

Não execute comandos de integração antes de verificar se está no repositório certo. Projetos com vários remotos podem usar origin para um fork e upstream para o repositório principal. A mensagem também pode ser causada por proteção de branch ou hook; nesses casos, o servidor costuma apresentar uma explicação adicional.

O que fast-forward significa

Imagine que o remoto aponta para B e seu commit C é descendente direto:

A---B---C
    remoto local

Mover o remoto de B para C preserva todos os commits e é fast-forward. Agora considere histórias divergentes:

      C  local
     /
A---B
     \
      D  remoto

Atualizar o remoto diretamente para C esconderia D. Por padrão, o Git rejeita. Você precisa construir um histórico que contenha ambos, por merge ou rebase, ou deliberadamente substituir a história remota quando a política permite.

Crie um laboratório com dois clones

O experimento abaixo usa apenas pastas descartáveis e um repositório bare:

mkdir laboratorio-git && cd laboratorio-git
git init --bare remoto.git
git clone remoto.git ana
git clone remoto.git bruno

No primeiro clone:

cd ana
git switch -c main
printf "linha inicial\n" > notas.txt
git add notas.txt
git commit -m "Adiciona notas"
git push -u origin main

No segundo clone, atualize a referência e crie outra mudança:

cd ../bruno
git fetch origin
git switch -c main --track origin/main
printf "mudança remota\n" >> notas.txt
git commit -am "Atualiza pelo clone Bruno"
git push

Volte ao primeiro clone, crie um commit sem buscar e tente enviar:

cd ../ana
printf "mudança local\n" >> local.txt
git add local.txt
git commit -m "Adiciona arquivo local"
git push

A rejeição agora é reproduzível e nenhuma conta externa foi usada.

Faça um ponto de segurança antes de integrar

Se há arquivos não commitados, o rebase ou merge pode ser interrompido. Veja o estado:

git status
git diff
git diff --staged

O melhor ponto de segurança é um commit coerente na sua branch. Se o trabalho ainda não pode virar commit, use uma branch temporária ou stash identificado:

git switch -c seguranca/antes-da-integracao
git add -A
git commit -m "WIP: preserva estado antes da integração"

Depois volte à branch original, se necessário. Branches e commits são mais fáceis de inspecionar que um stash anônimo. Não inclua segredos só para criar o ponto de segurança; remova-os do índice e trate a exposição se já foram commitados.

Atualize o remoto com git fetch

git fetch origin baixa objetos e atualiza referências de rastreamento como origin/main, sem alterar seus arquivos de trabalho:

git fetch origin
git status -sb
git log --oneline --graph --decorate --all -n 20

Compare o que existe apenas em cada lado:

git log --oneline HEAD..origin/main
git log --oneline origin/main..HEAD
git diff --stat HEAD...origin/main

O primeiro comando lista commits remotos ausentes localmente; o segundo lista commits locais não publicados. O operador de três pontos no diff compara a partir do ancestral comum, útil para entender a divergência. A ferramenta de comparação de texto pode ajudar com trechos pequenos, mas não substitui o grafo do Git.

Opção 1: rebase para uma história linear

O rebase reaplica seus commits locais sobre o topo remoto:

git rebase origin/main

O resultado conceitual é:

A---B---D---C'

C' contém a mesma intenção de C, mas é um novo commit com outro identificador. Se os commits locais ainda não foram compartilhados, isso costuma produzir um histórico simples. Depois:

git push origin main

Não faça rebase de commits que outras pessoas já usam sem combinar a mudança. Reescrever história publicada obriga os demais clones a reconciliar referências diferentes.

Resolva conflitos durante o rebase

Quando as duas linhas alteram a mesma região, o Git pausa:

git status
git diff --name-only --diff-filter=U

Abra cada arquivo, entenda as duas intenções e remova os marcadores <<<<<<<, ======= e >>>>>>>. Depois teste e continue:

git add caminho/do/arquivo
git rebase --continue

Se perceber que escolheu a estratégia errada:

git rebase --abort

Não use git checkout --ours ou --theirs automaticamente sem entender que, durante rebase, os nomes podem parecer invertidos em relação à intuição. Revise o conteúdo final, execute testes e veja git diff --check para detectar marcadores ou espaços problemáticos.

Opção 2: merge para preservar as linhas de trabalho

O merge cria um commit que conecta os dois históricos:

git merge origin/main

Se houver conflito, edite os arquivos, adicione as resoluções e finalize:

git add -A
git commit
git push origin main

O histórico registra explicitamente que dois ramos existiram. Isso pode ser desejável em branches compartilhadas ou quando a equipe evita reescrever commits locais. Se quiser cancelar antes do commit:

git merge --abort

Merge não é inferior a rebase; representa outra política de histórico. O importante é que o novo topo seja descendente do topo remoto e preserve ambas as mudanças.

Escolha entre pull --rebase e pull --no-rebase

git pull combina fetch com uma integração. Para diagnóstico, separar as etapas deixa o processo mais claro. Depois que a equipe define uma política, você pode usar:

git pull --rebase origin main

ou:

git pull --no-rebase origin main

git pull --ff-only aceita somente atualização sem divergência e falha quando um merge ou rebase seria necessário. É uma opção conservadora para evitar integração implícita. Configure a preferência no repositório, não globalmente por acidente:

git config pull.rebase true

Documente a escolha no guia de contribuição. Misturar políticas sem acordo gera ruído e conflitos desnecessários.

Quando force-with-lease é aceitável

Após um rebase de uma branch que você publicou intencionalmente, o push comum pode ser rejeitado porque os identificadores mudaram. Se a política permite reescrever essa branch e você verificou que ninguém publicou algo novo, prefira:

git push --force-with-lease origin minha-branch

O lease compara a referência remota com a expectativa local e recusa a substituição se ela mudou desde seu último conhecimento. Ainda assim, faça git fetch e leia o grafo imediatamente antes. Não use em main ou branch compartilhada sem autorização. --force-with-lease reduz risco; não torna a reescrita inofensiva.

O --force puro ignora essa proteção. Reservá-lo a manutenção controlada evita apagar commits de terceiros.

Árvore de decisão entre fetch, rebase, merge e force-with-lease Legenda: integrar é o padrão; reescrever só é opção em branch autorizada e após verificar o estado remoto.

Branch protegida e pull request

Alguns servidores recusam push direto mesmo quando seria fast-forward. A mensagem pode mencionar protected branch, required checks ou permission denied. Nesse fluxo, envie sua branch:

git switch -c correcao/minha-alteracao
git push -u origin correcao/minha-alteracao

Abra um pull request e aguarde revisão e verificações. Não tente contornar a proteção mudando o remoto ou usando credencial de outra pessoa. A restrição existe para manter testes, auditoria e aprovação.

Se o nome da branch padrão mudou de master para main, confira git remote show origin e atualize a referência. Um push para a branch errada pode parecer problema de sincronização quando é apenas destino incorreto.

E se o remoto foi reescrito por outra pessoa

Depois de fetch, você pode perceber que origin/main não é descendente da referência anterior. Antes de fazer qualquer coisa, capture o grafo e comunique a equipe. Use o reflog para localizar sua visão anterior:

git reflog show origin/main -n 10
git log --graph --oneline --decorate --all -n 30

Não force a branch de volta por conta própria. A reescrita pode ter removido um segredo, revertido uma publicação indevida ou aplicado uma correção coordenada. Crie uma branch apontando para commits que precisa preservar:

git branch recuperacao/meus-commits <hash>

Depois, replique os commits necessários com rebase ou cherry-pick conforme decisão da equipe.

Recupere um commit que parece ter sumido

Commits locais normalmente continuam no banco de objetos por algum tempo, mesmo após reset ou rebase. O reflog registra movimentos das referências locais:

git reflog --date=local
git show <hash>
git branch recuperacao/commit <hash>

Crie a branch antes de continuar experimentos. A ferramenta de hash ajuda a explicar identificadores, mas não acessa objetos do seu repositório. O comando git show é a fonte correta para conteúdo e metadados do commit.

Evite executar limpeza agressiva enquanto procura o trabalho. Não apague a pasta .git; ela contém o histórico e o reflog usados na recuperação.

Automatize uma verificação antes do push

Em CI ou script local, atualize a referência e teste ancestralidade:

git fetch origin main
if git merge-base --is-ancestor origin/main HEAD; then
  echo "push pode avançar origin/main"
else
  echo "histórico divergiu; integre antes de enviar"
  exit 1
fi

O teste não resolve conflitos nem decide a política, mas transforma uma surpresa tardia em diagnóstico claro. Hooks locais não devem ser a única proteção porque podem ser ignorados; combine com regras no servidor.

Para equipes, também vale exibir branch, ahead e behind no prompt ou IDE. A informação reduz pushes feitos a partir de um estado antigo.

Erros comuns que pioram a situação

Evite estas respostas automáticas:

  • executar git push --force sem buscar o remoto;
  • usar git reset --hard origin/main e apagar mudanças locais sem backup;
  • fazer rebase de uma branch compartilhada sem avisar;
  • resolver todos os conflitos escolhendo sempre um lado;
  • apagar .git e clonar novamente antes de preservar commits locais;
  • misturar origin/main, upstream/main e a branch local.

Se um tutorial sugere comando destrutivo, primeiro entenda quais referências serão movidas. Use git status, git log --graph e uma branch de segurança. Para praticar comandos, a biblioteca Git do IATechNerds pode complementar este laboratório.

Checklist antes do novo push

Confirme que:

  1. O trabalho local está commitado ou preservado em branch.
  2. git fetch foi executado no remoto correto.
  3. O grafo mostra claramente os commits exclusivos de cada lado.
  4. Rebase ou merge segue a política da equipe.
  5. Conflitos foram resolvidos por intenção, não por escolha automática.
  6. Testes e git diff --check passaram.
  7. --force-with-lease só será usado em branch autorizada.
  8. O novo topo contém tudo que deve permanecer publicado.

Após o push, confira a saída e a interface do servidor. O objetivo não é apenas remover a mensagem de erro, mas preservar a história correta.

Em uma revisão final, abra o conjunto de commits que será incorporado e confirme autoria, mensagens e arquivos modificados. Um histórico tecnicamente integrável ainda pode conter artefatos locais, credenciais, arquivos gerados ou alterações fora do escopo. Compare a branch contra a base com git diff origin/main...HEAD e use a suíte do projeto. Se o push continuar rejeitado após a integração, leia a nova mensagem: a referência pode ter avançado novamente enquanto você trabalhava. Nesse caso, faça outro fetch e repita a comparação, sem recorrer imediatamente a força. Em equipes movimentadas, branches curtas e pull requests pequenos diminuem a janela de divergência. A rejeição deixa de ser um obstáculo misterioso e passa a ser um sinal de sincronização que protege o repositório.

Documentação primária

Autoria, revisão e método de produção

Autoria editorial: Equipe IATechNerds. Revisão técnica e editorial: pendente, obrigatória antes da publicação. O texto foi produzido com apoio de IA generativa, consulta à documentação oficial do Git e laboratório fictício reproduzível com repositório bare e dois clones. Nenhum comando foi executado em repositório do leitor. A política de branches, exemplos e links internos precisam de validação humana antes da publicação.

Camada extra: como tomar uma decisão melhor neste cenário

Em uso real, Git push rejected non-fast-forward: como integrar o remoto sem perder commits costuma envolver mais de uma camada. O ganho de qualidade aparece quando cada camada tem uma pergunta de verificação antes de qualquer mudança definitiva.

O erro **rejected non-fast-forward** aparece quando o Git se recusa a mover uma branch remota para o seu commit porque esse movimento descartaria commits que já existem no servidor. Em geral, outra pessoa enviou mudanças depois do seu últim A ideia central pode ser testada com quatro perguntas: o que foi observado, qual hipótese explica o sintoma, qual mudança é reversível e qual evidência prova que funcionou. Esse encadeamento evita que uma coincidência seja confundida com causa e torna o procedimento repetível por outra pessoa.

Qualidade de IA precisa de um teste, não de uma impressão

Para Git, non-fast-forward, rebase, merge, escolha três tarefas representativas: uma simples, uma ambígua e uma em que a resposta possa ser conferida em fonte primária. Compare utilidade, rastreabilidade, privacidade, velocidade e quantidade de correção humana necessária. Uma resposta elegante não compensa uma citação inexistente ou uma conclusão que não pode ser reproduzida.

Separe ainda o que pode sair do dispositivo do que deve permanecer local. Dados públicos toleram fluxos diferentes de documentos internos, contratos, informações pessoais ou bases de clientes. A escolha entre processamento local e nuvem deve ser feita pelo risco do conteúdo, não apenas pela conveniência da interface.

Grade de avaliação prática

CritérioPerguntaEvidência
CorreçãoA resposta bate com a fonte?Checagem independente
RastreabilidadeÉ possível localizar de onde veio?Citação ou trecho verificável
PrivacidadeQue dado sai do dispositivo?Política e configuração
EsforçoQuanto trabalho humano resta?Tempo de revisão

O ponto em que a IA deixa de ajudar

Se a tarefa exige precisão absoluta e a saída não pode ser validada, a automação deve ser limitada a apoio: localizar trechos, organizar opções ou preparar uma primeira versão. A decisão final precisa permanecer com alguém capaz de verificar a fonte e assumir a responsabilidade pelo resultado.

Checklist de fechamento

  • Registre o estado inicial antes de alterar qualquer coisa.
  • Faça uma mudança por rodada e anote o efeito.
  • Teste um caso normal, um caso-limite e o cenário que originalmente falhou.
  • Confirme que a solução continua válida depois de reiniciar, reabrir ou repetir o fluxo.
  • Guarde uma forma de voltar ao estado anterior quando a alteração for destrutiva.

Esse método acrescenta profundidade sem transformar o artigo em teoria abstrata: o leitor entende por que cada passo existe e como reconhecer quando a situação exige uma decisão diferente.

#Git #non-fast-forward #rebase #merge #versionamento