Reflog: o histórico de tudo que aconteceu localmente
1. O que é o Reflog e por que ele existe?
O Git mantém dois tipos de histórico: o histórico de commits, que é compartilhado com outros desenvolvedores via push e pull, e o reflog (reference log), que registra todas as ações locais que movem os ponteiros de referência do seu repositório. Enquanto o histórico de commits mostra apenas o estado dos commits em si, o reflog documenta cada operação que alterou onde HEAD ou um branch apontava.
O reflog registra ações como:
- Commits normais
- git reset (qualquer modo: --soft, --mixed, --hard)
- git checkout que move HEAD
- git merge e git rebase
- git commit --amend
- Criação e exclusão de branches
Uma característica fundamental: o reflog é exclusivamente local. Quando você executa git push, o reflog não é enviado para o repositório remoto. Isso significa que o reflog é seu diário pessoal de operações Git, visível apenas no seu clone do repositório.
2. Como visualizar o reflog
O comando básico para acessar o reflog é:
git reflog
A saída padrão mostra uma lista cronológica reversa (mais recente primeiro) com entradas como:
abc1234 HEAD@{0}: commit: Corrige bug no cálculo de juros
def5678 HEAD@{1}: rebase (finish): refatorando módulo de pagamentos
789abcd HEAD@{2}: reset: movendo para antes do merge problemático
123def4 HEAD@{3}: commit: Adiciona testes unitários
Opções úteis incluem:
git reflog --all # Mostra reflog de todas as referências
git reflog --date=iso # Exibe datas no formato ISO
git reflog --relative-date # Mostra datas relativas (ex: "2 horas atrás")
A diferença entre git reflog e git log -g é sutil: git log -g mostra o mesmo conteúdo do reflog, mas com formatação de log (autor, data completa, mensagem), enquanto git reflog foca nas referências e ações.
3. Navegando pelo reflog com referências
Cada entrada no reflog pode ser referenciada usando a sintaxe HEAD@{n} ou <nome-do-branch>@{n}. O número n indica a posição da entrada: HEAD@{0} é o estado mais recente, HEAD@{1} é o anterior, e assim por diante.
Você pode usar essas referências em qualquer comando Git que aceite uma revisão:
git show HEAD@{2} # Mostra o commit apontado por HEAD há 2 ações atrás
git diff HEAD@{1} HEAD@{0} # Compara o estado atual com o anterior
git checkout HEAD@{3} # Move HEAD para o estado de 3 ações atrás (detached HEAD)
Importante: entradas do reflog expiram. Por padrão:
- Commits alcançáveis expiram em 90 dias
- Commits não alcançáveis (órfãos) expiram em 30 dias
- Outras referências (como reflog de branches) seguem regras similares
4. Recuperando commits "perdidos" com o reflog
O caso de uso mais valioso do reflog é recuperar trabalho que parecia perdido. Considere este cenário: você executou git reset --hard HEAD~3 e percebeu que descartou commits importantes.
O reflog ainda mantém o registro:
git reflog
# Saída:
# abc1234 HEAD@{0}: reset: movendo para HEAD~3
# def5678 HEAD@{1}: commit: Implementa feature X
# 789abcd HEAD@{2}: commit: Adiciona validação de dados
Para recuperar o commit def5678:
git checkout def5678 # Vai para o commit em detached HEAD
# ou
git cherry-pick def5678 # Aplica o commit no branch atual
# ou
git branch feature-recuperada def5678 # Cria um branch apontando para o commit
Para recriar um branch apagado acidentalmente:
git branch meu-branch HEAD@{5}
Isso cria um branch chamado meu-branch apontando para onde HEAD estava há 5 ações atrás.
5. Reflog de branches específicos vs. HEAD
O comando git reflog sem argumentos mostra o reflog de HEAD. Mas cada branch tem seu próprio reflog:
git reflog main # Mostra o histórico do branch main
git reflog develop # Mostra o histórico do branch develop
O reflog de um branch é atualizado apenas quando a ponta do branch se move. Já o reflog de HEAD é atualizado sempre que HEAD muda, incluindo checkouts entre branches.
Exemplo prático:
# Início: no branch main
git checkout -b experimento
# HEAD@{0}: checkout: movendo para experimento
# experimento@{0}: branch: Criado a partir de main
git commit -m "Feature experimental"
# HEAD@{1}: commit: Feature experimental
# experimento@{1}: commit: Feature experimental
git checkout main
# HEAD@{2}: checkout: movendo para main
# (experimento não é atualizado)
6. Boas práticas e limitações do reflog
Quando confiar no reflog:
- Para recuperação de commits perdidos localmente
- Para entender o que aconteceu em uma sessão de trabalho
- Para desfazer operações recentes
Limitações importantes:
- O reflog nunca é enviado para repositórios remotos
- Ele não salva alterações não rastreadas (untracked files)
- Stashes perdidos não aparecem no reflog (use git stash list)
- Entradas expiram automaticamente
Gerenciando o reflog:
# Limpar entradas expiradas manualmente
git reflog expire --expire=now --all
# Remover entradas específicas
git reflog delete HEAD@{5}
# Configurar tempo de expiração
git config gc.reflogExpire 180.days
git config gc.reflogExpireUnreachable 60.days
7. Casos de uso avançados e armadilhas comuns
Desfazendo um git commit --amend:
git commit --amend -m "Mensagem corrigida"
# Oops! Quero a mensagem original
git reflog
# HEAD@{1}: commit (amend): Mensagem corrigida
# HEAD@{2}: commit: Mensagem original
git reset HEAD@{2} # ou git cherry-pick HEAD@{2}
Recuperando de um rebase interativo problemático:
git rebase -i HEAD~5
# Durante o rebase, algo deu errado
git rebase --abort
# Mas você quer o estado de antes do abort
git reflog
# HEAD@{3}: rebase: parando em commit X
git checkout HEAD@{3}
Armadilha comum: o reflog não substitui backups. Se você clonar um repositório novo, o reflog começa vazio. Além disso, o git gc (coleta de lixo) remove entradas expiradas, então confiar apenas no reflog para recuperação a longo prazo é arriscado.
Para objetos órfãos que não estão mais no reflog, use git fsck --lost-found, que varre o banco de objetos do Git em busca de commits sem referência.
Referências
- Documentação oficial do Git - git-reflog — Referência completa do comando reflog, com todas as opções e exemplos
- Pro Git Book - Capítulo 10: Reflog — Explicação detalhada sobre como o reflog funciona internamente no Git
- Atlassian Git Tutorial: Reflog — Guia prático com exemplos de recuperação de commits perdidos
- Git Reflog: How to Undo Almost Anything — Tutorial do freeCodeCamp mostrando cenários reais de uso do reflog
- Git Tips: Recovering Lost Commits with Reflog — Post do GitHub Engineering Blog sobre técnicas avançadas de recuperação com reflog