Estou tentando recuperar meu trabalho. Eu estupidamente fiz git reset --hard
, mas antes disso eu só get add .
fiz e não fiz git commit
. Por favor ajude! Aqui está meu log:
MacBookPro:api user$ git status
# On branch master
# Changes to be committed:
# (use "git reset HEAD <file>..." to unstage)
# modified: .gitignore
...
MacBookPro:api user$ git reset --hard
HEAD is now at ff546fa added new strucuture for api
É possível desfazer git reset --hard
nesta situação?
Respostas:
Você deve conseguir recuperar todos os arquivos adicionados ao índice (por exemplo, como na sua situação, com
git add .
), embora possa ser um pouco trabalhoso. Para adicionar um arquivo ao índice, git o adiciona ao banco de dados de objetos, o que significa que ele pode ser recuperado desde que a coleta de lixo ainda não tenha acontecido. Há um exemplo de como fazer isso dado na resposta de Jakub Narębski aqui:No entanto, tentei fazer isso em um repositório de teste e houve alguns problemas -
--cached
deveria haver--cache
, e descobri que ele não criou o.git/lost-found
diretório. No entanto, as seguintes etapas funcionaram para mim:Isso deve gerar todos os objetos no banco de dados de objetos que não podem ser acessados por nenhum ref, no índice ou por meio do reflog. A saída será semelhante a esta:
... e para cada um desses blobs, você pode fazer:
Para produzir o conteúdo do arquivo.
Muita produção?
Atualização em resposta a sehe 's comentário abaixo:
Se você achar que tem muitos commits e árvores listados na saída daquele comando, você pode querer remover da saída quaisquer objetos que são referenciados de commits não referenciados. (Normalmente você pode voltar a esses commits por meio do reflog de qualquer maneira - estamos apenas interessados em objetos que foram adicionados ao índice, mas nunca podem ser encontrados por meio de um commit.)
Primeiro, salve a saída do comando, com:
Agora, os nomes de objeto desses commits inacessíveis podem ser encontrados com:
Assim, você pode encontrar apenas as árvores e objetos que foram adicionados ao índice, mas não confirmados em nenhum ponto, com:
Isso reduz enormemente o número de objetos que você terá que considerar.
Atualização: Philip Oakley abaixo sugere outra maneira de reduzir o número de objetos a serem considerados, que é apenas considerar os arquivos modificados mais recentemente em
.git/objects
. Você pode encontrá-los com:(Encontrei essa
find
invocação aqui .) O final dessa lista pode ser assim:Nesse caso, você pode ver esses objetos com:
(Observe que você deve remover o
/
no final do caminho para obter o nome do objeto.)fonte
Acabei de fazer um
git reset --hard
e perdi um commit. Mas eu sabia o hash do commit, então fui capaz de fazergit cherry-pick COMMIT_HASH
para restaurá-lo.Fiz isso alguns minutos depois de perder o commit, então pode funcionar para alguns de vocês.
fonte
git reflog
, por exemplogit reset --hard
->git reflog
(olhando para o hash HEAD @ {1}) e finalmentegit cherry-pick COMMIT_HASH
git reset --hard
(assumindo que você não fez mais nada depois desse comando) égit reset --hard @{1}
Graças a Mark Longair recebi minhas coisas de volta!
Primeiro salvei todos os hashes em um arquivo:
em seguida, coloco todos eles (removendo o 'blob inacessível') em uma lista e coloco todos os dados em novos arquivos ... você tem que escolher seus arquivos e renomeá-los novamente, o que você precisa ... mas eu só precisava de alguns arquivos .. espero que isso ajude alguém ...
fonte
mkdir lost; git fsck --cache --unreachable $(git for-each-ref --format="%(objectname)") | grep -Po '\s\S{40}$' | xargs -i echo "git show {} > lost/{}.blob" | sh
. Os arquivos acabarão emlost/*.blob
A solução de @Ajedi32 nos comentários funcionou para mim exatamente nesta situação.
Observe que todas essas soluções dependem de não haver git gc, e algumas delas podem causar um, então eu compactaria o conteúdo do seu diretório .git antes de tentar qualquer coisa para que você tenha um instantâneo para voltar, caso não haja não funciona para você.
fonte
git reset --hard
, que bagunçou meu repositório de uma maneira desconhecida. @Duncan, o que @ {1} faz? e a qual comentário você está se referindo? Está reiniciando umgit reset
?Encontrou o mesmo problema, mas não adicionou as alterações ao índice. Portanto, todos os comandos acima não me trouxeram de volta as mudanças desejadas.
Depois de todas as respostas elaboradas acima, esta é uma dica ingênua, mas pode salvar alguém que não pensou nisso primeiro, como eu.
Em desespero, tentei pressionar CTRL-Z no meu editor (LightTable), uma vez em cada guia aberta - isso felizmente recuperou o arquivo nessa guia, ao seu último estado antes do
git reset --hard
. HTH.fonte
Isso provavelmente é óbvio para os profissionais git por aí, mas eu queria colocá-lo, pois em minha busca frenética não vi isso mencionado.
Eu testei alguns arquivos, e me
git reset --hard
apavorei um pouco, e então percebi que meu status mostrava todos os meus arquivos ainda testados, bem como todas as suas exclusões não testadas.Neste ponto, você pode comprometer essas alterações em estágio, contanto que não faça o estágio de suas exclusões. Depois disso, você só precisa reunir coragem para fazer
git reset --hard
mais uma vez, o que o trará de volta às mudanças que você encenou e agora acabou de comprometer.Novamente, isso provavelmente não é novidade para a maioria, mas espero que, como me ajudou e não encontrei nada que sugerisse isso, possa ajudar outra pessoa.
fonte
Meu Deus, puxei meu cabelo até que encontrei essa pergunta e suas respostas. Acredito que a resposta correta e sucinta para a pergunta feita só estará disponível se você juntar dois dos comentários acima, então aqui está tudo em um só lugar:
Como mencionado por chilicuil, execute
git reflog
para identificar lá o hash de commit que você deseja retornarComo mencionado por akimsko, você provavelmente NÃO vai querer escolher a menos que tenha perdido apenas um commit, então você deve executar
git reset --hard <hash-commit-you-want>
Observação para usuários do egit Eclipse: Não consegui encontrar uma maneira de fazer essas etapas dentro do Eclipse com egit. Fechar o Eclipse, executar os comandos acima em uma janela de terminal e, em seguida, reabrir o Eclipse funcionou perfeitamente para mim.
fonte
As soluções acima podem funcionar, no entanto, existem maneiras mais simples de se recuperar disso, em vez de passar pelo
git
desfazer complexo. Eu imagino que a maioria dos git-resets acontecem em um pequeno número de arquivos, e se você já usa o VIM, esta pode ser a solução mais eficiente em termos de tempo. A ressalva é que você já deve estar usandoViM's
persistent-undo, o que deve ser feito de qualquer maneira, porque fornece a capacidade de desfazer um número ilimitado de alterações.Aqui estão as etapas:
No vim pressione
:
e digite o comandoset undodir
. Se vocêpersistent undo
ativou em seu.vimrc
, ele mostrará um resultado semelhante aundodir=~/.vim_runtime/temp_dirs/undodir
.No seu repo, use
git log
para descobrir a última data / hora em que você fez o último commitEm seu shell, navegue até seu
undodir
usocd ~/.vim_runtime/temp_dirs/undodir
.Neste diretório use este comando para encontrar todos os arquivos que você alterou desde o último commit
find . -newermt "2018-03-20 11:24:44" \! -newermt "2018-03-23" \( -type f -regextype posix-extended -regex '.*' \) \-not -path "*/env/*" -not -path "*/.git/*"
Aqui, "2018-03-20 11:24:44" é a data e a hora da última confirmação. Se a data em que você fez o
git reset --hard
for "22/03/2018", use "22/03/2018" e "23/03/2018". Isso ocorre devido a uma peculiaridade de localizar, em que o limite inferior é inclusivo e o superior é exclusivo. https://unix.stackexchange.com/a/70404/242983Em seguida, vá para cada um dos arquivos, abra-os no vim e faça "20m anteriores". Você pode encontrar mais detalhes sobre "anterior" usando "h anterior". Aqui
earlier 20m
significa voltar ao estado do arquivo 20 minutos atrás, supondo que você tenha feito issogit hard --reset
20 minutos atrás. Repita isso para todos os arquivos que foram gerados a partir dofind
comando. Tenho certeza de que alguém pode escrever um script que combine essas coisas.fonte
Estou usando o IntelliJ e consegui simplesmente percorrer cada arquivo e fazer:
Edit -> reload from disk
Felizmente, eu tinha acabado de fazer um
git status
certo antes de apagar minhas alterações de trabalho, então eu sabia exatamente o que tinha que recarregar.fonte
Lembrar sua hierarquia de arquivos e usar a técnica de Mark Longair com a modificação de Phil Oakley produz resultados dramáticos.
Essencialmente, se você pelo menos adicionou os arquivos ao repo, mas não os confirmou, você pode restaurar usando interativamente
git show
, inspecionar o log e usar o redirecionamento de shell para criar cada arquivo (lembrando seu caminho de interesse).HTH!
fonte
Se você revisou recentemente um,
git diff
então há outra maneira de se recuperar de incidentes como este, mesmo quando você ainda não testou as alterações: se a saída degit diff
ainda estiver no buffer do console, você pode simplesmente rolar para cima, copiar e colar o diff em um arquivo e usar apatch
ferramenta para aplicar o diff a sua árvore:patch -p0 < file
. Essa abordagem me salvou algumas vezes.fonte