Por que o stash não pode ser aplicado ao diretório de trabalho?

96

Não consigo aplicar o stash de volta ao diretório de trabalho.

Pequena história:

Primeiro tentei enviar algumas alterações confirmadas, mas ele disse: "não, você não pode puxar primeiro" ... OK, então, puxarei coisas do GitHub e, em seguida, executarei minhas alterações. Quando tentei puxar, ele disse que havia alterações que seriam substituídas e que deveria armazená-las. OK, eu escondi as alterações ... fiz o pull e enviei as alterações confirmadas. Mas agora, não posso restaurar as alterações não confirmadas nas quais estava trabalhando.

Este é o erro:

MyPath/File.cs already exists, no checkout
Could not restore untracked files from stash

Com certeza ainda não entendi todos os conceitos do git, eles me confundem um pouco ... talvez eu tenha feito algo errado.

Seria ótimo se alguém pudesse me ajudar a resolver isso ... Estou pesquisando no google e tudo há mais de uma hora e ainda não encontrei uma solução.

A ajuda é muito apreciada. Obrigado!

Miguel Angelo
fonte

Respostas:

74

Parece que seu stash incluía um arquivo não rastreado que foi posteriormente adicionado ao repo. Quando você tenta fazer o check-out, o git se recusa com razão, pois estaria sobrescrevendo um arquivo existente.

Para corrigir, você pode fazer algo como excluir esse arquivo (está tudo bem, ainda está no repo), aplicar seu stash e, em seguida, substituir a versão do arquivo escondido pela versão in-repo, conforme apropriado.

Editar: também é possível que o arquivo só tenha sido criado na árvore de trabalho sem ter sido adicionado ao repo. Nesse caso, não exclua simplesmente o arquivo local, em vez disso:

  1. mova para outro lugar
  2. aplique o estoque
  3. mesclar manualmente as duas versões do arquivo (árvore de trabalho vs. movida).
blahdiblah
fonte
2
Existe alguma maneira de evitar ter que esconder coisas no futuro ... Eu venho do SVN, e parece tão avançado ... você apenas atualiza, resolve os conflitos e, em seguida, efetua o commit. Git não pode ser tão difícil, que preciso adicionar 2 etapas no ciclo. Obrigado novamente!
Miguel Angelo
2
@Miguel: Stashing não é um obstáculo. É uma ferramenta adicional fornecida pelo Git que permite melhorar seu fluxo de trabalho e evitar conflitos e commits sujos. git-scm.com/docs/git-stash
Koraktor
8
Embora a resposta seja válida, não tenho certeza se git está "correto" nisso. Os arquivos estão no repositório, portanto, não há perigo de perda de dados. porque não apenas aplicar as alterações? Veja este tópico - git.661346.n2.nabble.com/stash-refuses-to-pop-td7453780.html
studgeek
5
Acho que essa resposta não é a mais útil. git stashdeve ajudar a fazer backup das alterações locais rapidamente. Excluir manualmente um conjunto de arquivos para restaurá-lo interrompe o fluxo. A git stash branchabordagem na outra resposta parece melhor, mas ainda assim muito mais manual do que o desejado.
bentolor
Essa resposta funcionou melhor para mim na mesma situação. Depois de abrir o estoque, passei por uma fusão como esperava desde o início.
Billy Lazzaro
58

A maneira mais segura e fácil provavelmente seria guardar as coisas novamente:

git stash -u             # This will stash everything, including unstaged files
git stash pop stash@{1}  # This will apply your original stash

Depois, se você estiver satisfeito com o resultado, pode ligar

git stash drop

para remover seu esconderijo "seguro".

