Question Comment récupérer une cachette dropée dans Git?


J'utilise fréquemment git stash et git stash pop enregistrer et restaurer les modifications dans mon arbre de travail. Hier, j'ai eu quelques changements dans mon arbre de travail que j'avais caché et sauté, et puis j'ai apporté plus de changements à mon arbre de travail. Je voudrais revenir en arrière et revoir les changements cachés d'hier, mais git stash pop semble supprimer toutes les références à la validation associée.

Je sais que si j'utilise git stash puis .git / refs / stash contient la référence du commit utilisée pour créer la cachette. Et .git / logs / refs / stash contient toute la cachette. Mais ces références sont parties après git stash pop. Je sais que le commit est toujours dans mon référentiel 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 critique pour moi aujourd'hui car j'ai des sauvegardes quotidiennes et je peux revenir à l'arbre de travail d'hier pour obtenir mes changements. Je demande parce qu'il doit y avoir un moyen plus facile!


1331
2017-09-18 01:59


origine


Réponses:


Si vous venez juste de l'ouvrir et que le terminal est toujours ouvert, vous toujours avoir la valeur de hachage imprimé par git stash pop À 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-string 'dangling commit' | foreach { $bits = $_ -split ' '; echo $bits[2];}

Cela vous montrera tous les commits aux extrémités de votre graphe de validation qui ne sont plus référencés à partir d'une branche ou d'un tag - chaque commit perdu, y compris chaque commit caché que vous avez jamais créé, sera quelque part dans ce graphe.

La façon la plus simple de trouver la sauvegarde que vous voulez 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 seul commit dans le référentiel jamais, peu importe s'il est accessible ou non.

Vous pouvez remplacer gitk là avec quelque chose comme git log --graph --oneline --decorate si vous préférez un graphique sympa sur la console via une application graphique séparée.

Pour repérer les validations cachées, recherchez les messages de validation de ce formulaire:

WIP sur unbranch: commithash Un ancien message de commit

Remarque: Le message de validation sera uniquement dans ce formulaire (commençant par "WIP activé") si vous n'avez pas fourni de message lorsque vous l'avez fait git stash.

Une fois que vous connaissez le hachage du commit que vous voulez, vous pouvez l'appliquer en cachette:

git stash apply $ stash_hash

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


2151
2017-09-18 11:38



Si vous n'avez pas fermé le terminal, regardez simplement la sortie de git stash pop et vous aurez l'identifiant de l'objet de la cachette abandonnée. Cela ressemble normalement à ceci:

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

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

Pour récupérer ce cachet, il suffit de courir git branch tmp 2cae03eet vous l'aurez comme une branche. Pour convertir ceci en cachette, exécutez:

git stash apply tmp
git stash

Avoir comme une branche vous permet également de le manipuler librement; par exemple, pour le sélectionner ou le fusionner.


597
2017-10-21 03:13



Je voulais juste mentionner cet ajout à la solution acceptée. Ce n'était pas immédiatement évident pour moi la première fois que j'ai essayé cette méthode (peut-être que cela aurait dû l'être), mais pour appliquer la cachette de la valeur de hachage, il suffit d'utiliser "git stash apply":

$ git stash apply ad38abbf76e26c803b27a6079348192d32f52219

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


231
2018-03-03 20:28



Je viens de construire une commande qui m'a aidé à trouver mon commit caché 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 liste tous les objets dans l'arbre .git / objects, localise ceux qui sont de type commit, puis montre un résumé de chacun. À partir de ce moment, il suffisait de regarder à travers les commits pour trouver un "WIP sur le travail" approprié: "6a9bb2" ("work" est ma branche, 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 pu être 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

68
2017-09-18 02:10



Pour obtenir la liste des cachettes qui sont encore dans votre dépôt, mais qui ne sont plus joignables:

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

Si vous avez donné un titre à votre cachette, remplacez "WIP" par -grep=WIP à la fin de la commande avec une partie de votre message, par ex. -grep=Tesselation.

La commande est "grep" pour "WIP" parce que le message de commit par défaut pour une cachette est dans le formulaire WIP on mybranch: [previous-commit-hash] Message of the previous commit.


56
2018-05-04 06:42



git fsck --unreachable | grep commit devrait montrer le sha1, bien que la liste qu'il renvoie puisse être assez grande. git show <sha1> montrera si c'est le commit que vous voulez.

git cherry-pick -m 1 <sha1> fusionnera le commit sur la branche actuelle.


36
2017-09-18 02:08



Si vous voulez récupérer une cachette perdue, vous devez d'abord trouver le hash de votre cachette perdue.

Comme Aristote Pagaltzis a suggéré un git fsck devrait t'aider

Personnellement j'utilise mon log-all alias qui me montre chaque commit (commits récupérables) pour avoir une meilleure vision 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 des messages "WIP".

Une fois que vous connaissez votre sha1, vous changez simplement votre cache pour ajouter l'ancienne cachette:

git update-ref refs/stash ed6721d

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

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

Et vous voudrez même l'utiliser comme alias:

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

23
2018-06-23 14:20