git reset

Snapshots básicos

Redefinir o HEAD atual para o estado indicado


O comando 'git reset' serve para desfazer mudanças movendo o HEAD da branch atual para um commit indicado. Ele tem três modos principais: --soft (mantém as mudanças preparadas), --mixed (padrão - mantém as mudanças no diretório de trabalho) e --hard (descarta todas as mudanças). É essencial para desfazer commits, tirar arquivos da preparação e gerenciar o histórico. Cuidado com 'git reset --hard', que descarta as mudanças para sempre.

Sinopse

git reset [-q] [<tree-ish>] [--] <pathspec>...
git reset [-q] [--pathspec-from-file=<file>] [<tree-ish>]
git reset (--patch | -p) [<tree-ish>] [--] [<pathspec>...]
git reset [--soft | --mixed [-N] | --hard | --merge | --keep] [-q] [<commit>]
[ ] opcional| ou<arg> valor a substituir... repetível--flag opção

Opções

Clique em uma opção para expandir

Iniciante (3)

Redefine o HEAD para o commit indicado, mas mantém todas as mudanças preparadas. O diretório de trabalho e a área de preparação não mudam. Use para desfazer commits deixando as mudanças prontas para um novo commit.

Quando necessárioDesfazer commits mantendo as mudanças preparadas — por ex. para refazer o commit ou juntar

Exemplo

git reset --soft HEAD~1

O modo padrão. Redefine o HEAD e a área de preparação, mas mantém as mudanças no diretório de trabalho. Use para tirar mudanças da preparação e continuar podendo editá-las.

RecomendadoO jeito mais seguro de desfazer um commit local ou tirar da preparação; mantém as suas edições

Exemplo

git reset HEAD~1

Redefine o HEAD, a área de preparação E o diretório de trabalho para o commit indicado. Mudanças sem commit em arquivos rastreados são descartadas, e arquivos não rastreados que atrapalham os arquivos do commit são sobrescritos (os outros arquivos não rastreados ficam intactos). Não há como desfazer para mudanças sem commit.

Não recomendadoDestrói mudanças sem commit em arquivos rastreados — faça stash ou commit antes

Exemplo

git reset --hard HEAD~1

Intermediário (1)

Escolher de forma interativa os trechos a tirar da preparação. Permite remover mudanças específicas da área de preparação e manter outras preparadas.

Quando necessárioTirar hunks da preparação de forma interativa

Exemplo

git reset -p

Avançado (2)

Redefine o índice e atualiza os arquivos que diferem entre o commit e o HEAD, mas mantém as mudanças não preparadas. As mudanças preparadas são descartadas. Cancela se um arquivo que precisa mudar tiver edições não preparadas.

Quando necessárioAborta um merge; descarta mudanças preparadas, mas mantém as não preparadas

Exemplo

git reset --merge HEAD~1

Redefine o índice e atualiza os arquivos que diferem entre o commit e o HEAD. Cancela se algum desses arquivos tiver mudanças locais. Mantém as mudanças sem commit de arquivos que não mudam entre os commits.

Quando necessárioMais seguro que o --hard para voltar: recusa sobrescrever edições locais

Exemplo

git reset --keep HEAD~1

Escolhendo a opção certa

Modos de reset: o que é mantido?

Entender os três modos principais de reset e o que acontece com as suas mudanças

ComandoO HEAD se moveÁrea de preparaçãoDiretório de trabalhoUse quando
--softSimMantidas (preparadas)PreservadoDesfazer um commit para refazê-lo com mudanças
--mixed (default)SimEsvaziada (fora da preparação)PreservadoDesfazer um commit para editar antes de preparar
--hardSimEsvaziadoMudanças rastreadas PERDIDAS (não rastreadas mantidas)Descartar completamente o commit e todas as mudanças

Reset, revert ou checkout

Escolher o comando de desfazer certo para a sua situação

ComandoModifica o histórico?Seguro para commits enviados?Ideal para
git resetSim (move a branch)Não - causa problemasDesfazer commits locais ainda não enviados
git revertNão (adiciona um commit novo)Sim - seguro em branches compartilhadasDesfazer commits enviados em branches compartilhadas
git checkout -- fileNoSimDescartar mudanças sem commit de arquivos específicos

Tirar mudanças da preparação: reset ou restore

O Git moderno oferece o git restore como alternativa ao reset para tirar da preparação

ComandoPropósitoAfeta commits?Recomendado
git reset HEAD fileTirar um arquivo da preparaçãoNoJeito tradicional
git restore --staged fileTirar um arquivo da preparaçãoNoJeito moderno (Git 2.23+)
git resetTirar todos os arquivos da preparaçãoNoFunciona bem
git restore --staged .Tirar todos os arquivos da preparaçãoNoIntenção mais explícita

Modos de reset avançados

Quando usar --merge e --keep em vez de --hard

ComandoMantém as mudanças locais?Para se houver conflito?Caso de uso
--hardNão - destrói tudoNoReset completo, as mudanças não importam
--mergeSó as mudanças não preparadas (as preparadas se perdem)SimCancelar um merge mantendo o trabalho sem relação
--keepSim (nos arquivos que o reset não toca)SimDesfazer um commit, mas manter edições locais sem relação

Exemplos

Desfazer o último commit, mantendo as mudanças preparadas

git reset --soft HEAD~1

Volta o HEAD um commit. As mudanças daquele commit continuam preparadas, prontas para um novo commit.


Desfazer o último commit, mantendo as mudanças no diretório de trabalho

git reset HEAD~1

Modo padrão (--mixed). Volta o HEAD um commit. As mudanças são mantidas, mas fora da preparação.


