Pergunta

Eu freqüentemente usam git stash e git stash pop para salvar e restaurar mudanças em minha árvore de trabalho. Ontem eu tive algumas mudanças em minha árvore de trabalho que eu tinha escondido e estalaram, e depois fiz mais mudanças para a minha árvore de trabalho. Eu gostaria de voltar e alterações escondido revisão de ontem, mas git stash pop aparece para remover todas as referências ao associado cometer.

Eu sei que se eu usar git stash então .git / refs / esconderijo contém a referência do commit usado para criar o esconderijo. E .git / logs / refs / esconderijo contém todo esconderijo. Mas essas referências são ido após git stash pop. Eu sei que a cometer ainda está em meu lugar repositório, mas eu não sei o que era.

Existe uma maneira fácil de recuperar esconderijo de ontem commit referência?

Note que este não é crítica para mim hoje porque eu tenho backups diários e pode voltar para a árvore de trabalho de ontem para obter as minhas alterações. Estou perguntando porque deve haver uma maneira mais fácil!

Foi útil?

Solução

Depois de saber o hash do esconderijo cometer você caiu, você pode aplicá-lo como um esconderijo:

git stash apply $stash_hash

Ou, você pode criar um ramo separado para ele com

git branch recovered $stash_hash

Depois disso, você pode fazer o que quiser com todas as ferramentas normais. Quando você estiver pronto, basta soprar o ramo de distância.

Finding o hash

Se você tiver apenas o colocou eo terminal ainda está aberta, você vai ainda tem o valor de hash impresso pelo git stash pop em tela (graças, Dolda).

Caso contrário, você pode encontrá-lo usando isso para Linux, Unix ou Git Bash para Windows:

git fsck --no-reflog | awk '/dangling commit/ {print $3}'

... ou usando o PowerShell para Windows:

git fsck --no-reflog | select-string 'dangling commit' | foreach { $bits = $_ -split ' '; echo $bits[2];}

Isto irá mostrar-lhe todos os commits nas pontas de seu gráfico comprometer que já não são referenciados a partir de qualquer ramo ou etiqueta - cada perdido cometem, incluindo cada esconderijo cometer você já criado, será em algum lugar que o gráfico <. / p>

A maneira mais fácil de encontrar o esconderijo cometer você quer é, provavelmente, para passar essa lista para gitk:

gitk --all $( git fsck --no-reflog | awk '/dangling commit/ {print $3}' )

... ou veja a resposta de emragins se usando o PowerShell para Windows.

Isto irá lançar um navegador repositório mostrando-lhe cada comprometer no repositório nunca , independentemente de saber se é acessível ou não.

Você pode substituir gitk lá com algo como git log --graph --oneline --decorate se preferir um gráfico agradável no console sobre um aplicativo GUI separado.

Para detectar commits stash, olhar para cometer mensagens desta forma:

WIP em somebranch : commithash Alguns velha mensagem de commit

Nota :. A mensagem de confirmação será apenas nessa forma (começando com "WIP on") se você não forneceu uma mensagem quando você fez git stash

Outras dicas

Se você não fechar o olhar terminal, apenas na saída de git stash pop e você terá o ID do objeto do cair esconderijo. Ele normalmente se parece com isso:

$ git stash pop
[...]
Dropped refs/stash@{0} (2ca03e22256be97f9e40f08e6d6773c7d41dbfd1)

(Note que git stash drop também produz a mesma linha.)

Para obter essa volta stash, git branch tmp 2cae03e apenas correr, e você vai obtê-lo como um ramo. Para converter isso em um esconderijo, execute:

git stash apply tmp
git stash

Tê-lo como um ramo também permite que você manipulá-lo livremente; por exemplo, para cereja escolher-la ou fundi-lo.

Apenas queria mencionar esta adição à solução aceite. Não ficou imediatamente óbvio para mim a primeira vez que eu tentei este método (talvez deveria ter sido), mas para aplicar o esconderijo do valor de hash, é só usar "git stash de aplicar":

$ git stash apply ad38abbf76e26c803b27a6079348192d32f52219

Quando eu era novo para git, este não foi claro para mim, e eu estava tentando diferentes combinações de "show git", "git aplicar", "patch", etc.

Para obter a lista de esconderijos que ainda estão em seu repositório, mas não acessível mais:

git fsck --unreachable | grep commit | cut -d" " -f3 | xargs git log --merges --no-walk --grep=WIP

Se você deu um título para o seu esconderijo, substitua "WIP" em -grep=WIP no final do comando com uma parte de sua mensagem, por exemplo, -grep=Tesselation.

O comando é grepping para "WIP" porque o padrão mensagem de confirmação para um estoque está na forma WIP on mybranch: [previous-commit-hash] Message of the previous commit.

Eu só construiu um comando que me ajudou a encontrar meu dinheiro perdido cometer:

