W3docs

Introdução

Aprenda como o Git reescreve o histórico com git commit --amend, git reflog e git rebase — o que cada comando faz, quando usá-lo e como trabalhar com segurança.

No Git, o histórico é a sequência de commits que registra como o seu projeto mudou ao longo do tempo. Cada commit é identificado por um hash único e aponta para o commit (ou commits) que veio antes dele. Na maior parte do tempo, você apenas adiciona a essa cadeia. Mas às vezes é necessário alterar o que já está lá — corrigir um erro de digitação em uma mensagem de commit, unir vários commits bagunçados em um único commit limpo, ou recuperar um trabalho que você achou que havia perdido.

É para isso que servem as ferramentas de reescrita de histórico do Git. As três que você usará com mais frequência são:

  • git commit --amend — substitui o commit mais recente.
  • git reflog — exibe cada posição para a qual o HEAD apontou, permitindo recuperar commits "perdidos".
  • git rebase — reproduz uma série de commits sobre uma nova base, opcionalmente editando-os ao longo do processo.

Esta página oferece uma visão geral funcional de cada um. Os capítulos mais detalhados vinculados acima percorrem o conjunto completo de opções.

A regra de ouro da reescrita de histórico: nunca reescreva commits que você já enviou para um branch compartilhado. Reescrever altera os hashes dos commits, portanto qualquer pessoa que tenha obtido os commits antigos terá conflitos. Reescreva livremente em seus próprios branches locais; deixe o histórico compartilhado intocado.

Alterando o último commit com git commit --amend

É fácil esquecer de adicionar um arquivo ao stage, deixar um erro de digitação em uma mensagem de commit ou fazer um commit cedo demais. Em vez de adicionar um commit de "correção" separado, o git commit --amend permite substituir o último commit por um corrigido.

Para corrigir apenas a mensagem do commit mais recente:

git commit --amend -m "Add login validation"

Para adicionar um arquivo esquecido ao último commit, coloque-o no stage primeiro e, em seguida, faça o amend sem alterar a mensagem:

git add forgotten-file.js
git commit --amend --no-edit

A flag --no-edit mantém a mensagem existente e a reutiliza. Por baixo dos panos, o amend não edita o commit antigo diretamente — ele cria um commit totalmente novo (com um novo hash) e move o branch para apontá-lo. O commit original é deixado para trás, sem referência.

Como o amend produz um novo hash, a mesma regra de ouro se aplica: só faça amend em um commit que você não enviou para um branch compartilhado com outras pessoas.

Para um guia completo, consulte git commit --amend.

Recuperando commits perdidos com git reflog

O reflog (log de referências) registra cada alteração no topo de seus branches e no HEAD — cada commit, checkout, reset, merge e rebase. Este é o seu recurso de segurança: mesmo após uma reescrita ou um reset --hard, os commits antigos ainda estão no repositório e o reflog lembra onde eles estavam.

Visualize o log com:

git reflog

Uma saída típica tem a seguinte aparência:

a1b2c3d HEAD@{0}: commit: Add login validation
9f8e7d6 HEAD@{1}: reset: moving to HEAD~1
4c3b2a1 HEAD@{2}: commit: Work in progress

Cada entrada mostra um hash de commit, uma referência HEAD@{n} (quantos movimentos atrás) e o que aconteceu. Se você redefiniu acidentalmente um commit, encontre-o no reflog e traga-o de volta:

git reset --hard HEAD@{2}

O comando git reflog também possui subcomandos como git reflog show, git reflog expire e git reflog delete. Note que as entradas do reflog são locais ao seu repositório e expiram com o tempo (90 dias por padrão para entradas acessíveis), portanto são uma ferramenta de recuperação, não um backup permanente. Consulte git reflog e o capítulo relacionado de git reset para mais detalhes.

Fazendo rebase em uma nova base com git rebase

O git rebase pega uma série de commits e os reproduz no topo de um commit base diferente. Seu principal benefício é um histórico linear e legível: em vez de um commit de merge unindo dois branches, o seu trabalho aparece como uma linha limpa de commits.

Existem dois modos:

  • Modo padrão aplica os commits do seu branch atual no topo do último commit de outro branch. Esta é a alternativa ao merge ao integrar atualizações do main:
git rebase main
  • Modo interativo permite reordenar, editar, combinar ou descartar commits conforme são reproduzidos. Adicione a opção -i e passe o commit sobre o qual deseja fazer o rebase:
git rebase -i <base-branch>

Um alvo interativo comum é "os últimos N commits", por exemplo os últimos três:

git rebase -i HEAD~3

Para um tratamento mais completo, consulte git rebase e git rebase interactive.

Editando commits durante um rebase interativo

Quando você inicia um rebase interativo, o Git abre um editor listando os commits selecionados, cada um prefixado com uma ação. Você altera a palavra-chave da ação para controlar o que acontece:

  • pick — mantém o commit como está (padrão).
  • reword (r) — pausa para reescrever a mensagem desse commit.
  • squash (s) — mescla este commit no anterior e combina suas mensagens em um editor.
  • fixup (f) — como squash, mas descarta a mensagem deste commit e mantém apenas a do anterior (sem prompt do editor).
  • edit (e) — pausa para que você possa fazer amend no conteúdo do commit.
  • drop (d) — remove o commit completamente.

Uma lista de tarefas típica de rebase tem a seguinte aparência:

pick a1b2c3d Add login form
squash 9f8e7d6 Fix typo in label
fixup 4c3b2a1 Adjust spacing

Aqui, o segundo e o terceiro commits são incorporados ao primeiro, resultando em um único commit organizado.

Por que commits reescritos recebem novos IDs

O rebase não move os commits originais — ele cria commits novos com as mesmas alterações, mas com pais diferentes e, portanto, hashes diferentes. Os commits antigos ficam sem referência (ainda recuperáveis pelo reflog por um tempo). Mesmo commits marcados com pick recebem novos IDs se qualquer commit anterior a eles na sequência foi alterado, porque o pai deles mudou.

Combinando commits durante um rebase interativo

É exatamente por isso que a regra de ouro importa: novos hashes significam um histórico divergente para qualquer pessoa que tinha os antigos.

Prática

Prática
Quais das afirmações a seguir são verdadeiras sobre os mecanismos de reescrita de histórico no Git?
Quais das afirmações a seguir são verdadeiras sobre os mecanismos de reescrita de histórico no Git?
Was this page helpful?