reset, revert e cherry-pick: as três formas de desfazer
'Desfazer no git' não é um comando só — são três ferramentas diferentes, e usar a errada em histórico compartilhado causa dor de cabeça.
"Preciso desfazer isso" pode significar coisas bem diferentes: desfazer um commit que só existe localmente, desfazer um commit que já foi pushado e outras pessoas já viram, ou trazer só uma mudança específica de outra branch sem trazer tudo. Cada caso tem uma ferramenta certa — usar a errada pode reescrever histórico que não devia ser reescrito.
git reset — move o ponteiro da branch pra trás
reset move o HEAD (e a branch atual) pra um commit anterior, como se os commits depois dele nunca tivessem existido nessa branch. As três variantes controlam o que acontece com as mudanças desses commits "desfeitos":
git reset --soft HEAD~1 # desfaz o commit, mas mantém as mudanças staged (prontas pra commitar de novo)
git reset --mixed HEAD~1 # desfaz o commit e a staging area, mas mantém as mudanças no arquivo (padrão)
git reset --hard HEAD~1 # desfaz o commit E descarta as mudanças completamente — perde o trabalho--hard é o único destrutivo de verdade — os outros dois só reorganizam onde a mudança "mora" (commit, staging, ou arquivo), sem apagar código.
git revert — desfaz publicamente, criando um commit novo
revert não apaga nem reescreve nada — ele cria um commit novo que aplica o efeito contrário do commit escolhido. O commit problemático continua no histórico (pra quem quiser auditar), e o revert some por cima dele.
git revert a3f9e2b # cria um commit que desfaz a3f9e2breset vs. revert: a regra que importa em equipe
reset reescreve o histórico da branch (os commits desfeitos deixam de existir nela) — seguro só em commits locais, não pushados, exatamente pela mesma razão do rebase (lição anterior). revert não reescreve nada, só adiciona — por isso é a ferramenta certa pra desfazer algo em main ou qualquer branch que outras pessoas já têm localmente.
Commit só local, ainda não pushado, quer apagar de vez → git reset
Commit já em main / já pushado / outras pessoas já viram → git revertgit cherry-pick — traz um commit específico, sem trazer a branch toda
Às vezes você quer só um commit de outra branch — não a branch inteira via merge. cherry-pick pega esse commit específico e reaplica na sua branch atual, como um commit novo com o mesmo conteúdo.
git checkout hotfix/producao
git cherry-pick a3f9e2b # traz só esse commit específico, feito originalmente em outra branchUso clássico: alguém corrigiu um bug numa branch de feature ainda não finalizada, mas esse fix específico precisa ir pra produção agora — sem esperar o resto da feature ficar pronto.
Exercício
Um commit com um bug sério já foi pushado pra main há 2 dias, e outras 3 pessoas já deram pull. Você precisa desfazer o efeito desse commit agora. Por que git reset seria uma escolha arriscada aqui, e o que usar no lugar?