Como extrair um único arquivo (ou alterações em um arquivo) de um stash git?

775

Gostaria de saber se é possível extrair um único arquivo ou diff de um arquivo de um stash git sem desativar o conjunto de alterações stash.

Alguém pode fornecer algumas sugestões / idéias sobre isso?

Danny
fonte

Respostas:

1132

Na página de manual do git stash, você pode ler (na seção "Discussão", logo após a descrição de "Opções") que:

Um stash é representado como um commit cuja árvore registra o estado do diretório de trabalho e seu primeiro pai é o commit no HEAD quando o stash foi criado.

Portanto, você pode tratar o stash (por exemplo, o stash@{0}primeiro / o mais alto stash) como um commit de mesclagem e usar:

$ git diff stash@{0}^1 stash@{0} -- <filename>

Explicação: stash@{0}^1significa o primeiro pai do stash especificado, que, conforme declarado na explicação acima, é o commit no qual as alterações foram ocultadas. Usamos essa forma de "git diff" (com duas confirmações) porque stash@{0}/ refs/stashé uma confirmação de mesclagem e temos que dizer ao git qual pai ou mãe queremos diferenciar. Mais enigmático:

$ git diff stash@{0}^! -- <filename>

também deve funcionar (consulte a página de manual do git rev-parse para obter uma explicação da rev^!sintaxe, na seção "Especificando intervalos").

Da mesma forma, você pode usar o git checkout para verificar um único arquivo fora do stash:

$ git checkout stash@{0} -- <filename>

ou para salvá-lo com outro nome de arquivo:

$ git show stash@{0}:<full filename>  >  <newfile>

ou

$ git show stash@{0}:./<relative filename> > <newfile>

( observe que aqui <nome completo do arquivo> é o nome completo do caminho de um arquivo em relação ao diretório superior de um projeto (pense em: relativo a stash@{0})).


Você pode precisar se proteger stash@{0}da expansão do shell, ou seja, use "stash@{0}"or 'stash@{0}'.

Jakub Narębski
fonte
8
Isso é muito legal ... Eu realmente não entendi como o stash funcionou até ler sua resposta (o que me levou à adição do git-checkout). Eu realmente não entendi isso, quando você faz um stash, o git salva DOIS commits - um para o estado do índice e outro para o estado da cópia de trabalho, que é uma mesclagem entre o índice e o HEAD original. Isso explica as árvores ímpares que eu vi quando visualizo o repositório com "gitk --all" quando há esconderijos.
Pat Notz
4
Principalmente, acho que o aplicativo git checkout é a melhor maneira de realizar o que eu queria fazer. No entanto, fiquei curioso e verifiquei duas vezes git checkouta página de manual. Ele não pode soltar o arquivo em outro local. Há uma referência a isso em: stackoverflow.com/questions/888414/...
Danny
84
$ Git checkout esconderijo @ {0} - <filename> é muito útil, graças
gravitação
43
Observe que a git checkoutabordagem copia o arquivo exato do stash - não o mescla com o que está em seu diretório de trabalho como git stash applyfaria. (Portanto, se você tiver alguma alteração na base em que o stash foi criado, elas serão perdidas).
Peterflynn
4
Observe que, para git stash applymesclar as alterações em um arquivo que foi modificado na árvore de trabalho desde que o arquivo foi armazenado em stash, esse arquivo na árvore de trabalho deve ser preparado. Para que a mesclagem automática funcione, os mesmos arquivos não podem ser modificados na cópia de trabalho e na cópia oculta para mesclar. Finalmente, aplicar stash não remove o item do stash como git stash popfaria.
Ville
46

Se você usar, em git stash applyvez de git stash pop, ele aplicará o estoque à sua árvore de trabalho, mas ainda o manterá.

Com isso feito, você pode add/ commito arquivo que deseja e, em seguida, redefinir as alterações restantes.

