1659 votes

Récupération de la cachette abandonnée dans git

J'utilise fréquemment git stash et git stash pop pour sauvegarder et restaurer les changements dans mon arbre de travail. Hier, j'avais des modifications dans mon arbre de travail que j'avais mises de côté et retirées, puis j'ai apporté d'autres modifications à mon arbre de travail. J'aimerais revenir en arrière et revoir 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 puis .git/refs/stash contient la référence du commit utilisé pour créer la cachette. Et .git/logs/refs/stash contient tout le stock. Mais ces références ont disparu après git stash pop . Je sais que le commit est toujours dans mon dépôt quelque part, mais je ne sais pas ce qu'il était.

Existe-t-il un moyen simple de récupérer la référence du commit de la cachette 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 récupérer mes modifications. Je pose la question parce qu'il doit y avoir un moyen plus simple !

2668voto

Aristotle Pagaltzis Points 43253

Si vous venez juste de l'ouvrir et que le terminal est encore ouvert, vous pourrez ont toujours la valeur de hachage imprimée par git stash pop à l'écran (merci, Dolda).

Sinon, vous pouvez le trouver en utilisant ceci :

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

Cela vous montrera tous les commits aux extrémités de votre graphe de commit qui ne sont plus référencés par aucune branche ou tag - chaque commit perdu, y compris chaque commit stash que vous avez créé, sera quelque part dans ce graphe.

La façon la plus simple de trouver le commit de la réserve 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 livraison dans le référentiel jamais , qu'il soit atteignable ou non.

Vous pouvez remplacer gitk avec quelque chose comme git log --graph --oneline --decorate si vous préférez un beau graphique sur la console plutôt qu'une application GUI séparée.

Pour repérer les commits stash, recherchez les messages commit de cette forme :

        WIP sur une certaine branche : commithash Un ancien message de commit

Une fois que vous connaissez le hash du commit que vous voulez, vous pouvez l'appliquer comme une cachette :

git stash apply $stash_hash

Ou vous pouvez utiliser le menu contextuel dans gitk pour créer des branches pour tous 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 supprimer ces branches à nouveau.

696voto

Dolda2000 Points 7523

Si vous n'avez pas fermé le terminal, regardez simplement la sortie de git stash pop et vous aurez l'ID de l'objet de la cachette abandonnée. Normalement, ça ressemble à ça :

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

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

Pour récupérer cette cachette, il suffit de lancer git branch tmp 2cae03e et vous l'obtiendrez comme une branche. Pour convertir ceci en une réserve, exécutez :

git stash apply tmp
git stash

Le fait de l'avoir en tant que branche vous permet également de la manipuler librement ; par exemple, de la sélectionner ou de la fusionner.

267voto

Wade Points 1531

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 ça aurait dû l'être), mais pour appliquer le stash à partir de la valeur de hachage, il suffit d'utiliser "git stash apply" :

$ git stash apply ad38abbf76e26c803b27a6079348192d32f52219

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

74voto

Greg Hewgill Points 356191

Je viens de construire une commande qui m'a aidé à retrouver ma cachette perdue :

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 affiche un résumé de chacun d'eux. A partir de là, il suffisait de parcourir les commits pour trouver un "WIP on work : 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", je n'aurais pas de problème. message "alors l'engagement 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

40voto

Nathan Jones Points 1480

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

git cherry-pick -m 1 <sha1> va fusionner le commit sur la branche courante.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X