git reset --soft HEAD~1 remove o commit e deixa todas as alterações na área de staging, exatamente como estavam um instante antes do commit. Essa é a resposta para o caso comum. Em qual caso você está importa mais do que a flag.
1. Ainda não fez push — desfazer o commit, manter o trabalho em staging
$ clai desfaça meu último commit mas mantenha as alterações em staging→ git reset --soft HEAD~1$ git status --shortM f.txt
O commit some do log, os arquivos ficam intocados, tudo continua no índice. Corrija a mensagem ou adicione o arquivo esquecido e faça o commit de novo.
2. Manter as alterações mas tirá-las do staging
$ clai desfaça o último commit e também tire as alterações do staging→ git reset HEAD~1
--mixed é o padrão. Igual ao soft, um passo além: os arquivos ficam no disco, o índice é limpo. Use quando quiser redividir o trabalho em commits diferentes.
3. Descartar o trabalho por completo
$ clai apague meu último commit e todas as suas alterações permanentemente→ git reset --hard HEAD~1⚠ DANGER — uncommitted changes in the working tree are destroyed
--hard é o único dos três que perde trabalho. Conteúdo commitado é recuperável via reflog; o que você tinha modificado mas não commitado, não.
4. Já fez push — revert em vez de reset
$ clai desfaça o commit que eu já fiz push, sem reescrever o histórico→ git revert HEAD
revert cria um commit novo que desfaz o antigo. O histórico permanece intacto, então ninguém que já deu pull precisa fazer nada. Numa branch compartilhada, essa é a única resposta correta.
5. Só corrigir a mensagem
$ clai mude a mensagem do meu último commit→ git commit --amend -m "Fix cache invalidation on write path"
Se nada estiver em staging, --amend reescreve só a mensagem. Se houver algo em staging, isso também é incorporado ao commit anterior — útil, mas fácil de fazer sem querer.
6. Escolheu errado — recupere
$ clai mostre onde estava o HEAD antes desse reset→ git reflog4d2e830 HEAD@{0}: reset: moving to HEAD~1dc4fa62 HEAD@{1}: commit: second4d2e830 HEAD@{2}: commit (initial): first$ git reset --hard dc4fa62
O reflog lembra por padrão cada posição que o HEAD ocupou nos últimos 90 dias. Um reset --hard sobre um commit perdido o traz de volta exatamente como estava.
Pegadinhas
- Nunca dê force-push num reset numa branch compartilhada. Reescrever um histórico que outros já deram pull quebra os clones deles. É exatamente para isso que existe o
revert. HEAD~1eHEAD^são a mesma coisa aqui — um commit atrás. Eles só diferem em merge commits, ondeHEAD^2significa o segundo pai.--amenddepois do push também reescreve o histórico. Ele cria um novo objeto de commit com um hash novo, então a mesma regra vale.
Perguntas relacionadas
Como desfazer os últimos três commits mantendo todas as alterações? git reset --soft HEAD~3 — tudo desses commits acaba junto em staging.
O reset apaga o commit para sempre? Não imediatamente. Ele fica inacessível e o reflog ainda aponta para ele por cerca de 90 dias, até rodar o garbage collection.
Reset ou revert numa feature branch que mais ninguém usa? Reset. É mais limpo. Revert assim que alguém mais possa ter dado pull.
Veja também
- Tarefas de git ditas em voz alta: "me mostre os commits que eu não fiz push"
- SAFE, CAUTION, DANGER: como o CliAI classifica o que está prestes a rodar
- Dia 1 de onboarding: como o CliAI substitui o "pergunta pro sênior no Slack"
O CliAI marca reset --hard como DANGER e pede confirmação digitada — o único comando do git que realmente perde trabalho. Instale em uma linha.