Comment récupérer une cachette perdue dans Git?

J’utilise fréquemment git stash et git stash pop pour enregistrer et restaurer les modifications dans mon arbre de travail. Hier, j’ai eu quelques modifications dans mon arbre de travail que j’avais cachées et que j’ai apscopes, puis j’ai apporté plus de modifications à mon arbre de travail. Je voudrais revenir en arrière et examiner les modifications cachées d’hier, mais git stash pop semble supprimer toutes les références au commit associé.

Je sais que si j’utilise git stash alors .git / refs / stash contient la référence du commit utilisé pour créer le stash. Et. Git / logs / refs / stash contient tout le cache. Mais ces références ont disparu après la disparition de git stash pop . Je sais que le commit est toujours dans mon repository quelque part, mais je ne sais pas ce que c’était.

Existe-t-il un moyen facile de récupérer la référence de validation cachée d’hier?

Notez que ce n’est pas essentiel pour moi aujourd’hui car j’ai des sauvegardes quotidiennes et je peux revenir à l’arborescence de travail d’hier pour obtenir mes modifications. Je demande parce qu’il doit y avoir un moyen plus facile!

    Si vous venez juste de l’ouvrir et que le terminal est toujours ouvert, vous aurez toujours la valeur de hachage imprimée par git stash pop sur l’écran (merci, Dolda).

    Sinon, vous pouvez le trouver en utilisant ceci pour Linux et Unix:

     git fsck --no-reflog | awk '/dangling commit/ {print $3}' 

    et pour Windows:

     git fsck --no-reflog | select-ssortingng 'dangling commit' | foreach { $bits = $_ -split ' '; echo $bits[2];} 

    Cela vous montrera tous les commits sur les bouts de votre graphe de commit qui ne sont plus référencés depuis une twig ou une balise – chaque commit perdu, y compris chaque commit de cache que vous avez déjà créé, sera quelque part dans ce graphique.

    La manière la plus simple de trouver l’engagement que vous souhaitez est probablement de passer cette liste à gitk :

     gitk --all $( git fsck --no-reflog | awk '/dangling commit/ {print $3}' ) 

    Cela lancera un navigateur de référentiel vous montrant chaque engagement unique dans le référentiel , qu’il soit accessible ou non.

    Vous pouvez remplacer gitk par quelque chose comme git log --graph --oneline --decorate si vous préférez un graphique agréable sur la console par rapport à une application GUI séparée.

    Pour repérer les commits cachés, recherchez les messages de validation de ce formulaire:

    WIP sur somebranch : commithash Un ancien message de commit

    Remarque : Le message de validation ne sera disponible que sous cette forme (commençant par “WIP activé”) si vous n’avez pas fourni de message lorsque vous avez effectué un git stash .

    Une fois que vous connaissez le hachage de la validation souhaitée, vous pouvez l’appliquer comme une réserve:

     git stash apply $stash_hash 

    Ou vous pouvez utiliser le menu contextuel de gitk pour créer des twigs pour tous les commits inaccessibles qui vous intéressent. Après cela, vous pouvez faire ce que vous voulez avec tous les outils habituels. Lorsque vous avez terminé, il suffit de faire sauter ces twigs à nouveau.

    Si vous ne fermez pas le terminal, regardez simplement la sortie de git stash pop de git stash pop et vous aurez l’ID d’object de la réserve cachée. Cela ressemble normalement à ceci:

     $ git stash pop [...] Dropped refs/stash@{0} (2ca03e22256be97f9e40f08e6d6773c7d41dbfd1) 

    (Notez que la git stash drop produit également la même ligne.)

    Pour récupérer ce cache, lancez git branch tmp 2cae03e et vous l’obtiendrez en tant que twig. Pour convertir cela en une réserve, exécutez:

     git stash apply tmp git stash 

    Le faire en tant que twig vous permet également de le manipuler librement; par exemple, pour le choisir ou le fusionner.

    Je voulais juste mentionner cette addition à la solution acceptée. La première fois que j’ai essayé cette méthode, ce n’était pas évident pour moi (peut-être que cela aurait dû être le cas), mais pour appliquer la valeur cachée à la valeur de hachage, utilisez simplement “git stash apply”:

     $ git stash apply ad38abbf76e26c803b27a6079348192d32f52219 

    Quand j’étais nouveau pour git, ce n’était pas clair pour moi, et j’essayais différentes combinaisons de “git show”, “git apply”, “patch”, etc.

    Je viens de construire une commande qui m’a aidé à trouver mon engagement de cache perdu:

     for ref in `find .git/objects | sed -e 's#.git/objects/##' | grep / | tr -d /`; do if [ `git cat-file -t $ref` = "commit" ]; then git show --summary $ref; fi; done | less 

    Cela répertorie tous les objects dans l’arborescence .git / objects, localise ceux qui sont de type commit, puis affiche un résumé de chacun. A partir de là, il suffisait de parcourir les commits pour trouver un “WIP on work: 6a9bb2” approprié (“work” est ma twig, 619bb2 est un commit récent).

    Je note que si j’utilise “git stash apply” au lieu de “git stash pop” je n’aurais pas ce problème, et si j’utilise “git stash save message ” alors le commit aurait été plus facile à trouver.

    Mise à jour: Avec l’idée de Nathan, cela devient plus court:

     for ref in `git fsck --unreachable | grep commit | cut -d' ' -f3`; do git show --summary $ref; done | less 

    Pour obtenir la liste des stashes encore présents dans votre référentiel, mais qui ne sont plus accessibles:

     git fsck --unreachable | grep commit | cut -d" " -f3 | xargs git log --merges --no-walk --grep=WIP 

    Si vous avez donné un titre à votre réserve, remplacez “WIP” dans -grep=WIP à la fin de la commande par une partie de votre message, par exemple -grep=Tesselation .

    La commande recherche “WIP” parce que le message de validation par défaut pour une réserve est sous la forme WIP on mybranch: [previous-commit-hash] Message of the previous commit.

    git fsck --unreachable | grep commit git fsck --unreachable | grep commit devrait afficher le sha1, bien que la liste renvoyée puisse être assez grande. git show montrera si c’est le commit que vous voulez.

    git cherry-pick -m 1 fusionnera le commit sur la twig en cours.

    Si vous souhaitez recadrer une cachette perdue, vous devez d’abord trouver le hash de votre cachette perdue.

    Comme Aristote Pagaltzis l’a suggéré, git fsck devrait vous aider.

    Personnellement j’utilise mon alias log-all qui me montre tous les commit (commitables récupérables) pour avoir une meilleure vue de la situation:

     git log --graph --decorate --pretty=oneline --abbrev-commit --all $(git fsck --no-reflogs | grep commit | cut -d' ' -f3) 

    Vous pouvez effectuer une recherche encore plus rapide si vous recherchez uniquement les messages “WIP on”.

    Une fois que vous connaissez votre sha1, il vous suffit de changer votre reflet pour append l’ancienne réserve:

     git update-ref refs/stash ed6721d 

    Vous préférerez probablement avoir un message associé pour un -m

     git update-ref -m "$(git log -1 --pretty=format:'%s' ed6721d)" refs/stash ed6721d 

    Et vous voudrez même l’utiliser comme un alias:

     restash = !git update-ref -m $(git log -1 --pretty=format:'%s' $1) refs/stash $1 

    J’ai aimé l’approche d’Aristotle, mais je n’ai pas aimé utiliser GITK … comme je suis habitué à utiliser GIT depuis la ligne de commande.

    Au lieu de cela, j’ai pris les commits en suspens et sorti le code dans un fichier DIFF pour examen dans mon éditeur de code.

     git show $( git fsck --no-reflog | awk '/dangling commit/ {print $3}' ) > ~/stash_recovery.diff 

    Vous pouvez maintenant charger le fichier diff / txt résultant (dans votre dossier personnel) dans votre éditeur txt et voir le code réel et le SHA résultant.

    Alors utilisez juste

     git stash apply ad38abbf76e26c803b27a6079348192d32f52219 

    Dans OSX avec git v2.6.4, je lance simplement accidentellement Git Stash Drop, puis je l’ai trouvé en passant sous les étapes

    Si vous connaissez le nom de la réserve, utilisez:

    $ git fsck --unreachable | grep commit | cut -c 20- | xargs git show | grep -B 6 -A 2

    sinon vous trouverez l’ID du résultat manuellement avec:

    $ git fsck --unreachable | grep commit | cut -c 20- | xargs git show

    Ensuite, quand vous trouvez l’id de la validation, appuyez simplement sur la git stash apply {commit-id}

    J’espère que cela aide rapidement quelqu’un

    Windows PowerShell équivalent en utilisant gitk:

    gitk --all $(git fsck --no-reflog | Select-Ssortingng "(dangling commit )(.*)" | %{ $_.Line.Split(' ')[2] })

    Il y a probablement un moyen plus efficace de le faire dans un tube, mais cela fait l’affaire.

    Je veux append à la solution acceptée un autre bon moyen de passer en revue toutes les modifications, lorsque vous n’avez pas de gitk disponible ou pas de X pour la sortie.

     git fsck --no-reflog | awk '/dangling commit/ {print $3}' > tmp_commits for h in `cat tmp_commits`; do git show $h | less; done 

    Ensuite, vous obtenez tous les diffs pour ces hachages affichés les uns après les autres. Appuyez sur ‘q’ pour accéder au diff suivant.

    Pourquoi les gens posent cette question? Parce qu’ils ne connaissent pas encore ou ne comprennent pas le reflog.

    La plupart des réponses à cette question donnent de longues commandes avec des options dont presque personne ne se souviendra. Donc, les gens entrent dans cette question et copient collent tout ce dont ils pensent avoir besoin et l’oublient presque immédiatement après.

    Je conseillerais à tous ceux qui ont cette question de vérifier le reflog (git reflog), pas beaucoup plus que cela. Une fois que vous voyez cette liste de tous les commits, il y a une centaine de façons de savoir ce que vous recherchez et de choisir ou créer une twig. Dans le processus, vous aurez appris les options de redogging et les options utiles pour différentes commandes de base de git.

    La réponse acceptée par Aristote montrera tous les commits accessibles, y compris les commits non cachés. Pour filtrer le bruit:

     git fsck --no-reflog | \ awk '/dangling commit/ {print $3}' | \ xargs git log --no-walk --format="%H" \ --grep="WIP on" --min-parents=3 --max-parents=3 

    Cela n’inclut que les commits qui ont exactement 3 commits parents (ce qui sera le cas dans un cache) et dont le message inclut “WIP activé”.

    Gardez à l’esprit que si vous avez sauvegardé votre cache avec un message (par exemple, git stash save "My newly created stash" ), cela remplacera le message par défaut “WIP on …”.

    Vous pouvez afficher plus d’informations sur chaque validation, par exemple afficher le message de validation ou le transmettre à git stash show :

     git fsck --no-reflog | \ awk '/dangling commit/ {print $3}' | \ xargs git log --no-walk --format="%H" \ --grep="WIP on" --min-parents=3 --max-parents=3 | \ xargs -n1 -I '{}' bash -c "\ git log -1 --format=medium --color=always '{}'; echo; \ git stash show --color=always '{}'; echo; echo" | \ less -R 

    Je n’ai pu obtenir aucune des réponses pour travailler sous Windows dans une fenêtre de commande simple (Windows 7 dans mon cas). awk , grep et Select-ssortingng n’ont pas été reconnus comme des commandes. J’ai donc essayé une approche différente:

    • première exécution: git fsck --unreachable | findstr "commit" git fsck --unreachable | findstr "commit"
    • copier la sortie dans le bloc-notes
    • find remplacez “commit non accessible” par start cmd /k git show

    ressemblera à ceci:

    start cmd /k git show 8506d235f935b92df65d58e7d75e9441220537a4 start cmd /k git show 44078733e1b36962571019126243782421fcd8ae start cmd /k git show ec09069ec893db4ec1901f94eefc8dc606b1dbf1 start cmd /k git show d00aab9198e8b81d052d90720165e48b287c302e

    • enregistrer en tant que fichier .bat et l’exécuter
    • le script va ouvrir un tas de fenêtres de commandes, montrant chaque commit
    • Si vous avez trouvé celui que vous cherchez, lancez: git stash apply (your hash)

    peut-être pas la meilleure solution, mais a travaillé pour moi

    Ce que je suis venu chercher ici, c’est comment récupérer le cache, peu importe ce que j’ai vérifié. En particulier, j’avais caché quelque chose, puis extrait une version plus ancienne, puis je l’avais remplie, mais la réserve était une erreur à ce moment-là, de sorte que la réserve avait disparu; Je ne pouvais pas simplement me git stash pour le repousser sur la stack. Cela a fonctionné pour moi:

     $ git checkout somethingOld $ git stash pop ... nothing added to commit but untracked files present (use "git add" to track) Dropped refs/stash@{0} (27f6bd8ba3c4a34f134e12fe69bf69c192f71179) $ git checkout 27f6bd8ba3c $ git reset HEAD^ # Make the working tree differ from the parent. $ git stash # Put the stash back in the stack. Saved working directory and index state WIP on (no branch): c2be516 Some message. HEAD is now at c2be516 Some message. $ git checkout somethingOld # Now we are back where we were. 

    En rétrospective, j’aurais dû utiliser git stash apply pas git stash pop . Je faisais un bisect et j’avais un petit patch que je voulais appliquer à chaque étape. Maintenant je fais ça:

     $ git reset --hard; git bisect good; git stash apply $ # Run tests $ git reset --hard; git bisect bad; git stash apply etc. 

    Récupéré en utilisant les étapes suivantes:

    1. Identifiez le code de hachage caché supprimé:

      gitk –all $ (git fsck –no-reflog | awk ‘/ dangling commit / {print $ 3}’)

    2. Cherry Pick the Stash:

      git cherry-pick -m 1 $ stash_hash_code

    3. Résoudre les conflits, le cas échéant, en utilisant:

      git mergetool

    De plus, vous pourriez avoir des problèmes avec le message de validation si vous utilisez gerrit. Veuillez ranger vos modifications avant de suivre les alternatives suivantes:

    1. Utilisez la réinitialisation matérielle pour la validation précédente, puis recommencez cette modification.
    2. Vous pouvez également cacher le changement, le rebaser et le renouveler.

    Vous pouvez lister tous les commits inaccessibles en écrivant cette commande dans le terminal –

     git fsck --unreachable 

    Vérifiez le hash de commit inaccessible –

     git show hash 

    Enfin, appliquez si vous trouvez l’article caché –

     git stash apply hash 

    Un autre cas d’utilisation courant: vous avez essayé de sauter sur la mauvaise twig et vous avez eu des conflits?

    Tout ce que vous voulez, c’est défaire la pop, tout en la conservant dans la liste de dissimulation pour pouvoir la faire apparaître dans la bonne twig.

    Pour y remédier, procédez comme suit:

     git reset HEAD --hard git checkout my_correct_branch git stash pop 

    Terminé!

    J’ai accidentellement enlevé la cachette dans l’application GitUP. Appuyez simplement sur Ctrl + Z pour l’annuler.

    Peut-être que ça aide quelqu’un;)