Come invertire applicare una scorta?


233

Ho una piccola patch salvata nella mia scorta di git. L'ho applicato alla mia copia di lavoro utilizzando git stash apply. Ora, vorrei annullare quei cambiamenti applicando la patch in senso inverso (un po 'come quello che git revertfarebbe ma contro la scorta).

Qualcuno sa come fare questo?

Chiarimento: ci sono altre modifiche nella mia copia di lavoro. Il mio caso particolare è difficile da descrivere, ma puoi immaginare un codice di debug o sperimentale che è nella scorta. Ora è mescolato nella mia copia di lavoro con alcune altre modifiche e mi piacerebbe vedere l'effetto con e senza le modifiche dalla scorta.

Al momento non sembra che stash lo supporti, ma git stash apply --reversesarebbe una bella funzionalità.


1
Non puoi semplicemente creare una patch inversa differendo tra la revisione attuale e quella precedente? E poi applicare quello?
ralphtheninja,

Ci sono cambiamenti nell'albero di lavoro diversi dalla scorta applicata?
Greg Bacon,

Aggiungendo questo qui, ... doveva essere una FAQ non una domanda ... stackoverflow.com/questions/59973103/…
Don Thomas Boyle

Risposte:


188

Secondo la manpage git-stash , "Uno stash è rappresentato come un commit il cui albero registra lo stato della directory di lavoro, e il suo primo genitore è il commit al HEADmomento della creazione dello stash" e git stash show -pci fornisce "le modifiche registrate nel stash come diff tra lo stato stashed e il suo genitore originale.

Per mantenere intatte le altre modifiche, utilizzare git stash show -p | patch --reversecome segue:

$ 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

Modificare:

Un leggero miglioramento a questo è quello di utilizzare git applyal posto della patch:

git stash show -p | git apply --reverse

In alternativa, puoi anche usare git apply -Runa scorciatoia per git apply --reverse.

L'ho trovato davvero utile ultimamente ...


2
Fantastico, grazie. Sembra che questa potrebbe essere una bella caratteristica per lo stash.
Pat Notz,

5
Sì, git apply -Rè un miglioramento, almeno per me sulla mia finestra di Windows con Git Bash in quanto ha patch --reverseavuto problemi a individuare il file da correggere (nessun vero indizio sul motivo per cui l'alternativa ha funzionato). +1 e buona spiegazione
hakre,

non sarebbe meglio aggiungere --indexproprio così git stash show -p | git apply --reverse --index. Perché non è più necessario aggiungere nell'indice le modifiche ripristinate.
theUnnown777

3
@ Greg Bacon, hey, ho cercato di passare attraverso lo script che avete descritto, ma la patch non è riuscita quando mi sono imbattuto git stash show -p | git apply -R -vcon il messaggio: Checking patch messages... error: while searching for: Hello, world Hello again error: patch failed: messages:1. Sai cosa potrebbe esserci di sbagliato?
Max Koretskyi,

5
Ottengo l' errore: patch non riuscita: errore
Tim Boland

83

git stash[save]prende lo stato della directory di lavoro e lo stato dell'indice e li nasconde, impostando l'indice e l'area di lavoro alla HEADversione.

git stash applyriporta quei cambiamenti, quindi git reset --hardli rimuoverò di nuovo.

git stash popriporta quelle modifiche e rimuove le modifiche principali, in questo git stash [save]caso tornerebbe allo stato precedente (pre-pop).


82
git checkout -f

rimuoverà eventuali modifiche senza commit.


4
grazie, mi aiuti dal cambiamento in scena che non era non applicabile.
Fa.Shapouri,

1
Questo è stato molto più semplice
Mark A

È stato fantastico!
Kiran Sk,

22

La pagina man di V1 git conteneva un riferimento sulla non applicazione di una scorta. L'estratto è sotto.

La nuova pagina man di Git V2 non include alcun riferimento a non applicare uno stash ma il seguito funziona ancora bene

Annullamento dell'applicazione di uno stash In alcuni scenari di casi d'uso, è possibile che si desideri applicare modifiche stash, eseguire alcune operazioni, quindi annullare l'applicazione delle modifiche originate dallo stash. Git non fornisce un comando di non-applicazione tale stash, ma è possibile ottenere l'effetto semplicemente recuperando la patch associata a una stash e applicandola al contrario:

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

Ancora una volta, se non specifichi uno stash, Git assume lo stash più recente:

$ git stash show -p | git apply -R

Potresti voler creare un alias e aggiungere efficacemente un comando stash-unpply a Git. Per esempio:

$ git config --global alias.stash-unapply '!git stash show -p | git apply -R'
$ git stash apply
$ #... work work work
$ git stash-unapply

1
Per qualunque motivo questa utile sezione che hai collegato "Non applicare uno Stash" è stata rimossa dalla 2a versione -Latest version now is 2.1.146, 2019-04-15- of this book V2- Git Tools - Stashing and Cleaning . Potrebbe essere perché gli autori pensano che ci sia un modo migliore per farlo che non riesco a trovare.
Nad Alaba,

@NadAlaba grazie per l'heads-up, ho aggiornato la risposta per prendere nota della differenza tra v1 e v2 ... strano che gli autori di git hanno rimosso la sezione sulla non applicazione di una scorta
Choco Smith

13

Questo è da tempo, ma se interpreto correttamente il problema ho trovato una soluzione semplice, nota, questa è una spiegazione nella mia terminologia:

git stash [save] salverà le modifiche correnti e imposterà il ramo corrente sullo "stato pulito"

git stash list dà qualcosa come: stash@{0}: On develop: saved testing-stuff

git apply stash@{0}imposterà il ramo corrente come prima stash [save]

git checkout .Imposta il ramo corrente come dopo stash [save]

Il codice che viene salvato nella scorta non viene perso, ma può essere trovato di git apply stash@{0}nuovo.

Comunque, questo ha funzionato per me!


Giusto per essere sicuro, ho applicato un git stash apply --reverseprimo e poi semplicemente sono tornato git stash apply stash@{x}come mi hai detto. Ha funzionato senza problemi.
Carlos Garcia,

3

Come invertire applicare una scorta?

A parte ciò che altri hanno menzionato, il modo più semplice è prima di tutto

git reset HEAD

e quindi controlla tutte le modifiche locali

git checkout . 

Questo è di gran lunga il modo più semplice finché non hai assolutamente lavoro locale da salvare. Se hai applicato lo stash sbagliato a un ramo o hai colpito conflitti di unione che non vuoi risolvere, questo è il modo semplice e veloce per annullarlo ripristinando completamente il tuo working set all'ultimo commit del tuo ramo.
Shadoninja,

2

Oltre alla risposta @Greg Bacon, nel caso in cui i file binari fossero aggiunti all'indice e facessero parte dello stash usando

git stash show -p | git apply --reverse

può comportare

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

L'aggiunta --binaryrisolve il problema, ma sfortunatamente non ho ancora capito perché.

 git stash show -p --binary | git apply --reverse

1

È possibile seguire l'immagine che ho condiviso per decomprimerlo se si toccava accidentalmente lo stash.


0

Ciò si aggiunge alle risposte precedenti ma aggiunge la ricerca dello stash git in base al messaggio poiché il numero di stash può cambiare quando vengono salvati nuovi stash. Ho scritto un paio di funzioni 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. Crea stash con nome (messaggio) $ git stash save "my stash"
  2. Applicare nome $ apply "my stash"
  3. Per rimuovere lo stash denominato $ remove "my stash"
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.