TL;DR: o git revert cria um novo commit que desfaz um antigo — o histórico é preservado, seguro em branches que outras pessoas já puxaram. O git reset move o ponteiro da branch para trás — o histórico é reescrito, só seguro em commits que você ainda não fez push. Use revert em branches compartilhadas, reset em limpeza local. O reset --hard também apaga mudanças não commitadas do working tree; é ele que come trabalho de verdade.
Qual a diferença entre git revert e git reset?
Os dois fazem seu projeto parecer que um commit do passado nunca aconteceu. Eles discordam sobre como:
git revert <sha>calcula o patch inverso de um commit e o commita. Seu histórico cresce um commit que diz “desfaça aquele”. O commit ruim continua no log, seguido do seu cancelamento. Os SHAs de todo o resto ficam intactos.git reset <sha>move o ponteiro da branch atual para<sha>. Os commits depois dele ficam soltos — ainda na base de objetos até a garbage collection, mas inalcançáveis por qualquer branch ougit log.
Uma não reescreve nada; a outra finge que nada aconteceu. Essa única propriedade decide qual cada situação pede:
# Demo: um repositório descartável e executável
git init /tmp/revert-vs-reset && cd /tmp/revert-vs-reset
echo one > file.txt && git add . && git commit -m "one"
echo two > file.txt && git add . && git commit -m "two"
# Revert: o histórico mantém os dois commits, mais um terceiro que desfaz o "two"
git revert --no-edit HEAD
git log --oneline # 3 commits: revert, two, one
# Reset: o ponteiro da branch volta, e o "two" some do log
git reset --hard HEAD~1
git log --oneline # 1 commit: one Rode os dois e olhe o git log — a assimetria é a resposta inteira.
O que git reset —soft, —mixed e —hard fazem de fato?
Os três modos controlam onde suas mudanças sobrevivem depois que o ponteiro anda:
| Modo | Ponteiro da branch | Staging area | Working tree | Suas edições |
|---|---|---|---|---|
--soft | volta | mantém staged | intocado | mantidas por inteiro |
--mixed (padrão) | volta | unstaged | intocado | mantidas, unstaged |
--hard | volta | resetada | resetada | apagadas |
Leituras concretas dessa tabela:
git reset --soft HEAD~1— “comitei cedo demais.” Tudo volta para staged, pronto para recommittar, talvez junto com mais trabalho.git reset HEAD~1(mixed) — “staged os arquivos errados.” As edições sobrevivem no working tree, nada fica staged. Combine com remover arquivos untracked do git quando também quiser os arquivos perdidos fora.git reset --hard HEAD~1— “esse commit e minhas edições não commitadas são lixo.” O git não pergunta duas vezes; não há undo para a parte do working tree a menos que você tenha stashado ou commitado antes.
O revert não tem modos porque nunca destrói nada — ele só adiciona um commit compensatório.
Quando usar git revert em vez de git reset?
Faça uma pergunta: outra pessoa já puxou esse commit? Se sim, reset está fora de questão.
Resetar uma branch na qual outros basearam trabalho reescreve o histórico compartilhado. O próximo pull deles encontra branches divergentes, e o “conserto” costuma ser um force-push que transforma o seu erro em problema de todo mundo. O revert anexa um commit normal, então um git pull simples faz merge limpo para todos — por isso revert é a resposta padrão na main e nos pull requests do GitHub, onde o botão “Revert” existe justamente porque reescrever o histórico de um PR mergeado não é opção.
O reset é para a janela antes de compartilhar: o commit feito trinta segundos atrás, o erro de staging, a branch de experimento local. Se a única cópia do trabalho está na sua máquina, você pode rearranjar o histórico à vontade — esse é todo o propósito da janela pré-push.
Há um caso intermediário: você fez push para a sua própria feature branch e ninguém mais constrói sobre ela. Um force-push depois do reset é socialmente aceitável ali, mas o revert ainda custa menos coordenação. Reserve force-pushes para branches que são suas e de mais ninguém.
O git revert é mais seguro que o git reset em branches compartilhadas?
Sim, estruturalmente — não só por convenção:
- O revert produz um commit comum; o CI roda nele, o diff é revisável, e o
git logexplica para o você-do-futuro por que a mudança sumiu. - O reset descarta o estado intermediário em silêncio. Ninguém revisando depois consegue ver o que foi desfeito ou quando, porque o log mostra uma linha reta que nunca o contém.
Duas arestas práticas:
- Reverter um merge commit pede
git revert -m 1 <sha>(manter a linha do primeiro pai). Sem o-m, o git recusa e te deixa lendo o erro. - Revert não é máquina do tempo: ele desfaz o diff de um commit. Se commits posteriores mexeram nas mesmas linhas, você pode resolver conflitos — é o git te dizendo que o undo está enroscado, o que é informação útil, não defeito.
Para desfazer especificamente o seu último commit — mantendo ou descartando as mudanças — as opções estão em git undo last commit: mantenha as mudanças.
E o git restore, onde ele entra?
O git restore (e o git switch, seu par) chegaram no git 2.23 para assumir os trabalhos que o reset fazia mal por sobrecarga de nome:
| Tarefa | Jeito antigo | Jeito claro |
|---|---|---|
| Descartar edições do working tree em um arquivo | git checkout -- file / git reset --hard | git restore file |
| Tirar um arquivo da staging area | git reset HEAD file | git restore --staged file |
| Mover uma branch para outro commit | git reset <sha> | git reset <sha> (sem substituto — esse fica) |
Então a divisão moderna é: restore conserta arquivos, reset move branches, revert desfaz commits publicados. O autocomplete mostra que as pessoas pesquisam “git revert vs reset vs restore” juntas com razão — são um modelo mental dividido em três comandos. As formas antigas do git checkout funcionam em todo lugar; as novas apenas te impedem de mandar uma branch inteira para o triturador quando você só queria unstagar um arquivo.
Se o objetivo é copiar um commit bom para frente em vez de apagar um ruim, esse é o trabalho do cherry-pick — veja git cherry-pick: múltiplos commits, branches e conflitos.
Recap rápido de decisão
- Commit público (push feito, outras pessoas já puxaram) →
git revert <sha>. - Commit só local, quer refazê-lo →
git reset --softou--mixede commitar de novo. - Só local, quer fora junto com a bagunça não commitada →
git reset --hard, depois de uma olhada honesta no que mais o working tree guarda. - Um arquivo foi estragado →
git restore <file>e deixe a branch em paz.
A única entrada genuinamente perigosa da lista é o --hard — todo o resto se recupera conversando com o git reflog. As perdas permanentes no git são estreitas e quase sempre exigem que você digite o comando explicitamente; o hábito que vale construir é pausar meio segundo antes do --hard, não evitar as ferramentas afiadas do git.
— mrsaynothing
Get the next one by email
One email per post. No spam, no algorithms.
what is this?Serviço systemd não inicia? Como resolver
Gostou dos artigos? É assim que eu construo profissionalmente. me contrate