Comment récupérer des modifications non validées cachées

691

J'ai eu des changements non validés dans ma branche de développement et je les ai cachés en utilisant git stash, mais il y avait des changements qui étaient très importants parmi ceux qui étaient cachés. Existe-t-il un moyen de récupérer ces changements?

En outre, j'ai apporté des modifications au-dessus des fichiers de code cachés depuis.

Y a-t-il une chance que je puisse récupérer les modifications cachées dans une nouvelle branche si possible?

Aswathy P Krishnan
la source
7
avez-vous essayé d'utiliser 'stash pop'?
robert
Non. En fait, je suis nouveau à git. Comme je ne connais pas bien toutes les commandes, je n'ai rien essayé d'autre! Je ne veux pas perdre ces changements.
Aswathy P Krishnan, du
33
Si vous ne voulez pas perdre les modifications cachées, essayez d'utiliser 'git stash apply'. Cela appliquera les modifications cachées à votre branche actuelle, tout en conservant la cachette. Si tout va bien, après avoir appliqué la cachette, vous pouvez la déposer, en utilisant 'git stash drop'
robert
2
@robert Merci pour la réponse simple par rapport à la réponse acceptée horriblement compliquée (pour un débutant).
Saheel Godhane

Réponses:

1184

La réponse facile à la question facile est git stash apply

Vérifiez simplement la branche sur laquelle vous souhaitez que vos modifications soient effectuées, puis git stash apply. Utilisez ensuite git diffpour voir le résultat.

Une fois que vous avez terminé vos modifications - l' applyapparence est bonne et vous êtes sûr que vous n'avez plus besoin de la cachette - puis utilisez git stash droppour vous en débarrasser.

Je suggère toujours d'utiliser git stash applyplutôt que git stash pop. La différence est que les applyfeuilles autour de la planque pour rejuger facile du applyou pour regarder, etc. Si popest en mesure d'extraire la planque, il sera immédiatement aussi drop, et si vous le réalisez soudainement que vous vouliez extraire quelque part d'autre (dans une branche différente), ou avec --index, ou quelque chose comme ça, ce n'est pas si facile. Si vous apply, vous pouvez choisir quand drop.

C'est tout de même assez mineur d'une manière ou d'une autre, et pour un débutant, il devrait être à peu près la même chose. (Et vous pouvez sauter tout le reste!)


Et si vous faites des choses plus avancées ou plus compliquées?

