Neste post, mostrarei como fazer um git uncommit, isto é, se você fez um git commit, mas ainda não o enviou para o repositório central, como então desfazer (git undo) o último git commit local sem perder suas alterações ou dados.

Git uncomit ou git undo (desfazer) o último commit

Antes de começarmos, preciso ressaltar que não há um comando uncommit ou undo (desfazer) no Git.

Existe um comando git commit e existem outros comandos para nos ajudar a gerenciar todo o fluxo de trabalho, como os comandos git reset ou git clean. Também o comando git revert que geralmente é mal interpretado.

Dito isso, a necessidade de desfazer - voltar atrás no Git é real. Por exemplo, quando você erroneamente envia alguns arquivos usando commit convencional ou semântico, mas eles devem ser confirmados em seu próprio contexto.

Git desfazendo o último commit

Desfazer um commit trás certo risco se você não souber como isso funciona. Mas na verdade é muito fácil de fazer se você o entender. Vamos ver algumas maneiras diferentes de desfazer um git commit.

Vamos trabalhar com o seguinte contexto, você teria algo assim, onde C é o seu HEAD e (F) é o estado dos seus arquivos.

   (F)
A-B-C
  master

git reset hard

Usando git reset --hard você pode desfazer o commit e remover completamente todas as alterações. Em nosso cenário, o commit C seria destruído e também descartaria quaisquer alterações de arquivos não confirmadas.

Então executando:

git reset --hard HEAD~

O resultado seria:

 (F)
A-B
master

Então, usando git reset --hard HEAD~ agora B é o HEAD. Devido ao uso de --hard, os arquivos são redefinidos para seu estado no commit B.

Recuperando um git reset hard

Se você fez git reset --hard, mas precisa recuperar o código destruído, ainda há uma maneira de recuperá-lo. Execute este comando:

git reflog

O git reflog mostrará uma lista de commits (parciais) shas (isto é, hashes) que você moveu durante o trabalho. Então você pode encontrar o commit que você destruiu e executar:

git checkout -b someNewBranchName shaYouDestroyed

Pronto, você recuperou esse commit.

Isso pode ser feito porque os commits não são realmente destruídos no Git por cerca de 90 dias, então você geralmente pode voltar e resgatar um que você não queria se livrar.

git reset

Usando git reset HEAD~ você pode desfazer commit e unstage (retirar do stage) todos os arquivos.

Em nosso exemplo, se commit C não foi uma implementação completamente errada, mas apenas precisou de alguns ajustes. Neste cenário, provavelmente você deseja desfazer o commit, mas manter suas alterações para alguma edição antes de fazer um commit melhor.

Então, começando novamente com C como o HEAD commit:

   (F)
A-B-C
  master

Para desfazer o commit e retirar arquivos do stage, apenas deixe de fora a opção --hard:

git reset HEAD~1

Agora o resultado seria:

   (F)
A-B-C
master

Quando você faz um git reset HEAD~1, você diz ao Git para mover o ponteiro HEAD para trás um commit. Mas (a menos que você use –hard) você deixa seus arquivos como estavam. Então agora git status mostra as alterações que você verificou em C. Você não perdeu nenhuma alteração!

git reset soft

Usando git reset --soft HEAD~ você pode desfazer o commit e manter todos os arquivos preparados (em stage).

Este é o toque mais leve, você pode até desfazer seu commit, mas deixa seus arquivos e seu index:

git reset --soft HEAD~1

Isso não apenas deixa seus arquivos em paz, mas também deixa seu índice em paz. Ao fazer git status, você verá que os mesmos arquivos estão no índice como antes. Na verdade, logo após este comando, você poderia fazer git commit e estaria refazendo o mesmo commit que acabou de desfazer.

Cuidados

  1. Esteja ciente de que essas ações podem não fazer o que você espera se o seu commit errado for uma mesclagem (fast-forward)! Se a sua HEAD estiver em um merge commit (ex: merged branch feature no master), git reset --hard~1 irá apontar o branch master para o último commit dentro do feature branch. Nesse caso, o commit ID específico deve ser usado em vez do comando relativo.

  2. Se o commit foi previamente enviado para o repositório remoto, qualquer operação desfazer causará alguns problemas para o resto dos usuários que têm este commit em sua cópia local, quando eles fizerem um git pull no futuro. Portanto, se o commit já foi enviado (pushed), execute isto:

    git revert <bad-commit-sha1-id> 
    git push origin
    

Conclusões

Mesmo sem um comando git undo, o que seria realmente complicado de implementar e usar, o git oferece opções para voltar a realizar alterações com a oportunidade de refazer erros e organizar corretamente seu código-fonte.