Comment inverser l'application d'un stash?

233

J'ai un petit patch conservé dans ma cachette git. Je l'ai appliqué à ma copie de travail en utilisant git stash apply. Maintenant, je voudrais annuler ces modifications en appliquant le patch à l'envers (un peu comme ce git revertqui ferait mais contre la cachette).

Est-ce que quelqu'un sait comment faire ça?

Clarification: il y a d'autres changements dans ma copie de travail. Mon cas particulier est difficile à décrire, mais vous pouvez imaginer un code de débogage ou expérimental qui est dans la cachette. Maintenant, il est mélangé dans ma copie de travail avec d'autres modifications et j'aimerais voir l'effet avec et sans les modifications de la cachette.

Il ne semble pas que stash le supporte actuellement, mais ce git stash apply --reverseserait une fonctionnalité intéressante.

Pat Notz
la source
1
Vous ne pouvez pas simplement créer un patch inversé en faisant la différence entre la révision actuelle et la révision précédente? Et puis appliquer celui-là?
ralphtheninja
Y a-t-il des changements dans l'arborescence de travail autres que le stash appliqué?
Greg Bacon
Ajouter ceci ici, ... était censé être une FAQ et non une question ... stackoverflow.com/questions/59973103/…
Don Thomas Boyle

Réponses:

188

Selon la page de manuel git-stash , "Une stash est représentée comme un commit dont l'arborescence enregistre l'état du répertoire de travail, et son premier parent est le commit au HEADmoment où la stash a été créée", et git stash show -pnous donne "les changements enregistrés dans le stash en tant que différence entre l'état stashed et son parent d'origine.

Pour conserver vos autres modifications intactes, utilisez git stash show -p | patch --reversecomme suit:

$ git init
Initialized empty Git repository in /tmp/repo/.git/

$ echo Hello, world >messages

$ git add messages

$ git commit -am 'Initial commit'
[master (root-commit)]: created 1ff2478: "Initial commit"
 1 files changed, 1 insertions(+), 0 deletions(-)
 create mode 100644 messages

$ echo Hello again >>messages

$ git stash

$ git status
# On branch master
nothing to commit (working directory clean)

$ git stash apply
# On branch master
# Changed but not updated:
#   (use "git add <file>..." to update what will be committed)
#   (use "git checkout -- <file>..." to discard changes in working directory)
#
#       modified:   messages
#
no changes added to commit (use "git add" and/or "git commit -a")

$ echo Howdy all >>messages

$ git diff
diff --git a/messages b/messages
index a5c1966..eade523 100644
--- a/messages
+++ b/messages
@@ -1 +1,3 @@
 Hello, world
+Hello again
+Howdy all

$ git stash show -p | patch --reverse
patching file messages
Hunk #1 succeeded at 1 with fuzz 1.

$ git diff
diff --git a/messages b/messages
index a5c1966..364fc91 100644
--- a/messages
+++ b/messages
@@ -1 +1,2 @@
 Hello, world
+Howdy all

Éditer:

Une légère amélioration est à utiliser git applyà la place du patch:

git stash show -p | git apply --reverse

Alternativement, vous pouvez également utiliser git apply -Rcomme raccourci pour git apply --reverse.

J'ai trouvé ça très pratique ces derniers temps ...