for ref in `find .git/objects | sed -e 's#.git/objects/##' | grep / | tr -d /`; do if [ `git cat-file -t $ref` = "commit" ]; then git show --summary $ref; fi; done | less

Tudo isso lista os objetos no .git / objetos árvore, localiza os que são do tipo cometer, em seguida, mostra um resumo de cada um. A partir deste ponto, foi apenas uma questão de olhar através dos commits para encontrar um "WIP no trabalho: 6a9bb2" apropriado. ( "Trabalho" é o meu ramo, 619bb2 é uma recente commit)

Noto que se eu usar "git stash de aplicar" em vez de "git stash de pop" Eu não teria esse problema, e se eu usar "git stash save Mensagem ", então o poder comprometer ter sido mais fácil de encontrar.

Update: Com a ideia de Nathan, isso se torna mais curto:

for ref in `git fsck --unreachable | grep commit | cut -d' ' -f3`; do git show --summary $ref; done | less

git fsck --unreachable | grep commit deve mostrar o sha1, embora a lista retorna pode ser muito grande. git show <sha1> vai mostrar se é a cometer quiser.

git cherry-pick -m 1 <sha1> vai mesclar a cometer para o ramo atual.

Se você quiser restash um estoque perdido, você precisa encontrar o hash de seu esconderijo perdido em primeiro lugar.

Como Aristóteles Pagaltzis sugeriu uma git fsck deve ajudá-lo.

Pessoalmente eu uso o meu alias log-all que mostram me cada commit (commits recuperáveis) para ter uma melhor visão da situação:

git log --graph --decorate --pretty=oneline --abbrev-commit --all $(git fsck --no-reflogs | grep commit | cut -d' ' -f3)

Você pode fazer um ainda mais rápido procurar se você está olhando apenas para "WIP em" mensagens.

Uma vez que você sabe que seu sha1, você simplesmente mudar a sua reflog esconderijo para adicionar o antigo esconderijo:

git update-ref refs/stash ed6721d

Você provavelmente vai preferir ter uma mensagem associada de modo a -m

git update-ref -m "$(git log -1 --pretty=format:'%s' ed6721d)" refs/stash ed6721d

E você vai mesmo querer usar isso como um apelido:

restash = !git update-ref -m $(git log -1 --pretty=format:'%s' $1) refs/stash $1

Windows PowerShell equivalente usando gitk:

gitk --all $(git fsck --no-reflog | Select-String "(dangling commit )(.*)" | %{ $_.Line.Split(' ')[2] })

Há provavelmente uma maneira mais eficiente de fazer isso em um tubo, mas isso faz o trabalho.

Eu gostava abordagem de Aristóteles, mas não o fez como usar gitk ... como eu estou acostumado a usar GIT a partir da linha de comando.

Em vez disso, eu levei os commits pendentes e saída o código em um arquivo DIFF para revisão no meu editor de código.

git show $( git fsck --no-reflog | awk '/dangling commit/ {print $3}' ) > ~/stash_recovery.diff

Agora você pode carregar o / arquivo resultante diff txt (sua em sua pasta pessoal) em seu editor de txt e ver o código real e resultando SHA.

Em seguida, basta usar

git stash apply ad38abbf76e26c803b27a6079348192d32f52219

Em OSX com v2.6.4 git, eu só correr queda git stash acidentalmente, então eu descobri-lo indo cocho passos abaixo

Se você sabe o nome do esconderijo, em seguida, usar:

$ git fsck --unreachable | grep commit | cut -c 20- | xargs git show | grep -B 6 -A 2 <name of the stash>

Caso contrário, encontrará ID do resultado por manualmente com:

$ git fsck --unreachable | grep commit | cut -c 20- | xargs git show

Então, quando você encontrar o comprometer-id é só apertar o git stash aplicar {id comprometer-}

Espero que isso ajude alguém rapidamente

Por que as pessoas fazem essa pergunta? Porque eles ainda não conhecem ou entendem a reflog.

A maioria das respostas a esta pergunta dar comandos longos com opções quase ninguém vai se lembrar. Então, as pessoas entram em esta questão e copiar e colar o que eles acham que precisam e esquecê-lo quase imediatamente depois.

Eu aconselharia a todos com esta questão apenas para verificar o reflog (git reflog), não muito mais do que isso. Depois de ver que a lista de todos os commits há cem maneiras de descobrir o que cometem você está procurando e cherry-pick-lo ou criar um núcleo a partir dele. No processo, você terá aprendido sobre os reflog e úteis opções para vários comandos básicos git.

Você pode listar todas as submissões inacessíveis por escrever este comando no Terminal -

git fsck --unreachable

Verifique inacessível comprometer de hash -

git show hash

Finalmente, aplicar se você encontrar o item Stashed -

git stash apply hash

