J'ai eu un tas de changements par étapes et non et je voulais passer rapidement à une autre branche, puis revenir en arrière.
J'ai donc mis en scène mes modifications en utilisant:
$ git stash push -a
(Avec le recul, j'aurais probablement pu utiliser à la --include-untracked
place de --all
)
Ensuite, quand je suis allé ouvrir la cachette, je reçois beaucoup d'erreurs du genre:
$ git stash pop
foo.txt already exists, no checkout
bar.txt already exists, no checkout
...
Could not restore untracked files from stash entry
Il ne semble pas y avoir de modifications restaurées à partir de la réserve.
J'ai aussi essayé $ git stash branch temp
mais cela montre les mêmes erreurs.
J'ai trouvé un moyen de contourner ce problème qui consistait à utiliser:
$ git stash show -p | git apply
Désastre évité pour l'instant mais cela soulève quelques questions.
Pourquoi cette erreur s'est-elle produite en premier lieu et comment l'éviter la prochaine fois?
git stash show -p | git apply --3
git stash show
et que les fichiers de secours , un par un:$ git show stash@{0}:your/stashed/file.txt > your_rescued_file.txt
. Cela récupérera le fichier de la réserve et l'enregistrera sous un nom différent. Vous pouvez maintenant expérimenter en toute sécurité avec les méthodes de sauvetage appropriées (voir les réponses ci-dessous). Si les choses tournent mal, vous avez toujours vos fichiers sauvés comme dernière ressource.Réponses:
Comme explication supplémentaire, notez que cela
git stash
fait soit deux commits, soit trois commits. La valeur par défaut est de deux; vous en obtenez trois si vous utilisez une orthographe des options--all
ou--include-untracked
.Ces deux, ou trois, commits sont spéciaux d'une manière importante: ils ne sont sur aucune branche. Git les localise via le nom spécial
stash
. 1 Le plus important, cependant, est ce que Git vous permet - et vous oblige - à faire avec ces deux ou trois commits. Pour comprendre cela, nous devons examiner le contenu de ces commits.Qu'y a-t-il dans une cachette
Chaque commit peut lister un ou plusieurs commits parents . Ceux-ci forment un graphique, où les commits ultérieurs renvoient aux précédents. Le stash contient normalement deux commits, que j'aime appeler
i
pour le contenu de l'index / de la zone de préparation etw
pour le contenu de l'arbre de travail. Souvenez-vous également que chaque commit contient un instantané. Dans une validation normale, cet instantané est créé à partir du contenu de l'index / de la zone de préparation. Donc lei
commit est en fait un commit parfaitement normal! Ce n'est tout simplement pas sur aucune branche:Si vous créez une réserve normale, le
git stash
code le créew
maintenant en copiant tous vos fichiers d'arborescence de travail suivis (dans un index auxiliaire temporaire). Git définit le premier parent de cew
commit pour qu'il pointe vers leHEAD
commit et le second parent pour pointer vers commiti
. Enfin, il se metstash
à pointer vers cew
commit:Si vous ajoutez
--include-untracked
ou--all
, Git effectue un commit supplémentaire,,u
entre la création dei
etw
. Le contenu de l'instantané pouru
sont les fichiers qui ne sont pas suivis mais non ignorés (--include-untracked
), ou les fichiers qui ne sont pas suivis même s'ils sont ignorés (--all
). Ceu
commit supplémentaire n'a pas de parent, puis quand il estgit stash
faitw
, il définitw
le troisième parent de ceu
commit, de sorte que vous obtenez:Git également, à ce stade, supprime tous les fichiers d'arbre de travail qui se sont terminés dans le
u
commit (en utilisantgit clean
pour faire cela).Restaurer une cachette
Lorsque vous allez restaurer une réserve, vous avez la possibilité de l'utiliser
--index
ou de ne pas l'utiliser. Cela indiquegit stash apply
(ou l'une des commandes qui utilisent en interneapply
, telles quepop
) qu'il doit utiliser lai
validation pour tenter de modifier votre index actuel. Cette modification se fait avec:(plus ou moins; il y a un tas de détails nitty qui entravent l'idée de base ici).
Si vous omettez
--index
,git stash apply
ignore complètement lei
commit.Si le stash n'a que deux validations , vous
git stash apply
pouvez maintenant appliquer lew
commit. Il le fait en appelantgit merge
2 (sans lui permettre de valider ou de traiter le résultat comme une fusion normale), en utilisant le commit d'origine sur lequel le stash a été créé (i
le parent de etw
le premier parent de) comme base de fusion,w
comme le--theirs
commit et votre commit actuel (HEAD) comme cible de la fusion. Si la fusion réussit, tout va bien - enfin, du moins Git le pense - et legit stash apply
lui - même réussit. Si vous aviez l'habitudegit stash pop
d'appliquer la réserve, le code supprime maintenant la réserve. 3 Si la fusion échoue, Git déclare que l'application a échoué. Si vous avez utiliségit stash pop
, le code conserve la réserve et fournit le même état d'échec que pourgit stash apply
.Mais si vous avez ce troisième commit - s'il y a un
u
commit dans la réserve que vous appliquez - alors les choses changent! Il n'y a aucune option pour prétendre que leu
commit n'existe pas. 4 Git insiste pour extraire tous les fichiers de ceu
commit, 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 leu
commit.Pour que cela se produise, vous pouvez utiliser
git clean
vous-même - mais rappelez-vous que les fichiers non suivis (ignorés ou non) n'ont pas d'autre existence dans un référentiel Git, alors 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 conserver - ou même en faire un autregit stash save -u
ougit stash save -a
, puisque ceux-ci seront exécutésgit clean
pour vous. Mais cela ne vous laisse qu'une autreu
réserve de style à gérer plus tard.1 Ceci est en fait
refs/stash
. Cela est important si vous créez une branche nomméestash
: le nom complet de la branche estrefs/heads/stash
, donc ceux-ci ne sont pas en conflit. Mais ne faites pas cela: Git ne me dérangerait pas, mais vous vous confondez. :-)2 Le
git stash
code utilise en faitgit merge-recursive
directement ici. Ceci est nécessaire pour plusieurs raisons, et a également pour effet secondaire de s'assurer que Git ne le traite pas comme une fusion lorsque vous résolvez des conflits et commettez.3 C'est pourquoi je recommande d'éviter
git stash pop
, en faveur degit stash apply
. Vous avez la possibilité de revoir ce qui a été appliqué et de décider si cela a été effectivement appliqué correctement. Sinon, vous avez toujours votre réserve, ce qui signifie que vous pouvezgit stash branch
tout récupérer parfaitement. Eh bien, en supposant l'absence de cetu
engagement embêtant .4 Il devrait vraiment y avoir:
git stash apply --skip-untracked
ou quelque chose. Il devrait également y avoir une variante qui signifie déposer tous cesu
fichiers de validation dans un nouveau répertoire , par exemplegit stash apply --untracked-into <dir>
, peut-être.la source
--index
:git stash apply --index
?git stash save --all
, puis j'ai immédiatement faitgit stash apply
, mais certains fichiers manquaient parce que je les ai renommés puis créés à nouveau (avant de les cacher). Ce qui a aidé, c'est:git checkout stash@{0} -- .
je ne vais même pas me souciergit checkout stash^3 -- .
parce que tout semble OK maintenant. C'est dommage que je n'ai pas le temps de vraiment comprendre ce qui se passait. Merci.J'ai réussi à recréer votre problème. Il semble que si vous cachez des fichiers non suivis puis que vous créez ces fichiers (dans votre exemple,
foo.txt
etbar.txt
), vous avez alors des modifications locales sur des fichiers non suivis qui seraient écrasés lorsque vous postulezgit stash pop
.Pour contourner ce problème, vous pouvez utiliser la commande suivante. Cela remplacera toutes les modifications locales non enregistrées, alors soyez prudent.
Voici quelques informations supplémentaires que j'ai trouvées sur la commande précédente .
la source
--all
/-a
inclura les fichiers ignorés , donc cela peut être pertinent.git merge --squash --strategy-option=theirs stash
approche est meilleure dans ce cas).already exists, no checkout
), consultez ma réponse ci-dessous.Pour développer la réponse de Daniel Smith : ce code ne restaure que les fichiers suivis , même si vous avez utilisé
--include-untracked
(ou-u
) lors de la création du stash. Le code complet requis est:git checkout stash -- . git checkout stash^3 -- . git stash drop # Optional to unstage the changes (auto-staged by default). git reset
Cela restaure entièrement le contenu suivi (dans
stash
) et le contenu non suivi (dansstash^3
), puis supprime la réserve. Quelques notes:git checkout
fait tous devenir automatiquement mis en scène, j'ai donc ajoutégit reset
pour tout désinstaller.stash@{0}
etstash@{0}^3
, dans mes tests, cela fonctionne de la même manière avec ou sans@{0}
Sources:
stash^3
commit magique )la source
à part d'autres réponses, j'ai fait un petit truc
git stash apply
(peut utiliser n'importe quelle commande, par exemple appliquer, pop, etc.)la source