Greg Bacon
la source
2
Super merci. On dirait que cela pourrait être une fonctionnalité intéressante pour stash.
Pat Notz
5
Oui, git apply -Rc'est une amélioration, au moins pour moi sur ma boîte Windows avec git bash car j'ai patch --reverseeu des problèmes pour localiser le fichier à patcher (pas vraiment la raison pour laquelle l'alternative a fonctionné). +1 et bonne explication
hakre
ne serait-il pas préférable d'ajouter --indexjuste comme ça git stash show -p | git apply --reverse --index. Parce que vous n'avez plus besoin d'ajouter dans l'index les modifications qui sont annulées.
theUnknown777
3
Bacon @ Greg, hé, j'ai essayé de passer par le script que vous avez décrit, mais le patch a échoué quand je courais git stash show -p | git apply -R -vavec le message: Checking patch messages... error: while searching for: Hello, world Hello again error: patch failed: messages:1. Savez-vous ce qui pourrait mal se passer?
Max Koretskyi
5
Je reçois l' erreur: patch a échoué: /src/filename.java:46 erreur: src / patch filename.java ne s'applique pas
Tim Boland
83

git stash[save]prend votre état de répertoire de travail et votre état d'index et les cache, définissant l'index et la zone de travail sur la HEADversion.

git stash applyramène ces modifications, donc git reset --hardles supprimerait à nouveau.

git stash popramène ces changements et supprime les changements cachés, donc git stash [save]retournerait à l'état précédent (pré-pop) dans ce cas.

Jakub Narębski
la source
83
git checkout -f

supprimera toutes les modifications non validées.

salman
la source
4
merci, vous m'aidez d'un changement par étapes qui n'était pas inapplicable.
Fa.Shapouri
1
C'était beaucoup plus simple
Mark A
C'était génial!
Kiran Sk
22

La page de manuel V1 git contenait une référence sur la non-application d'un stash. L'extrait est ci-dessous.

La page de manuel git V2 plus récente n'inclut aucune référence à la non-application d'un stash mais le ci-dessous fonctionne toujours bien

Non-application d'un Stash Dans certains scénarios de cas d'utilisation, vous souhaiterez peut-être appliquer des modifications stashées, effectuer un certain travail, puis annuler les modifications qui provenaient à l'origine du stash. Git ne fournit pas une telle commande de non-application de stash, mais il est possible d'obtenir l'effet en récupérant simplement le patch associé à une stash et en l'appliquant à l'envers:

$ git stash show -p stash@{0} | git apply -R

Encore une fois, si vous ne spécifiez pas de cachette, Git suppose la cachette la plus récente:

$ git stash show -p | git apply -R

Vous voudrez peut-être créer un alias et ajouter efficacement une commande de stash-unapply à votre Git. Par exemple:

$ git config --global alias.stash-unapply '!git stash show -p | git apply -R'
$ git stash apply
$ #... work work work
$ git stash-unapply
Choco Smith
la source
1
Pour une raison quelconque, cette section utile que vous avez liée à " Désappliquer une cachette " a été supprimée de la 2e version - la dernière version en date est le 2.1.146, 2019-04-15- de ce livre V2- Git Tools - Stashing and Cleaning . Cela pourrait être dû au fait que les auteurs pensent qu'il existe une meilleure façon de procéder que je n'arrive pas à trouver.
Nad Alaba
@NadAlaba merci pour l'avertissement, ont mis à jour la réponse pour noter la différence entre v1 et v2 ... bizarre, les auteurs de git ont supprimé la section sur la non-application d'une cachette
Choco Smith
13

Cela fait trop longtemps, mais si j'interprète correctement le problème, j'ai trouvé une solution simple, notez, ceci est une explication dans ma propre terminologie:

git stash [save] enregistrera les modifications actuelles et mettra votre branche actuelle en "état propre"

git stash list donne quelque chose comme: stash@{0}: On develop: saved testing-stuff

git apply stash@{0}définira la branche actuelle comme auparavant stash [save]

git checkout .Définira la branche actuelle comme après stash [save]

Le code qui est enregistré dans la cachette n'est pas perdu, il peut être retrouvé par git apply stash@{0}.

Quoi qu'il en soit, cela a fonctionné pour moi!

Slim Sim
la source
Juste pour être sûr, j'ai appliqué une git stash apply --reversepremière, puis je suis simplement revenu sur ce git stash apply stash@{x}que vous mentionnez. Fonctionné sans problème.
Carlos Garcia
3

Comment inverser l'application d'un stash?

En dehors de ce que d'autres ont mentionné, le moyen le plus simple consiste à

git reset HEAD

puis vérifier tous les changements locaux

git checkout . 
Achal
la source
C'est de loin le moyen le plus simple tant que vous n'avez absolument aucun travail local que vous souhaitez enregistrer. Si vous avez appliqué le mauvais stash à une branche ou que vous avez résolu les conflits de fusion que vous ne voulez pas résoudre, c'est le moyen rapide et facile de le annuler en rétablissant complètement votre jeu de travail au dernier commit de votre branche.
Shadoninja
2

En plus de la réponse @Greg Bacon, dans le cas où des fichiers binaires étaient ajoutés à l'index et faisaient partie de la cachette en utilisant

git stash show -p | git apply --reverse

peut entraîner

error: cannot apply binary patch to '<YOUR_NEW_FILE>' without full index line
error: <YOUR_NEW_FILE>: patch does not apply

L'ajout --binaryrésout le problème, mais n'a malheureusement pas encore compris pourquoi.

 git stash show -p --binary | git apply --reverse
MHosafy
la source
1

Vous pouvez suivre l'image que j'ai partagée pour la décompresser si vous avez accidentellement appuyé sur la dissimulation.

Amanpreet Singh
la source
0

Ceci s'ajoute aux réponses ci-dessus, mais ajoute la recherche de la cachette git en fonction du message, car le numéro de cachette peut changer lorsque de nouvelles cachettes sont enregistrées. J'ai écrit quelques fonctions bash:

apply(){
  if [ "$1" ]; then
    git stash apply `git stash list | grep -oPm1 "(.*)(?=:.*:.*$1.*)"`
  fi
}
remove(){
  if [ "$1" ]; then
    git stash show -p `git stash list | grep -oPm1 "(.*)(?=:.*:.*$1.*)"` | git apply -R
    git status
  fi
}
  1. Créer une cachette avec un nom (message) $ git stash save "my stash"
  2. À nommer $ apply "my stash"
  3. Pour supprimer le cache nommé $ remove "my stash"
durée de vie
la source