Descartar completamente o último commit e as mudanças

git reset --hard HEAD~1

Volta o HEAD um commit e descarta TODAS as mudanças sem commit em arquivos rastreados. Use com cuidado - o trabalho sem commit perdido não pode ser recuperado (o commit em si continua no git reflog).


Tirar um arquivo específico da preparação

git reset HEAD file.js

Remove file.js da área de preparação sem descartar as mudanças. O arquivo continua modificado no diretório de trabalho.

Exemplos de fluxos de trabalho

1
git log --oneline -3

Ver os commits recentes para confirmar qual desfazer

2
git reset --soft HEAD~1

Desfazer o commit, mantendo as mudanças preparadas

3
git status

Conferir que as mudanças estão preparadas

4
git commit -m "Better message"

Fazer o commit de novo com uma mensagem nova

1
git status

Ver o que está preparado agora

2
git reset HEAD unwanted-file.js

Tirar um ou mais arquivos da preparação

3
git status

Confirmar que o arquivo saiu da preparação

4
git commit

Fazer commit só dos arquivos que você quer

1
git status

Revisar o que vai ser perdido

2
git stash

(Opcional) Guardar as mudanças por garantia

3
git reset --hard HEAD~1

Descartar o último commit E todas as mudanças rastreadas (arquivos não rastreados ficam)

4
git status

Confirmar que o diretório de trabalho está limpo

1
git reflog

Achar o hash do commit anterior ao reset

2
git reset --hard abc1234

Voltar para aquele hash de commit

3
git log --oneline

Conferir que os commits foram restaurados

Solução de problemas

fatal: ambiguous argument 'HEAD~1': unknown revision

Causa: Você está no commit inicial - não há commit anterior para onde voltar

Confira o git log. Se só existe um commit, não dá para voltar mais. Use git update-ref -d HEAD para recomeçar do zero.

error: Entry 'app.js' not uptodate. Cannot merge.

Causa: Um arquivo que o --merge ou o --keep precisaria mudar tem edições locais sem commit, então o reset é cancelado

Faça commit ou stash das mudanças antes, ou use --hard se quiser descartá-las

Usei --hard sem querer e perdi mudanças

Causa: O reset hard descarta para sempre todo o trabalho sem commit

Se as mudanças tinham ido para um commit: git reflog para achar o commit, depois git reset --hard <hash>. Se nunca foram para um commit: provavelmente se perderam para sempre.

O reset funcionou, mas um colega diz que o histórico quebrou

Causa: Você deu reset em commits que já estavam em uma branch compartilhada

Em branches compartilhadas, use git revert. Para consertar: git reflog, ache o commit original, dê reset para ele e faça force push (combinando com a equipe).

fatal: ambiguous argument 'HEAD' ao rodar git reset HEAD file

Causa: O repositório ainda não tem commits, então o HEAD não existe (ou o caminho está errado)

Tire o HEAD: git reset file.js (ou git rm --cached file.js). Confira o caminho exato com git status.

Dicas e armadilhas

Boas práticas

  • ✓Nunca use git reset em commits enviados para branches compartilhadas - use git revert
  • ✓Sempre rode git status antes do reset para entender o que será afetado
  • ✓Prefira --soft quando quiser refazer um commit com mudanças
  • ✓Use git stash antes de um reset --hard se talvez queira as mudanças de volta
  • ✓Lembre que o git reflog recupera a maioria dos erros de reset (para mudanças com commit)
  • ✓Use git reset HEAD <file> para tirar arquivos da preparação em vez de dar reset em commits inteiros
  • ✓Considere git restore --staged como alternativa moderna para tirar arquivos da preparação

Erros comuns

  • ✗Usar 'git reset --hard' sem perceber que ele apaga para sempre as mudanças sem commit. Sempre confira duas vezes antes de usar --hard.
  • ✗Dar reset em commits já enviados para um remoto compartilhado. Isso reescreve o histórico e causa problemas para quem colabora. Use 'git revert'.
  • ✗Confundir 'git reset' com 'git revert'. O reset move o ponteiro da branch para trás; o revert cria um commit novo que desfaz as mudanças.
  • ✗Não saber que dá para se recuperar de um reset ruim usando 'git reflog' para achar o hash do commit anterior.
  • ✗Usar 'git reset --hard HEAD' para descartar mudanças de trabalho quando 'git checkout -- .' ou 'git restore .' seriam mais adequados.

Perguntas frequentes

A:

O soft mantém as mudanças preparadas. O mixed (padrão) mantém as mudanças no diretório de trabalho, mas fora da preparação. O hard descarta tudo. Pense assim: soft = desfazer só o commit, mixed = desfazer o commit + tirar da preparação, hard = desfazer tudo.

A:

Para mudanças com commit: sim, use git reflog para achar o hash do commit original e dê reset para ele. Para mudanças sem commit perdidas com --hard: em geral não, elas se foram para sempre.

A:

HEAD~1 significa “um commit antes do HEAD”. HEAD~2 é dois commits para trás, e assim por diante. Você também pode usar hashes de commit diretamente, como git reset abc1234.

A:

Reset para commits locais ainda não enviados - ele reescreve o histórico de forma limpa. Revert para commits enviados em branches compartilhadas - ele cria um commit novo que desfaz as mudanças sem reescrever o histórico.

A:

Use git reset HEAD filename para tirar um arquivo específico da preparação. Isso não move o HEAD nem afeta nenhum commit, só remove o arquivo da área de preparação.

A:

Ele apaga para sempre as mudanças sem commit. Ao contrário das mudanças com commit (recuperáveis pelo reflog), trabalho que nunca foi para um commit não pode ser recuperado depois de um reset hard.