À titre d'explication supplémentaire, notez que git stash
fait soit deux engagements, soit trois engagements. La valeur par défaut est deux ; vous obtenez trois si vous utilisez n'importe quelle orthographe de l'option --all
ou --include-untracked
options.
Ces deux, ou trois, commits sont spéciaux d'une manière importante : ils sont sur pas de branche. Git les localise grâce au nom spécial stash
. 1 La chose la plus importante, cependant, est ce que Git vous permet - et fait que vous faites avec ces deux ou trois engagements. Pour comprendre cela, nous devons regarder ce qu'il y a dans ces commits.
Ce qu'il y a dans une cachette
Chaque commit peut lister un ou plusieurs parent s'engage. Ceux-ci forment un graphe, où les commits ultérieurs pointent vers les précédents. La cachette contient normalement deux commits, que j'aime appeler i
pour l'index / le contenu de la zone de mise en scène, et w
pour le contenu de l'arbre de travail. Rappelez-vous également que chaque livraison contient un instantané. Dans un commit normal, cet instantané est réalisé de l'index / le contenu de la zone de mise en scène. Ainsi, le i
est en fait un commit parfaitement normal ! Il n'est juste sur aucune branche :
...--o--o--o <-- branch (HEAD)
|
i
Si vous faites une cachette normale, les git stash
Le code fait w
maintenant en copiant tous vos fichiers d'arbre de travail suivis (dans un index auxiliaire temporaire). Git définit le premier parent de ce w
pour pointer vers le HEAD
commit, et le second parent pour pointer vers commit i
. Enfin, il fixe stash
pour pointer vers ce w
commettre :
...--o--o--o <-- branch (HEAD)
|\
i-w <-- stash
Si vous ajoutez --include-untracked
ou --all
Git fait un commit supplémentaire, u
entre la fabrication i
et w
. Le contenu de l'instantané pour u
sont les fichiers qui ne sont pas suivis mais qui ne sont pas ignorés ( --include-untracked
), ou des fichiers qui ne sont pas suivis même s'ils sont ignorés ( --all
). Ce supplément u
commettre a pas de parent, et ensuite quand git stash
fait w
il fixe w
's troisième parent à ce u
s'engager, pour que vous obteniez :
...--o--o--o <-- branch (HEAD)
|\
i-w <-- stash
/
u
Git aussi, à ce stade, supprime tous les fichiers de l'arbre de travail qui se sont retrouvés dans les u
commettre (en utilisant git clean
pour le faire).
Restaurer une cachette
Quand vous allez à rétablir une réserve, vous avez la possibilité d'utiliser --index
ou de ne pas l'utiliser. Ceci indique git stash apply
(ou n'importe quelle commande qui utilise en interne la commande apply
tels que pop
) qu'il devrait utiliser le site i
pour tenter de modifier votre index actuel. Cette modification se fait avec :
git diff <hash-of-i> <hash-of-i's-parent> | git apply --index
(plus ou moins ; il y a un tas de détails qui entravent l'idée de base).
Si vous omettez --index
, git stash apply
ignore complètement le i
commettre.
Si la cachette n'a que deux commits, git stash apply
peut maintenant appliquer le w
s'engager. Pour ce faire, il appelle git merge
2 (sans lui permettre de commiter ou de traiter le résultat comme une fusion normale), en utilisant le commit original sur lequel la cachette a été faite ( i
et w
(le premier parent de l'enfant) comme base de fusion, w
comme le --theirs
et votre livraison actuelle (HEAD) comme cible de la fusion. Si la fusion réussit, tout va bien - enfin, au moins Git le pense - et le git stash apply
elle-même réussit. Si vous avez utilisé git stash pop
pour appliquer la cachette, le code maintenant gouttes la cachette. 3 Si la fusion échoue, Git déclare que l'application a échoué. Si vous avez utilisé git stash pop
le code conserve la cachette et fournit le même état d'échec que dans le cas de git stash apply
.
Mais si vous avez ce troisième commettre - s'il y a un u
engager dans la réserve que vous appliquez - alors les choses changent ! Il n'est pas possible de prétendre que le u
commit n'existe pas. 4 Git insiste pour extraire tous les fichiers de que u
dans l'arbre de travail actuel. Cela signifie que les fichiers doivent soit ne pas exister du tout, soit avoir le même contenu que dans l'arbre de travail actuel. u
commettre.
Pour ce faire, vous pouvez utiliser git clean
mais rappelez-vous que les fichiers non suivis (ignorés ou non) n'ont aucune autre existence dans un dépôt Git, donc assurez-vous que ces fichiers peuvent tous être détruits ! Ou bien, vous pouvez créer un répertoire temporaire, et y déplacer les fichiers pour les mettre en sécurité - ou même faire un autre git stash save -u
ou git stash save -a
puisque ceux-ci fonctionneront git clean
pour vous. Mais ça vous laisse juste avec un autre u
-pour s'en occuper plus tard.
1 C'est en fait refs/stash
. Ceci est important si vous créez une branche nommée stash
le nom complet de la branche est refs/heads/stash
Il n'y a donc pas de conflit entre les deux. Mais ne faites pas ça : Git Cela ne vous dérangera pas, mais vous vous embrouillerez vous-même :-)
2 Le site git stash
utilise en fait git merge-recursive
directement ici. Ceci est nécessaire pour de multiples raisons, et a également pour effet secondaire de s'assurer que Git ne le traite pas comme une fusion lorsque vous résolvez les conflits et livrez.
3 C'est pourquoi je recommande d'éviter git stash pop
en faveur de git stash apply
. Vous avez l'occasion de revoir ce qui a été appliqué et de décider si c'était en fait appliqué correctement. Si ce n'est pas le cas, vous vous avez toujours votre stock ce qui signifie que vous pouvez utiliser git stash branch
pour tout récupérer parfaitement. Eh bien, en supposant l'absence de ce pesant u
commettre.
4 Il devrait vraiment y en avoir : git stash apply --skip-untracked
ou autre. Il devrait également y avoir une variante qui signifie laissez tomber tous ces u
commettre des fichiers dans un nouveau répertoire par exemple, git stash apply --untracked-into <dir>
peut-être.
60 votes
J'ai dû utiliser :
git stash show -p | git apply --3
7 votes
La seule chose qui a fonctionné pour moi est ABOVE COMMENTAIRE !!
4 votes
Merci @xmedeko, quelqu'un peut-il faire la différence entre git stash show -p | git apply et git stash show -p | git apply --3 ?
9 votes
Si vous paniquez, il suffit de lister vos fichiers cachés avec
git stash show
et ensuite sauver les fichiers un par un :$ git show stash@{0}:your/stashed/file.txt > your_rescued_file.txt
. Ceci récupérera le fichier de la cachette et le sauvegardera sous un nom différent. Vous pouvez maintenant expérimenter les méthodes de sauvetage appropriées (voir les réponses ci-dessous). Si les choses s'égarent, vous avez toujours vos fichiers sauvés comme dernière ressource.0 votes
Wow, merci @xmedeko ! Une fois de plus, votre commentaire est la seule chose qui a fonctionné, et c'était si simple. +1 !