Koraktor
fonte
2
Obrigada por isso, me salvou de muita dor e sofrimento!
danjarvis de
9
stash pop será aplicado e descartar seu stash original. Apenas para uso seguro em applyvez de pop.
Hilbrand Bouwkamp
2
Na verdade popé uma combinação de applye drop, mas só dropse applyfuncionou sem conflitos. Mas sim, applygeralmente é mais seguro.
Koraktor
2
Isso pressupõe que não haja outras mudanças no diretório de trabalho que você deseja manter. Para esta questão em particular, ele sugere (mas não diz explicitamente) que está em um estado limpo, mas eu queria apontar isso para outras pessoas que vêm aqui com alterações locais.
Studgeek
1
Isso só resolve o problema se os problemas conflitantes não foram cometidos . Você recebe exatamente a mesma mensagem quando eles foram confirmados (por exemplo, com um checkout limpo) e então isso não mudará nada ...
Jasper
56

Conforme mencionado por @bentolo, você pode excluir manualmente os arquivos dos quais está reclamando, alternar entre os ramos e adicioná-los de volta manualmente. Mas eu pessoalmente prefiro ficar "dentro do git".

A melhor maneira de fazer isso é converter o stash em um branch. Uma vez que é um branch, você pode trabalhar normalmente no git usando as técnicas / ferramentas normais relacionadas ao branch que você conhece e adora. Esta é na verdade uma técnica geral útil para trabalhar com stashes, mesmo quando você não tem o erro listado. Funciona bem porque um stash é realmente um commit nos bastidores (veja PS).

Converter um esconderijo em um galho

O seguinte cria um branch baseado no HEAD quando o stash foi criado e então aplica o stash (não o confirma).

git stash branch STASHBRANCH

Trabalhando com o "branch stash"

O que você faz a seguir depende da relação entre o stash e onde seu branch de destino (que chamarei de ORIGINALBRANCH) está agora.

Opção 1 - Rebase do branch stash normalmente (muitas mudanças desde o stash)

Se você fez muitas mudanças em seu ORIGINALBRANCH, então provavelmente é melhor tratar o STASHBRANCH como qualquer filial local. Faça o commit de suas alterações no STASHBRANCH, rebase-o em ORIGINALBRANCH, depois mude para ORIGINALBRANCH e rebase / mescle as mudanças STASHBRANCH sobre ele. Se houver conflitos, trate-os normalmente (uma das vantagens dessa abordagem é que você pode ver e resolver conflitos).

Opção 2 - Redefinir o branch original para corresponder ao stash (alterações limitadas desde o stash)

Se você apenas armazenou em stash enquanto mantém algumas alterações em staged, então efetue o commit, e tudo que você deseja fazer é obter as alterações adicionais que não estavam armazenadas em stash, você pode fazer o seguinte. Ele retornará ao seu branch e índice originais sem alterar sua cópia de trabalho. O resultado final serão suas mudanças adicionais em sua cópia de trabalho.

git symbolic-ref HEAD refs/heads/ORIGINALBRANCH
git reset

fundo

Stashes são commits como branches / tags (não patches)

PS, É tentador pensar em um stash como um patch (assim como é tentador pensar em um commit como um patch), mas um stash é na verdade um commit contra o HEAD quando foi criado. Quando você aplica / pop, está fazendo algo semelhante a selecioná-lo em seu branch atual. Tenha em mente que branches e tags são realmente apenas referências a commits, então de muitas maneiras, stashes, branches e tags são apenas maneiras diferentes de apontar para um commit (e seu histórico).

Às vezes é necessário, mesmo quando você não fez alterações no diretório de trabalho

PPS, você pode precisar desta técnica depois de usar o stash com --patch e / ou --include-untracked. Mesmo sem alterar os diretórios de trabalho, essas opções às vezes podem criar um stash que você não pode simplesmente aplicar de volta. Devo admitir que não entendo totalmente o porquê. Veja http://git.661346.n2.nabble.com/stash-refuses-to-pop-td7453780.html para alguma discussão.