Il existe au moins trois ou quatre "façons différentes d'utiliser git stash", pour ainsi dire. Ce qui précède est pour la "voie 1", la "voie facile":

  1. Vous avez commencé avec une branche propre, travailliez sur certains changements, puis vous avez réalisé que vous les faisiez dans la mauvaise branche. Vous voulez juste prendre les changements que vous avez maintenant et les "déplacer" vers une autre branche.

    C'est le cas facile, décrit ci-dessus. Exécutez git stash save(ou simplement git stash, la même chose). Découvrez l'autre branche et utilisez git stash apply. Cela permet à git de fusionner dans vos modifications précédentes, en utilisant le mécanisme de fusion plutôt puissant de git. Inspectez soigneusement les résultats (avec git diff) pour voir si vous les aimez, et si vous le faites, utilisez git stash droppour déposer la réserve. Vous avez terminé!

  2. Vous avez commencé certains changements et les avez cachés. Ensuite, vous êtes passé à une autre branche et avez commencé d'autres changements, oubliant que vous aviez les cachés.

    Vous souhaitez maintenant conserver, voire déplacer, ces modifications et appliquer également votre cachette.

    Vous pouvez en fait à git stash savenouveau, car cela git stashfait une "pile" de changements. Si vous faites cela, vous avez deux cachettes, une juste appelée stash- mais vous pouvez également écrire stash@{0}- et une orthographiée stash@{1}. Utilisez git stash list(à tout moment) pour les voir tous. Le plus récent est toujours le plus petit. Lorsque vous git stash drop, il supprime le plus récent et celui qui était stash@{1}déplacé vers le haut de la pile. Si vous en aviez encore plus, celui qui l'était stash@{2}devient stash@{1}, et ainsi de suite.

    Vous pouvez aussi apply, puis dropune cachette spécifique:, git stash apply stash@{2}et ainsi de suite. En supprimant une réserve spécifique, vous ne renumérotez que les numéros plus élevés. Encore une fois, celui sans numéro l'est aussi stash@{0}.

    Si vous empilez beaucoup de cachettes, cela peut devenir assez salissant (était-ce la cachette que je voulais stash@{7}ou était-ce stash@{4}? Attendez, j'en ai juste poussé une autre, maintenant elles sont 8 et 5?). Personnellement, je préfère transférer ces modifications dans une nouvelle succursale, car les succursales ont des noms et représentent cleanup-attempt-in-Decemberbeaucoup plus pour moi que stash@{12}. (La git stashcommande prend un message de sauvegarde facultatif, et ceux-ci peuvent aider, mais d'une manière ou d'une autre, toutes mes réserves se terminent par un nom WIP on branch.)

  3. (Extra-avancé) Vous avez utilisé git stash save -p, ou soigneusement git addet / ou git rmdes bits spécifiques de votre code avant de lancer git stash save. Vous aviez une version dans l'index / zone de stockage caché et une autre version (différente) dans l'arborescence de travail. Vous voulez conserver tout cela. Alors maintenant, vous utilisez git stash apply --index, et cela échoue parfois avec:

    Conflicts in index.  Try without --index.
    
  4. Vous utilisez git stash save --keep-indexpour tester "ce qui sera commis". Celui-ci dépasse le cadre de cette réponse; voir cette autre réponse StackOverflow à la place.

Pour les cas compliqués, je recommande de commencer par un répertoire de travail "propre" en validant toutes les modifications que vous avez maintenant (sur une nouvelle branche si vous le souhaitez). De cette façon, le «quelque part» que vous appliquez ne contient rien d'autre, et vous essayerez simplement les changements cachés:

git status               # see if there's anything you need to commit
                         # uh oh, there is - let's put it on a new temp branch
git checkout -b temp     # create new temp branch to save stuff
git add ...              # add (and/or remove) stuff as needed
git commit               # save first set of changes

Vous êtes maintenant sur un point de départ "propre". Ou peut-être que cela ressemble plus à ceci:

git status               # see if there's anything you need to commit
                         # status says "nothing to commit"
git checkout -b temp     # optional: create new branch for "apply"
git stash apply          # apply stashed changes; see below about --index

La principale chose à retenir est que le "stash" est un commit, c'est juste un commit légèrement "drôle / bizarre" qui n'est pas "sur une branche". L' applyopération examine ce que le commit a changé et essaie de le répéter où que vous soyez. La cachette sera toujours là (la gardera applyautour), donc vous pouvez la regarder plus, ou décider que ce n'était pas le bon endroit applyet réessayer différemment, ou autre chose.


Chaque fois que vous avez une cachette, vous pouvez utiliser git stash show -ppour voir une version simplifiée de ce qu'elle contient. (Cette version simplifiée ne regarde que les modifications de "l'arborescence de travail finale", pas les modifications d'index enregistrées qui sont --indexrestaurées séparément.) La commande git stash apply, sans --index, essaie maintenant de faire ces mêmes modifications dans votre répertoire de travail maintenant.

Cela est vrai même si vous avez déjà des modifications. La applycommande est heureuse d'appliquer une cachette à un répertoire de travail modifié (ou au moins, d'essayer de l'appliquer). Vous pouvez, par exemple, faire ceci:

git stash apply stash      # apply top of stash stack
git stash apply stash@{1}  # and mix in next stash stack entry too

Vous pouvez choisir ici la commande «appliquer», en sélectionnant des masques particuliers à appliquer dans une séquence particulière. Notez cependant que chaque fois que vous effectuez une "fusion git", et comme la documentation de fusion l'avertit:

L'exécution de git merge avec des modifications non validées non triviales est déconseillée: bien que cela soit possible, cela peut vous laisser dans un état difficile à reculer en cas de conflit.

Si vous commencez avec un répertoire propre et que vous effectuez simplement plusieurs git applyopérations, il est facile de revenir en arrière: utilisez git reset --hardpour revenir à l'état propre et modifiez vos applyopérations. (C'est pourquoi je recommande de commencer par un répertoire de travail propre, pour ces cas compliqués.)


Et le pire cas possible?

Disons que vous faites beaucoup de trucs Git avancés, et que vous avez créé une stash, et que vous le souhaitez git stash apply --index, mais il n'est plus possible d'appliquer la stash enregistrée avec --index, car la branche a trop divergé depuis le moment où vous l'avez enregistrée.

C'est pour ça git stash branch.

Si vous:

  1. vérifiez le commit exact sur lequel vous étiez lorsque vous avez fait l'original stash, puis
  2. créer une nouvelle branche, et enfin
  3. git stash apply --index

la tentative de recréer les changements sans aucun doute va fonctionner. C'est ce qui fait. (Et il supprime ensuite la réserve car il a été appliqué avec succès.)git stash branch newbranch