Eu quero adicionar à solução aceita outra boa maneira de passar por todas as mudanças, quando você não quer ter gitk disponíveis ou nenhuma X para a saída.

git fsck --no-reflog | awk '/dangling commit/ {print $3}' > tmp_commits

for h in `cat tmp_commits`; do git show $h | less; done

Em seguida, você recebe todos os diffs para os hashes exibidos um após o outro. Pressione 'q' para chegar ao próximo diff.

A resposta aceite por Aristóteles vai mostrar todos os commits alcançáveis, incluindo os não-stash-like commits. Para filtrar o ruído:

git fsck --no-reflog | \
awk '/dangling commit/ {print $3}' | \
xargs git log --no-walk --format="%H" \
  --grep="WIP on" --min-parents=3 --max-parents=3

Isso só irá incluir commits que têm exatamente 3 commits pais (que um estoque terá), e cuja mensagem inclui "WIP on".

Tenha em mente que, se você salvou o seu esconderijo com uma mensagem (por exemplo git stash save "My newly created stash"), este irá substituir o "WIP em ..." default mensagem.

Você pode exibir mais informações sobre cada commit, por exemplo, exibir a mensagem de commit, ou passá-lo para git stash show:

git fsck --no-reflog | \
awk '/dangling commit/ {print $3}' | \
xargs git log --no-walk --format="%H" \
  --grep="WIP on" --min-parents=3 --max-parents=3 | \
xargs -n1 -I '{}' bash -c "\
  git log -1 --format=medium --color=always '{}'; echo; \
  git stash show --color=always '{}'; echo; echo" | \
less -R

Eu não poderia obter qualquer uma das respostas para funcionar no Windows em uma janela de comando simples (Windows 7 no meu caso). awk, grep e Select-string não foram reconhecidos como comandos. Então, eu tentei uma abordagem diferente:

  • primeira corrida: git fsck --unreachable | findstr "commit"
  • copiar a saída para o bloco de notas
  • Encontrar substituir "inacessível comprometer" com start cmd /k git show

será algo parecido com isto:

start cmd /k git show 8506d235f935b92df65d58e7d75e9441220537a4 start cmd /k git show 44078733e1b36962571019126243782421fcd8ae start cmd /k git show ec09069ec893db4ec1901f94eefc8dc606b1dbf1 start cmd /k git show d00aab9198e8b81d052d90720165e48b287c302e

  • salvar como um arquivo .bat e executá-lo
  • o script vai abrir um monte de janelas de comando, mostrando cada commit
  • Se você encontrou o que você está procurando, run: git stash apply (your hash)

pode não ser a melhor solução, mas funcionou para mim

O que eu vim aqui procurando como realmente obter a volta stash, independentemente do que eu verifiquei para fora. Em particular, eu tinha escondido alguma coisa, então check-out uma versão mais antiga, então poped, mas o esconderijo foi um não-op nesse ponto época anterior, de modo que o estoque desapareceu; Eu não podia simplesmente fazer git stash para empurrá-lo de volta na pilha. Isso funcionou para mim:

$ git checkout somethingOld
$ git stash pop
...
nothing added to commit but untracked files present (use "git add" to track)
Dropped refs/stash@{0} (27f6bd8ba3c4a34f134e12fe69bf69c192f71179)
$ git checkout 27f6bd8ba3c
$ git reset HEAD^    # Make the working tree differ from the parent.
$ git stash # Put the stash back in the stack.
Saved working directory and index state WIP on (no branch): c2be516 Some message.
HEAD is now at c2be516 Some message.
$ git checkout somethingOld # Now we are back where we were.

Em retrospecto, eu deveria ter usado git stash apply não git stash pop. Eu estava fazendo um bisect e tinha um pouco patch que eu queria aplicar a cada passo bisect. Agora eu estou fazendo isso:

$ git reset --hard; git bisect good; git stash apply
$ # Run tests
$ git reset --hard; git bisect bad; git stash apply
etc.

Recuperado lo usando seguintes etapas:

  1. Identificar o código de hash esconderijo excluído:

    gitk --all $ (git fsck --no-reflog | awk '/ pendurada commit / {print $ 3}')

  2. Cherry Escolha o Stash:

    cherry-pick git -m 1 $ stash_hash_code

  3. Resolver conflitos se houver usando:

    git mergetool

Além disso, você pode estar tendo problemas com mensagem de confirmação se você estiver usando gerrit. Por favor Stash suas alterações antes de seguir próximos alternativas:

  1. Use hard reset para submissão anterior e depois comprometer essa mudança.
  2. Você também pode esconder a mudança, rebase e recommit.

Eu fiz acidentalmente removido do esconderijo em GitUP aplicativo. basta pressionar Ctrl + Z para desfazer-lo.

Talvez ele ajuda a alguém;)

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