Studgeek
fonte
5
Esta resposta deve ser marcada como solução, pois fornece as dicas mais úteis sobre como resolver um 'stash bloqueado' de forma mais eficaz. Talvez melhore mencionando a 'solução de exclusão simples' primeiro e a solução de ramificação como segunda opção.
bentolor
8
"git stash branch STASHBRANCH" não parece funcionar se você estiver enfrentando este cenário (exatamente a mesma mensagem de erro ocorre com pop). Você pode ter que fazer algumas redefinições git de antemão.
+1 Eu me envolvi em uma bagunça espaguete com commits e mudanças e stashing etc etc. Isso me tirou disso, colocando o stash em um branch, obrigado studgeek
RobbZ
Obrigado pelo esclarecimento sobre como os stashes não são patches e como eles estão vinculados ao HEAD (no momento do stashing). Isso faz muito sentido. - Então ... suponho que há casos em que é mais flexível / portátil / conveniente criar um patch em vez de um stash (como você mencionou: quando há muitas alterações), de modo que pode ser aplicado em qualquer lugar (e é apenas uma questão de resolução de conflitos). Talvez git stash show -pesteja ajudando lá a fazer stash -> * patch *.
Kamafeather de
39

A solução: você precisa excluir o arquivo em questão e, em seguida, tentar esconder pop / aplicar novamente e ele deve prosseguir. Não apague outros arquivos, apenas os mencionados pelo erro.

O problema: Git é uma merda às vezes. Ao ser executado, git stash -uele inclui arquivos não rastreados (legal!), Mas não remove esses arquivos não rastreados e não sabe como aplicar os arquivos não rastreados escondidos em cima das sobras (não é legal!), O que realmente torna a -uopção bastante inútil.

qwertzguy
fonte
3
Eu teria aceitado essa resposta se fosse minha pergunta. Obrigado @qwertzguy, sua resposta resolveu meu problema,
Kobus Myburgh
Eu mesmo tive o mesmo problema, o git stash pop não se aplicaria até que eu excluísse os arquivos em questão - então, tive um conflito com um arquivo que fez com que o stash fosse rejeitado. Mas, em vez de remover os arquivos não rastreados, ele os deixou para trás. Portanto, observe para o futuro, fique longe degit stash -u
notzippy
Mau conselho se você precisar de partes de ambas as versões dos arquivos afetados.
Walf
2
"não remove esses arquivos não rastreados" ... e não os lista em git stash show. Essa resposta fez a lâmpada acender.
jscs
2
mais um para Git às vezes é uma merda.
Harish
29

Para aplicar as diferenças de código no stash como um patch, use o seguinte comando:

git stash show --patch | patch -p1
ciférico
fonte
11
Normalmente é melhor explicar uma solução em vez de apenas postar algumas linhas de código anônimo. Você pode ler Como faço para escrever uma boa resposta e também Explicando respostas inteiramente baseadas em código .
Massimiliano Kraus
Isso funciona para mim, pois o patch de git stash show --patchnão contém os arquivos não rastreados.
Steven Shaw
Essa resposta me ajudou muito, já que não consegui liberar meu estoque devido a muitas alterações em meu repositório desde que o estoque foi empurrado.
Erik Finnman
1

Isso já aconteceu comigo várias vezes, eu guardo arquivos não rastreados git stash -uque acabam sendo adicionados ao repositório e não consigo mais aplicar as alterações armazenadas.

Não consegui encontrar uma maneira de forçar git stash pop/applya substituição dos arquivos, então primeiro removo as cópias locais dos arquivos não rastreados que foram armazenados ( tenha cuidado, pois isso excluirá quaisquer alterações que não foram confirmadas ) e, em seguida, aplico as alterações armazenadas :

rm `git ls-tree -r stash@{0}^3 --name-only`
git stash apply

Finalmente, eu uso git status, git diffe outras ferramentas para verificar e adicionar de volta partes dos arquivos removidos, se houver algo faltando.


Se você tiver alterações não confirmadas que deseja manter, pode criar um commit temporário primeiro:

git add --all
git commit -m "dummy"
rm `git ls-tree -r stash@{0}^3 --name-only`
git stash apply

Use todas as ferramentas adequadas para mesclar as alterações confirmadas anteriormente de volta aos arquivos locais e remova o commit fictício:

git reset HEAD~1
Helder Pereira
fonte
0

Minha operação pop bloqueada de forma semelhante ocorreu porque restos de arquivos ignorados (consulte o arquivo .gitignore). O status do Git me mostrou rastreado e não rastreado, mas minhas atividades não limparam os arquivos ignorados.

Detalhes: Eu usei git stash save -a, verifiquei o master para compilar e ver o comportamento original, depois tentei colocar tudo de volta para continuar editando. Quando eu verifiquei meu branch e tentei abrir, meus arquivos ignorados ainda estavam lá antes de salvar o stash. Isso ocorre porque o check-out do mestre afetou apenas os arquivos confirmados - não apagou os arquivos ignorados. Então o pop falhou, essencialmente dizendo que não queria restaurar meus arquivos ignorados armazenados em cima dos arquivos que ainda estavam lá. É uma pena que não consegui descobrir uma maneira de iniciar uma sessão de mesclagem com eles.

No final das contas, eu costumava git clean -f -d -xremover os arquivos ignorados. Curiosamente, dos meus ~ 30, 4 arquivos ainda permaneceram após a limpeza (enterrados em subdiretórios). Terei que descobrir em que categoria eles estão, que eles tiveram que ser excluídos manualmente.

Então meu pai teve sucesso.

afirmado
fonte
0

Experimente isto:

git checkout stash -.

Nalan Madheswaran
fonte
-1

Outra solução:

cd to/root/your/project

# Show what git will be remove
git clean -n

# If all is good
git clean -f

# If not all is good, see
git clean --help

# Finish
git stash pop
ktretyak
fonte
O erro mencionado na pergunta é causado por um arquivo que existe tanto na pilha quanto no diretório de trabalho. A limpeza só corrige se esse arquivo não for rastreado, o que certamente nem sempre é o caso (e não é o caso do OP, já que ele obteve o arquivo de um pull).
Xavier Poinas
-1

Com Git 2.14.x / 2.15 (Q3 2017), a solução qwertzguy de 2014 não será mais necessária.

Antes do terceiro trimestre de 2017, você tinha que excluir o arquivo em questão e, em seguida, tentar armazenar / aplicar novamente.
Com o próximo lançamento do Git, você não terá que fazer isso.

Veja o commit bbffd87 (11 de agosto de 2017) de Nicolas Morey-Chaisemartin ( nmorey) .
(Incorporado por Junio ​​C Hamano - gitster- no commit 0ca2f32 , 23 de agosto de 2017)

stash: limpar arquivos não rastreados antes de redefinir

Se estiver chamando git stash -uum repo que contém um arquivo que não é mais ignorado devido a uma modificação atual do gitignorearquivo, esse arquivo é armazenado, mas não removido da árvore de trabalho.
Isso ocorre porque git-stashprimeiro faz um reset --hardque limpa a .gitignoremodificação do arquivo e depois chama git clean, deixando o arquivo intacto.
Isso faz git stash popcom que falhe devido ao arquivo existente .

Este patch simplesmente muda a ordem entre limpeza e redefinição e adiciona um teste para este caso de uso.

VonC
fonte
-1

A maneira mais segura de seguir o stashing

git stash -u

Isso irá esconder tudo, incluindo mudanças não planejadas

git stash drop

depois de terminar de trabalhar nele, para remover seu stash "seguro".

RahulMohan Kolakandy
fonte
Conforme explicado em stackoverflow.com/a/23743125/6309 , isso nem sempre funcionaria com Git 2.14 ou menos. Ele funcionará com Git 2.15: stackoverflow.com/a/46027357/6309
VonC