Pergunta

É possível desfazer as alterações causadas pelo seguinte comando?Se sim, como?

git reset --hard HEAD~1
Foi útil?

Solução

Pat Notz está correto.Você pode recuperar o commit desde que tenha ocorrido dentro de alguns dias.git apenas coleta de lixo após cerca de um mês ou mais, a menos que você diga explicitamente para remover blobs mais recentes.

$ git init
Initialized empty Git repository in .git/

$ echo "testing reset" > file1
$ git add file1
$ git commit -m 'added file1'
Created initial commit 1a75c1d: added file1
 1 files changed, 1 insertions(+), 0 deletions(-)
 create mode 100644 file1

$ echo "added new file" > file2
$ git add file2
$ git commit -m 'added file2'
Created commit f6e5064: added file2
 1 files changed, 1 insertions(+), 0 deletions(-)
 create mode 100644 file2

$ git reset --hard HEAD^
HEAD is now at 1a75c1d... added file1

$ cat file2
cat: file2: No such file or directory

$ git reflog
1a75c1d... HEAD@{0}: reset --hard HEAD^: updating HEAD
f6e5064... HEAD@{1}: commit: added file2

$ git reset --hard f6e5064
HEAD is now at f6e5064... added file2

$ cat file2
added new file

Você pode ver no exemplo que o arquivo2 foi removido como resultado da reinicialização total, mas foi colocado de volta no lugar quando eu reiniciei por meio do reflog.

Outras dicas

O que você deseja fazer é especificar o sha1 do commit para o qual deseja restaurar.Você pode obter o sha1 examinando o reflog (git reflog) e depois fazendo

git reset --hard <sha1 of desired commit>

Mas não espere muito...depois de algumas semanas, o git eventualmente verá esse commit como não referenciado e excluirá todos os blobs.

A resposta está oculta na resposta detalhada acima, você pode simplesmente fazer:

$> git reset --hard HEAD@{1}

(Veja a saída de show de reflog do git)

É possível recuperá-lo se o Git ainda não tiver coletado o lixo.

Obtenha uma visão geral dos commits pendentes com fsck:

$ git fsck --lost-found
dangling commit b72e67a9bb3f1fc1b64528bcce031af4f0d6fcbf

Recupere o commit pendente com rebase:

$ git rebase b72e67a9bb3f1fc1b64528bcce031af4f0d6fcbf

Se você tiver muita sorte, como eu tive, você pode voltar ao seu editor de texto e clicar em ‘desfazer’.

Eu sei que essa não é uma resposta adequada, mas me economizou meio dia de trabalho, então espero que faça o mesmo com outra pessoa!

Exemplo de caso IRL:

$ git fsck --lost-found

Checking object directories: 100% (256/256), done.
Checking objects: 100% (3/3), done.
dangling blob 025cab9725ccc00fbd7202da543f556c146cb119
dangling blob 84e9af799c2f5f08fb50874e5be7fb5cb7aa7c1b
dangling blob 85f4d1a289e094012819d9732f017c7805ee85b4
dangling blob 8f654d1cd425da7389d12c17dd2d88d318496d98
dangling blob 9183b84bbd292dcc238ca546dab896e073432933
dangling blob 1448ee51d0ea16f259371b32a557b60f908d15ee
dangling blob 95372cef6148d980ab1d7539ee6fbb44f5e87e22
dangling blob 9b3bf9fb1ee82c6d6d5ec9149e38fe53d4151fbd
dangling blob 2b21002ca449a9e30dbb87e535fbd4e65bac18f7
dangling blob 2fff2f8e4ea6408ac84a8560477aa00583002e66
dangling blob 333e76340b59a944456b4befd0e007c2e23ab37b
dangling blob b87163c8def315d40721e592f15c2192a33816bb
dangling blob c22aafb90358f6bf22577d1ae077ad89d9eea0a7
dangling blob c6ef78dd64c886e9c9895e2fc4556e69e4fbb133
dangling blob 4a71f9ff8262701171d42559a283c751fea6a201
dangling blob 6b762d368f44ddd441e5b8eae6a7b611335b49a2
dangling blob 724d23914b48443b19eada79c3eb1813c3c67fed
dangling blob 749ffc9a412e7584245af5106e78167b9480a27b
dangling commit f6ce1a403399772d4146d306d5763f3f5715cb5a    <- it's this one

$ git show f6ce1a403399772d4146d306d5763f3f5715cb5a

commit f6ce1a403399772d4146d306d5763f3f5715cb5a
Author: Stian Gudmundsen Høiland <stian@Stians-Mac-mini.local>
Date:   Wed Aug 15 08:41:30 2012 +0200

    *MY COMMIT MESSAGE IS DISPLAYED HERE*

diff --git a/Some.file b/Some.file
new file mode 100644
index 0000000..15baeba
--- /dev/null
+++ b/Some.file
*THE WHOLE COMMIT IS DISPLAYED HERE*

$ git rebase f6ce1a403399772d4146d306d5763f3f5715cb5a

