Se o commit já foi enviado para um branch compartilhado e outras pessoas podem ter baseado trabalho nele, a opção mais segura em geral é git revert. O comando não apaga o commit antigo: ele cria um novo commit que aplica o inverso das mudanças. Já git reset move o HEAD e, dependendo do modo, também altera o índice e a árvore de trabalho. Isso é útil para corrigir histórico local, mas pode causar perda de trabalho alheio quando o histórico já foi publicado e depois é reescrito.
Regra prática: histórico compartilhado pede revert
Pense primeiro em uma pergunta: o commit que você quer desfazer já está no remoto e pode ter sido visto, baixado ou usado por outra pessoa? Se a resposta for sim, prefira preservar o histórico. git revert <commit> cria um novo commit que neutraliza as alterações introduzidas pelo commit escolhido, sem mover para trás o ponteiro do branch.
Esse comportamento é especialmente importante em branches como main, master, develop ou qualquer branch de equipe. Quem já possui o commit original continua com um histórico compatível com o remoto. O novo commit de reversão aparece depois dele, deixando registrado o que aconteceu e quando a decisão foi tomada.
Quando git reset faz sentido
git reset é apropriado quando você controla o histórico que está alterando, principalmente antes de publicar os commits. Na forma que recebe um commit como alvo, o comando move o HEAD do branch atual para esse ponto. O efeito sobre o índice e os arquivos depende do modo escolhido.
| Comando | HEAD | Índice | Arquivos de trabalho | Uso típico |
|---|---|---|---|---|
| git reset --soft HEAD~1 | Volta um commit | Preserva | Preserva | Refazer o último commit mantendo tudo preparado para commit |
| git reset --mixed HEAD~1 | Volta um commit | Redefine | Preserva | Desfazer o commit e manter as alterações nos arquivos, fora do stage |
| git reset --hard HEAD~1 | Volta um commit | Redefine | Redefine | Descartar o commit e alterações rastreadas correspondentes, apenas quando isso for realmente desejado |
Sem indicar um modo, git reset usa o comportamento de --mixed. O ponto crítico é --hard: ele redefine índice e árvore de trabalho para o alvo e descarta mudanças em arquivos rastreados que não existam naquele estado. Por isso, não deve ser tratado como um simples botão de desfazer.
Exemplo seguro para um commit já publicado
Suponha que o commit problemático seja a1b2c3d e ele já esteja em um branch compartilhado. O fluxo mais previsível é atualizar sua visão do remoto, confirmar o commit e então criar a reversão:
git fetch origin git log --oneline --decorate -n 10 git revert a1b2c3d git push origin nome-do-branchSe a reversão gerar conflitos, o Git interrompe a operação para que eles sejam resolvidos. Depois de editar os arquivos e marcar as resoluções com git add, continue com git revert --continue. Se perceber que escolheu o commit errado ou não quer prosseguir, use git revert --abort para abandonar a operação de reversão em andamento.
Exemplo para corrigir o último commit ainda local
Se o commit ainda não foi publicado e você apenas quer refazê-lo sem perder as mudanças, --soft costuma ser a alternativa mais conservadora:
git reset --soft HEAD~1 git status # ajuste arquivos ou mensagem conforme necessário git commitAs mudanças permanecem preparadas no índice. Se você preferir que elas voltem para a árvore de trabalho sem ficar no stage, use git reset HEAD~1, equivalente ao modo --mixed nesse contexto.
Por que reset depois do push pode afetar outras pessoas
Depois de um reset que move o branch para trás, seu histórico local deixa de conter, naquela linha do branch, commits que ainda podem existir no remoto e nos clones de colegas. Um push comum tende a ser rejeitado porque não é um avanço direto. Forçar a atualização substitui a referência remota e pode tornar commits de outras pessoas inacessíveis pelo branch compartilhado.
A documentação do git push alerta que --force pode fazer o repositório remoto perder commits. --force-with-lease adiciona uma proteção: a atualização forçada falha se a referência remota não estiver no valor esperado. Mesmo assim, não transforma reescrita de histórico compartilhado em operação rotineira e há ressalvas quando ferramentas fazem fetch em segundo plano.
Se a reescrita for inevitável
Há equipes que permitem rebase, squash ou outra reescrita em branches de feature. Nesses casos, a segurança depende do acordo da equipe e de saber exatamente quem pode estar usando o branch. Antes de um push forçado, atualize as referências remotas, confirme o alvo e evite --force cego. Quando a política permitir reescrita, --force-with-lease é uma proteção melhor do que --force, mas não substitui coordenação.
Como recuperar um reset local feito por engano
Um reset que moveu o HEAD nem sempre significa que o commit ficou imediatamente irrecuperável. O reflog local registra movimentos de referências e pode ajudar a encontrar o identificador anterior:
git reflog git show <hash-encontrado>Depois de identificar o commit correto, você pode criar um branch temporário para preservá-lo antes de qualquer outra alteração:
git branch recuperacao <hash-encontrado>O reflog é local. Ele registra movimentos das referências naquele repositório específico, portanto não deve ser tratado como substituto de backup, revisão de comandos ou proteção do histórico remoto.
E se o commit a desfazer for um merge?
Reverter um merge exige informar qual pai deve ser considerado a linha principal com -m <parent-number>. Isso não deve ser escolhido por tentativa. Primeiro inspecione o merge e identifique corretamente a linha principal. Além disso, reverter um merge registra que as mudanças trazidas pelo merge não são desejadas, o que pode influenciar merges posteriores. Para esse caso, vale revisar o grafo e a intenção antes de executar o comando.
Checklist antes de desfazer um commit
- Confirme em qual branch você está com git status ou git branch --show-current.
- Atualize referências remotas com git fetch antes de decidir sobre histórico publicado.
- Verifique o hash e o conteúdo do commit com git show <hash>.
- Se o commit já foi compartilhado, prefira git revert.
- Se o commit é apenas local, escolha entre reset --soft, reset --mixed e reset --hard conforme o que deve acontecer com índice e arquivos.
- Evite reset --hard quando houver mudanças locais que você ainda precisa preservar.
- Não faça push forçado em branch compartilhado sem política e coordenação explícitas.
Em resumo
git revert e git reset desfazem problemas de maneiras diferentes. revert acrescenta um novo commit inverso e é a escolha padrão quando o histórico já é compartilhado. reset reposiciona o histórico local e é mais adequado antes da publicação, quando você controla os commits afetados. Para não apagar trabalho de outras pessoas, a decisão deve partir do estado do histórico, não apenas do resultado que você quer ver nos arquivos.