Quelques derniers mots sur --index(de quoi diable s'agit-il?)

Ce que cela --indexfait est simple à expliquer, mais un peu compliqué en interne:

  • Lorsque vous avez des modifications, vous devez git add(ou les "mettre en scène") avant de les commiting.
  • Ainsi, lorsque vous avez exécuté git stash, vous avez peut- être édité les deux fichiers fooet zorg, mais n'en avez créé qu'un seul.
  • Donc, lorsque vous demandez à récupérer la cachette, ce serait bien si ce git addsont les addchoses éditées et non git add les choses non ajoutées. Autrement dit, si vous avez addédité foomais pas zorgavant de faire le stash, il serait peut-être bien d'avoir exactement la même configuration. Ce qui a été mis en scène, devrait à nouveau être mis en scène; ce qui a été modifié mais pas mis en scène, devrait à nouveau être modifié mais pas mis en scène.

Le --indexdrapeau pour applytente de configurer les choses de cette façon. Si votre arbre de travail est propre, cela fonctionne généralement bien. Si votre arbre de travail contient déjà des éléments add, vous pouvez voir comment il peut y avoir des problèmes ici. Si vous omettez --indexcette applyopération , l' opération n'essaie pas de conserver l'intégralité de la configuration par étapes / non. Au lieu de cela, il appelle simplement la machine de fusion de git, en utilisant la validation de l'arbre de travail dans le "sac de dissimulation" . Si vous ne vous souciez pas de la préservation par étapes / sans mise en scène, laisser de côté --indexfacilite beaucoup la tâche git stash apply.

torek
la source
2
Je ne comprends pas votre commentaire. Voulez-vous dire: vous avez couru git stash pop? Ou voulez-vous dire: vous avez modifié certains fichiers, mais ne les avez pas git stashencore exécutés ? Ou voulez-vous dire autre chose entièrement?
torek
1
Oui. Remarque, dans ma (longue) modification, je recommande de valider ce que vous avez maintenant avant de applycréer une cachette. Vous n'êtes pas obligé de le faire, mais cela rend les choses beaucoup plus simples à regarder. Vous pouvez utiliser rebase -ipour écraser ensemble plusieurs validations, ou sélectionner des modifications particulières, ou quoi que ce soit, plus tard.
torek
1
Oui: git stash apply --index(rappelez-vous les deux tirets). Si vous omettez --index, ce n'est pas grave; le seul point --indexest de conserver la configuration par étapes / non par étapes. (Vous n'avez probablement pas eu de configuration spéciale en premier lieu.) Ensuite, git statusetc, et ajoutez / validez comme vous le souhaitez, etc. Quand (et seulement quand) vous avez terminé avec la cachette, utilisez git stash droppour la jeter.
torek
1
Tant que vous conservez (ne pas dropou pop) la cachette, vous avez toujours le code caché d'origine en sécurité lors d'une validation, car une cachette est une validation! Si vous voulez le récupérer exactement, mais sur une branche, utilisez git stash branch(voir cette section ci-dessus, ou le livre Pro Git dans la réponse de Shunya ). Vous pouvez alors git checkoutcette branche, ou git cherry-pickla validation hors de cette branche, etc.
torek
2
@ChuckWolber: Les conventions de dénomination de Git laissent beaucoup à désirer (combien de significations différentes pouvons-nous attribuer aux mots "distant", "suivi" et "branche"?!). Il convient de noter que vous pouvez cependant appliquer une cachette à quelque chose sans rapport avec la cachette d'origine.
torek
57
git stash pop

va tout remettre en place

comme suggéré dans les commentaires, vous pouvez utiliser git stash branch newbranchpour appliquer la cachette à une nouvelle branche, ce qui revient à exécuter:

git checkout -b newbranch
git stash pop
Stefano Falasca
la source
Merci pour l'aide. Puis-je intégrer ces modifications dans une nouvelle succursale? En ce moment je suis sur la branche
develop
3
git stash branch newbranch, créera une nouvelle branche avec les changements cachés.
robert
3
@robert: git stash branch newbranchfera effectivement cela; mais sachez qu'il crée la nouvelle branche avec son parent défini sur la validation qui était HEADau moment où l'opération a stashété effectuée. En d'autres termes, c'est quand vous revenez après une longue session de piratage ou autre, regardez le désordre et décidez "j'aurais dû mettre ça sur une branche, plutôt que de le cacher" :-)
torek
J'ai édité ma question. J'aimerais apporter ces modifications à une nouvelle branche si possible.
Aswathy P Krishnan
1
Parfois, vous voulez juste la réponse TLDR :)
sachinruk
24

Pour simplifier, vous avez deux options pour réappliquer votre stash:

  1. git stash pop - Restaurez à l'état enregistré, mais il supprime la cachette de la mémoire temporaire.
  2. git stash apply - Restaurez à l'état enregistré et laisse la liste cachée pour une éventuelle réutilisation ultérieure.

Vous pouvez lire plus en détail sur les cachettes git dans cet article.

Nesha Zoric
la source
19

Pour vérifier votre contenu caché: -

git stash list

appliquer un no de stash particulier de la liste de stash: -

git stash appliquer stash @ {2}

ou pour appliquer uniquement le premier stash: -

git stash pop

Remarque: git stash pop supprimera la stash de votre liste de stash tandis que git stash ne s'applique pas. Utilisez-les donc en conséquence.

Shivansh Rajolia - HeLleR
la source
2

Sur mac, cela a fonctionné pour moi:

git stash list (voir toutes vos stashs)

git stash list

git stash applique (juste le numéro que vous voulez dans votre liste de stash)

comme ça:

git stash apply 1
Zack
la source
0

vous pouvez cacher les modifications non validées en utilisant "git stash" puis passer à une nouvelle branche en utilisant "git checkout -b" puis appliquer les commits cachés "git stash apply"

S.Sandeeptha
la source