First, rewinding head to replay your work on top of it...
Fast-forwarded master to f6ce1a403399772d4146d306d5763f3f5715cb5a.

até onde sei, --hard irá descartar alterações não confirmadas.Uma vez que estes não são rastreados pelo git.mas você pode desfazer o discarded commit.

$ git reflog

listará:

b0d059c HEAD@{0}: reset: moving to HEAD~1
4bac331 HEAD@{1}: commit: added level introduction....
....

onde 4bac331 é o discarded commit.

Agora é só mover o head para esse commit::

$ git reset --hard 4bac331

Na maioria dos casos, sim.

Dependendo do estado em que seu repositório estava quando você executou o comando, os efeitos de git reset --hard pode variar de trivial a desfazer, até basicamente impossível.

Abaixo listei uma série de diferentes cenários possíveis e como você pode se recuperar deles.

Todas as minhas alterações foram confirmadas, mas agora os commits desapareceram!

Esta situação geralmente ocorre quando você executa git reset com um argumento, como em git reset --hard HEAD~.Não se preocupe, isso é fácil de recuperar!

Se você acabou de correr git reset e não fiz mais nada desde então, você pode voltar para onde estava com esta frase:

git reset --hard @{1}

Isso redefine sua ramificação atual, independentemente do estado em que ela estava antes da última modificação (no seu caso, a modificação mais recente na ramificação seria a reinicialização total que você está tentando desfazer).

Se, no entanto, você ter fez outras modificações em seu branch desde a redefinição, a linha acima não funcionará.Em vez disso, você deve executar git reflog <branchname> para ver uma lista de todas as alterações recentes feitas em sua filial (incluindo redefinições).Essa lista será mais ou menos assim:

7c169bd master@{0}: reset: moving to HEAD~
3ae5027 master@{1}: commit: Changed file2
7c169bd master@{2}: commit: Some change
5eb37ca master@{3}: commit (initial): Initial commit

Encontre nesta lista a operação que deseja “desfazer”.No exemplo acima, seria a primeira linha, aquela que diz “reset:movendo para HEAD~".Em seguida, copie a representação do commit antes (abaixo) essa operação.No nosso caso, isso seria master@{1} (ou 3ae5027, ambos representam o mesmo commit) e executam git reset --hard <commit> para redefinir seu branch atual de volta para esse commit.

Eu organizei minhas mudanças com git add, mas nunca comprometido.Agora minhas alterações desapareceram!

Isso é um pouco mais complicado de se recuperar.idiota faz tenha cópias dos arquivos que você adicionou, mas como essas cópias nunca foram vinculadas a nenhum commit específico, você não pode restaurar as alterações todas de uma vez.Em vez disso, você deve localizar os arquivos individuais no banco de dados do git e restaurá-los manualmente.Você pode fazer isso usando git fsck.

Para obter detalhes sobre isso, consulte Desfazer git reset --hard com arquivos não confirmados na área de teste.

Tive alterações em arquivos em meu diretório de trabalho que nunca testei git add, e nunca comprometido.Agora minhas alterações desapareceram!

Ah, ah.Odeio dizer isso, mas provavelmente você está sem sorte.git não armazena alterações que você não adiciona ou confirma, e de acordo com o documentação para git reset:

--duro

Redefine o índice e a árvore de trabalho. Quaisquer alterações nos arquivos rastreados na árvore de trabalho desde <commit> são descartados.

É possível que você poder ser capaz de recuperar suas alterações com algum tipo de utilitário de recuperação de disco ou um serviço profissional de recuperação de dados, mas neste ponto isso provavelmente é mais problemático do que vale a pena.

Se você ainda não fez a coleta de lixo em seu repositório (por exemplo,usando git repack -d ou git gc, mas observe que a coleta de lixo também pode acontecer automaticamente), então seu commit ainda estará lá – apenas não será mais acessível por meio do HEAD.

Você pode tentar encontrar seu commit olhando a saída de git fsck --lost-found.

As versões mais recentes do Git têm algo chamado "reflog", que é um log de todas as alterações feitas nas referências (em oposição às alterações feitas no conteúdo do repositório).Então, por exemplo, toda vez que você muda seu HEAD (ou seja,toda vez que você faz um git checkout para mudar de branch) que serão logados.E, claro, seu git reset também manipulou o HEAD, então também foi logado.Você pode acessar estados mais antigos de suas referências de maneira semelhante à que você pode acessar estados mais antigos de seu repositório, usando um @ sinal em vez de um ~, como git reset HEAD@{1}.

Demorei um pouco para entender qual é a diferença entre HEAD@{1} e HEAD~1, então aqui está uma pequena explicação:

git init
git commit --allow-empty -mOne
git commit --allow-empty -mTwo
git checkout -b anotherbranch
git commit --allow-empty -mThree
git checkout master # This changes the HEAD, but not the repository contents
git show HEAD~1 # => One
git show HEAD@{1} # => Three
git reflog

