Como um pouco de explicação adicional, note que git stash
faz dois commits ou três commits. O padrão é dois; você ganha três se usar qualquer grafia das opções --all
ou --include-untracked
.
Esses dois ou três commits são especiais de uma maneira importante: eles não estão em nenhum branch. Git os localiza por meio do nome especial stash
. 1 A coisa mais importante, entretanto, é o que o Git permite - e o faz - fazer com esses dois ou três commits. Para entender isso, precisamos olhar o que está nesses commits.
O que há dentro de um esconderijo
Cada commit pode listar um ou mais commits pais . Eles formam um gráfico, onde os commits posteriores apontam para os anteriores. O stash normalmente contém dois commits, que eu gosto de chamar i
para o conteúdo da área de teste / índice e w
para o conteúdo da árvore de trabalho. Lembre-se também de que cada commit contém um instantâneo. Em uma confirmação normal, este instantâneo é feito do índice / conteúdo da área de teste. Portanto, o i
commit é de fato um commit perfeitamente normal! Simplesmente não está em qualquer ramo:
...--o--o--o <-- branch (HEAD)
|
i
Se você está fazendo um estoque normal, o git stash
código o faz w
copiando todos os seus arquivos da árvore de trabalho rastreados (em um índice auxiliar temporário). Git configura o primeiro pai deste w
commit para apontar para o HEAD
commit e o segundo pai para apontar para o commit i
. Por último, ele define stash
para apontar para este w
commit:
...--o--o--o <-- branch (HEAD)
|\
i-w <-- stash
Se você adicionar --include-untracked
ou --all
, o Git fará um commit extra,, u
entre fazer i
e w
. O conteúdo do instantâneo u
são aqueles arquivos que não são rastreados, mas não são ignorados ( --include-untracked
), ou arquivos que não são rastreados, mesmo que sejam ignorados ( --all
). Este u
commit extra não tem pai, e então quando git stash
é feito w
, ele configura w
o terceiro pai para este u
commit, de forma que você obtém:
...--o--o--o <-- branch (HEAD)
|\
i-w <-- stash
/
u
Git também, neste ponto, remove todos os arquivos da árvore de trabalho que terminaram no u
commit (usando git clean
para fazer isso).
Restaurando um estoque
Ao restaurar um estoque, você tem a opção de usá-lo --index
ou não. Isso diz git stash apply
(ou qualquer um dos comandos que usa internamente apply
, como pop
) que deve usar o i
commit para tentar modificar seu índice atual. Essa modificação é feita com:
git diff <hash-of-i> <hash-of-i's-parent> | git apply --index
(mais ou menos; há um monte de detalhes essenciais que atrapalham a ideia básica aqui).
Se você omitir --index
, git stash apply
ignora completamente o i
commit.
Se o stash tiver apenas dois commits, git stash apply
agora pode aplicar o w
commit. Ele faz isso chamando git merge
2 (sem permitir que ele comprometa ou trate o resultado como uma mesclagem normal), usando o commit original no qual o stash foi feito ( i
o pai de, e w
o primeiro pai de) como a base de mesclagem, w
como o --theirs
commit, e seu commit atual (HEAD) como o alvo da fusão. Se a fusão for bem-sucedida, tudo estará bem - bem, pelo menos Git pensa assim - e o git stash apply
próprio sucesso. Se você costumava git stash pop
aplicar o stash, o código agora descarta o stash. 3 Se a fusão falhar, o Git declara que a aplicação falhou. Se você usougit stash pop
, o código retém o stash e entrega o mesmo status de falha de git stash apply
.
Mas se você tiver aquele terceiro commit - se houver um u
commit no stash que você está aplicando - então as coisas mudam! Não há opção de fingir que o u
commit não existe. 4 Git insiste em extrair todos os arquivos de que u
cometeu, na obra-árvore atual. Isso significa que os arquivos não devem existir ou ter o mesmo conteúdo do u
commit.
Para fazer isso acontecer, você pode usar git clean
você mesmo - mas lembre-se de que arquivos não rastreados (ignorados ou não) não têm outra existência dentro de um repositório Git, portanto, certifique-se de que todos esses arquivos possam ser destruídos! Ou você pode criar um diretório temporário e mover os arquivos para segurança - ou até mesmo fazer outro git stash save -u
ou git stash save -a
, já que esses serão executados git clean
para você. Mas isso só deixa você com outro u
estoque de estilo para lidar mais tarde.
1 Isso é de fato refs/stash
. Isso é importante se você criar um branch chamado stash
: o nome completo do branch é refs/heads/stash
, portanto, eles não estão em conflito. Mas não faça isso: o Git não se importará, mas você se confundirá. :-)
2 Na git stash
verdade, o código usa git merge-recursive
diretamente aqui. Isso é necessário por vários motivos e também tem o efeito colateral de garantir que o Git não o trate como uma mesclagem quando você resolver conflitos e enviar commit.
3 É por isso que recomendo evitar git stash pop
, em favor de git stash apply
. Você tem a chance de revisar o que foi aplicado e decidir se foi realmente aplicado corretamente. Se não, você ainda tem seu estoque, o que significa que pode usar git stash branch
para recuperar tudo perfeitamente. Bem, supondo a falta daquele u
commit irritante .
4 Realmente deveria haver: git stash apply --skip-untracked
ou algo assim. Também deve haver uma variante que significa colocar todos os u
arquivos de commit em um novo diretório , por exemplo git stash apply --untracked-into <dir>
, talvez.
git stash show -p | git apply --3