Tim Henigan
fonte
2
Para fazer aparecer um estoque específico: git stash pop stash@{0}(lista as mudanças escondidas: git stash list)
MrYoshiji
Se outros arquivos no stash causarem um conflito de mesclagem, o git não me permitirá confirmar no arquivo que eu quero :(
cambunctious
33

Existe uma maneira fácil de obter alterações de qualquer ramificação, incluindo stashes:

$ git checkout --patch stash@{0} path/to/file

Você pode omitir a especificação do arquivo se desejar corrigir várias partes. Ou omita o patch (mas não o caminho) para obter todas as alterações em um único arquivo. Substitua 0pelo número do stash de git stash list, se você tiver mais de um. Observe que é assim diffe oferece a aplicação de todas as diferenças entre os ramos. Para obter alterações de apenas um único commit / stash, dê uma olhada git cherry-pick --no-commit.

Walf
fonte
Isso copia o arquivo exato do esconderijo ou é mesclado? No caso de cópia, se você tiver alguma alteração desde que o stash foi criado, elas serão perdidas.
Danijel
2
@Danijel Read git help checkout. --patchfaz mesclagem interativa. Aplica todos os pedaços que você aprova no shell (ou o que você salva se optar por eeditar o patch). Somente o caminho substituirá o arquivo, como escrevi, "todas as alterações".
Walf
1
ligeira melhoria: git config --global alias.applydiffat '!git checkout --patch "$1" -- $(git diff --name-only "$1"^ "$1")' - em seguida, git applydiffat stash@{4}só usa arquivos que foram alterados entre o stash e seu pai.
Mark
25

Resposta curta

Para ver o arquivo inteiro: git show stash@{0}:<filename>

Para ver o diff: git diff stash@{0}^1 stash@{0} -- <filename>

Luboš Turek
fonte
1
Eu não acho que ele estava preocupado em visualizar o esconderijo de um arquivo em particular - apenas exibindo esse arquivo.
Amalgovinus
1
Era isso que eu estava procurando. Em seguida, você pode substituir diffpor difftoolpara usar seu diff externo favorito.
Peet Brits
19
$ git checkout stash@{0} -- <filename>

Notas:

  1. Certifique-se de colocar espaço após o parâmetro "-" e o nome do arquivo

  2. Substitua zero (0) pelo seu número de stash específico. Para obter a lista stash, use:

    git stash list
    

Baseado na resposta de Jakub Narębski - Versão mais curta

RAM
fonte
11

Você pode obter o diff para um stash com " git show stash@{0}" (ou qualquer que seja o número do stash; consulte "git stash list"). É fácil extrair a seção do diff para um único arquivo.

Nathan Kitchen
fonte
2
Mais simples ainda para mentes como eu: use git show stashpara mostrar o estoque mais alto (normalmente o único que você tem). Da mesma forma, você pode mostrar a diferença entre o seu ramo atual e o esconderijo com git diff head stash.
Dizzley
5

O conceito mais simples de entender, embora talvez não seja o melhor, é que você alterou três arquivos e deseja ocultar um arquivo.

Se você fizer git stashpara guardar todos eles, git stash applytraga-os de volta e depois git checkout f.cno arquivo em questão para redefini-lo efetivamente.

Quando você deseja descompactar esse arquivo, execute um git reset --harde, em seguida, execute git stash applynovamente, aproveitando o fato de que git stash applynão limpa o diff da pilha stash.

Philluminati
fonte
1

Se os arquivos ocultos precisarem ser mesclados com a versão atual, use as formas anteriores usando diff. Caso contrário, você pode usá-lo git poppara desempacotá-los, preparar git add fileWantToKeepo arquivo e fazer um git stash save --keep-indexpara guardar tudo, exceto o que está no palco. Lembre-se de que a diferença dessa maneira com as anteriores é que ela "exibe" o arquivo do stash. As respostas anteriores o mantêm, de git checkout stash@{0} -- <filename>acordo com as suas necessidades.

Hola Soy Edu Feliz Navidad
fonte
0

Use o seguinte para aplicar as alterações em um arquivo em uma ocultação à sua árvore de trabalho.

git diff stash^! -- <filename> | git apply

Isso geralmente é melhor do que usar, git checkoutporque você não perderá nenhuma alteração feita no arquivo desde a criação do stash.

cambunctious
fonte