Então, HEAD~1 significa "ir para o commit antes do commit que HEAD aponta atualmente", enquanto HEAD@{1} significa "ir para o commit que HEAD apontou antes de apontar para onde aponta atualmente".

Isso permitirá que você encontre facilmente seu commit perdido e recupere-o.

Eu sei que este é um tópico antigo...mas como muitas pessoas estão procurando maneiras de desfazer coisas no Git, ainda acho que pode ser uma boa ideia continuar dando dicas aqui.

Quando você faz um "git add" ou move qualquer coisa do canto superior esquerdo para o canto inferior esquerdo no git gui, o conteúdo do arquivo é armazenado em um blob e é possível recuperar o conteúdo do arquivo desse blob.

Portanto, é possível recuperar um arquivo mesmo que ele não tenha sido confirmado, mas tenha que ser adicionado.

git init  
echo hello >> test.txt  
git add test.txt  

Agora o blob foi criado, mas é referenciado pelo índice, portanto não será listado com git fsck até que sejamos redefinidos.Então reiniciamos...

git reset --hard  
git fsck  

você obterá um blob pendente ce013625030ba8dba906f756967f9e9ca394464a

git show ce01362  

lhe devolverá o conteúdo do arquivo "olá"

Para encontrar commits não referenciados, encontrei uma dica em algum lugar sugerindo isso.

gitk --all $(git log -g --pretty=format:%h)  

Eu tenho isso como uma ferramenta no git gui e é muito útil.

Antes de responder vamos adicionar algumas informações básicas, explicando o que é isso HEAD.

First of all what is HEAD?

HEAD é simplesmente uma referência ao commit atual (mais recente) no branch atual.
Só pode haver um único HEAD a qualquer momento.(excluindo git worktree)

O conteúdo de HEAD está armazenado dentro .git/HEAD e contém os 40 bytes SHA-1 do commit atual.


detached HEAD

Se você não estiver no commit mais recente - o que significa que HEAD está apontando para um commit anterior no histórico, é chamado detached HEAD.

enter image description here

Na linha de comando, será parecido com isto- SHA-1 em vez do nome da ramificação, já que o HEAD não está apontando para a ponta do galho atual

enter image description here


Algumas opções sobre como recuperar de um HEAD desanexado:


git checkout

git checkout <commit_id>
git checkout -b <new branch> <commit_id>
git checkout HEAD~X // x is the number of commits t go back

Isso fará o checkout do novo branch apontando para o commit desejado.
Este comando fará o checkout para um determinado commit.
Neste ponto você pode criar um branch e começar a trabalhar a partir deste ponto.

# Checkout a given commit. 
# Doing so will result in a `detached HEAD` which mean that the `HEAD`
# is not pointing to the latest so you will need to checkout branch
# in order to be able to update the code.
git checkout <commit-id>

# create a new branch forked to the given commit
git checkout -b <branch name>

git reflog

Você sempre pode usar o reflog também.
git reflog exibirá qualquer alteração que atualizou o HEAD e verificar a entrada de reflog desejada definirá o HEAD de volta a este commit.

Cada vez que o HEAD for modificado haverá uma nova entrada no reflog

git reflog
git checkout HEAD@{...}

Isso o levará de volta ao commit desejado

enter image description here


git reset HEAD --hard <commit_id>

"Mova" sua cabeça de volta para o commit desejado.

# This will destroy any local modifications.
# Don't do it if you have uncommitted work you want to keep.
git reset --hard 0d1d7fc32

# Alternatively, if there's work to keep:
git stash
git reset --hard 0d1d7fc32
git stash pop
# This saves the modifications, then reapplies that patch after resetting.
# You could get merge conflicts, if you've modified things which were
# changed since the commit you reset to.
  • Observação:(Desde o Git 2.7)
    você também pode usar o git rebase --no-autostash também.


git revert <sha-1>

"Desfazer" o commit ou intervalo de commits fornecido.
O comando reset irá "desfazer" quaisquer alterações feitas no commit fornecido.
Um novo commit com o patch desfeito será confirmado enquanto o commit original também permanecerá no histórico.

# add new commit with the undo of the original one.
# the <sha-1> can be any commit(s) or commit range
git revert <sha-1>

Este esquema ilustra qual comando faz o quê.
Como você pode ver lá reset && checkout modificar o HEAD.

enter image description here

Acabei de fazer uma reinicialização completa no projeto errado.O que salvou minha vida foi a história local do Eclipse.Diz-se que o IntelliJ Idea também tem um, e seu editor também, vale a pena conferir:

  1. Tópico de ajuda do Eclipse sobre Histórico Local
  2. http://wiki.eclipse.org/FAQ_Where_is_the_workspace_local_history_stored%3F

Criei um pequeno script para tornar um pouco mais fácil encontrar o commit que você está procurando:

git fsck --lost-found | grep commit | cut -d ' ' -f 3 | xargs -i git show \{\} | egrep '^commit |Date:'

Sim, pode ficar consideravelmente mais bonito com o awk ou algo parecido, mas é simples e eu só precisava dele.Pode economizar 30 segundos para outra pessoa.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top