Jak cofnąć zastosowanie skrytki?

233

Mam małą łatkę zapisaną w mojej skrytce git. Zastosowałem go do mojej kopii roboczej za pomocą git stash apply. Teraz chciałbym wycofać się z tych zmian, odwrotnie stosując łatkę (coś w rodzaju tego git revert, co by zrobił, gdyby nie skrytka).

Czy ktoś wie jak to zrobić?

Wyjaśnienie: Istnieją inne zmiany w mojej kopii roboczej. Mój konkretny przypadek jest trudny do opisania, ale możesz sobie wyobrazić jakiś debugujący lub eksperymentalny kod, który jest w skrytce. Teraz jest mieszany w mojej kopii roboczej z kilkoma innymi zmianami i chciałbym zobaczyć efekt ze zmianami ukrytymi i bez nich.

Nie wygląda na to, że skrytka obsługuje to obecnie, ale git stash apply --reversebyłaby to miła funkcja.

Pat Notz
źródło
1
Czy nie można po prostu utworzyć odwróconej łatki, różnicując bieżącą i poprzednią wersję? A następnie zastosować ten?
ralphtheninja
Czy w drzewie roboczym występują zmiany inne niż zastosowana skrytka?
Greg Bacon
Dodanie tego tutaj ... miało być FAQ, a nie pytaniem ... stackoverflow.com/questions/59973103/
Don Thomas Boyle

Odpowiedzi:

188

Według strony podręcznika git-stash: „Skrytka jest reprezentowana jako zatwierdzenie, którego drzewo rejestruje stan katalogu roboczego, a jej pierwszy element nadrzędny jest zatwierdzeniem w HEADmomencie utworzenia skrytki” i git stash show -pdaje nam „zmiany zapisane w ukryj jako różnicę między stanem ukrytym a jego pierwotnym elementem nadrzędnym.

Aby zachować pozostałe zmiany w nienaruszonym stanie, wykonaj git stash show -p | patch --reversenastępujące czynności:

$ 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

Edytować:

Lekkim ulepszeniem tego jest użycie git applyzamiast łatki:

git stash show -p | git apply --reverse

Możesz także użyć git apply -Rjako skrótu do git apply --reverse.

Ostatnio bardzo mi się to przydaje ...

Greg Bacon
źródło
2
Wielkie dzieki. Wygląda na to, że może to być fajna funkcja do przechowywania.
Pat Notz
5
Tak, git apply -Rjest poprawą, przynajmniej dla mnie na moim oknie z git bash, ponieważ patch --reversemiał problemy z lokalizacją pliku do łatania (brak prawdziwej wskazówki, dlaczego alternatywa działała). +1 i dobre wyjaśnienie
hakre
Czy nie byłoby lepiej, aby dodać --indextak jak ten git stash show -p | git apply --reverse --index. Ponieważ nie trzeba już dodawać do indeksu zmian cofniętych z powrotem.
theNieznany777
3
@Greg Bacon, hej, próbowałem przejść przez skrypt, który przedstawionym, ale patch nie powiodła kiedy wpadłem git stash show -p | git apply -R -vz komunikatem: Checking patch messages... error: while searching for: Hello, world Hello again error: patch failed: messages:1. Czy wiesz, co może być nie tak?
Max Koretskyi
5
Pojawia się błąd: poprawka nie powiodła się: /src/nazwa_pliku.java:46 błąd: src / nazwa_pliku.java nie dotyczy
Tim Boland
83

git stash[save]pobiera stan katalogu roboczego i stan indeksu i ukrywa je, ustawiając indeks i obszar roboczy na HEADwersję.

git stash applyprzywraca te zmiany, więc git reset --hardusunęłoby je ponownie.

git stash popprzywraca te zmiany i usuwa najbardziej ukrytą zmianę, więc w takim git stash [save]przypadku powróciłby do poprzedniego stanu (przed popem).

Jakub Narębski
źródło
82
git checkout -f

usunie wszelkie zmiany niezwiązane z zatwierdzeniem.

Salman
źródło
4
dzięki, pomagasz mi od etapowej zmiany, która nie była niestosowna.
Fa.Shapouri
1
To było o wiele prostsze
Mark A
To było niesamowite!
Kiran Sk
22

Strona podręcznika git w wersji V1 zawierała odniesienie do cofania stosowania skrytki. Fragment znajduje się poniżej.

Nowsza strona git man V2 nie zawiera żadnych odniesień do cofania stosowania skrytki, ale poniższe działania nadal działają dobrze

Cofanie zastosowania skrytki W niektórych scenariuszach przypadków użycia możesz chcieć zastosować zmiany ukryte, wykonać trochę pracy, ale potem cofnąć stosowanie tych zmian, które pierwotnie pochodziły ze skrytki. Git nie udostępnia polecenia cofnięcia zastosowania skrytki, ale można osiągnąć ten efekt, po prostu pobierając łatkę związaną ze skrytką i stosując ją w odwrotnej kolejności:

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

Ponownie, jeśli nie określisz skrytki, Git zakłada najnowszą skrytkę:

$ git stash show -p | git apply -R

Możesz utworzyć alias i skutecznie dodać do swojego Git polecenie ukrywania-niestosowania. Na przykład:

$ git config --global alias.stash-unapply '!git stash show -p | git apply -R'
$ git stash apply
$ #... work work work
$ git stash-unapply
Choco Smith
źródło
1
Bez względu na przyczynę ta pomocna sekcja, którą podłączyłeś „Nieużywanie skrytki ” została usunięta z 2. wersji - najnowsza wersja to 2.1.146, 15.04.2019 - tej książki V2 - Narzędzia Git - Składowanie i czyszczenie . Może dlatego, że autorzy uważają, że istnieje lepszy sposób, aby tego nie znaleźć.
Nad Alaba,
@NadAlaba dzięki za heads-upy, zaktualizowałem odpowiedź, aby zanotować różnicę między wersją v1 i v2 ... dziwne, że autorzy git usunęli rozdział o nie stosowaniu skrytki
Choco Smith
13

To już dawno minęło, ale jeśli poprawnie interpretuję problem, znalazłem proste rozwiązanie, zauważ, że to wyjaśnienie w mojej własnej terminologii:

git stash [save] zapisze bieżące zmiany i ustawi swój aktualny oddział na „czysty stan”

git stash list daje coś takiego: stash@{0}: On develop: saved testing-stuff

git apply stash@{0}ustawi dotychczasową gałąź jak poprzednio stash [save]

git checkout .Ustawi obecny oddział jak później stash [save]

Kod zapisany w skrytce nie zostanie utracony, można go znaleźć git apply stash@{0}ponownie.

W każdym razie to zadziałało dla mnie!

Slim Sim
źródło
Dla pewności git stash apply --reversenajpierw złożyłem aplikację, a potem po prostu wróciłem do tego git stash apply stash@{x}, o czym wspomniałeś. Pracowałem bez problemów.
Carlos Garcia
3

Jak cofnąć zastosowanie skrytki?

Oprócz tego, co wspomnieli inni, najpierw najłatwiej jest to zrobić

git reset HEAD

a następnie sprawdź wszystkie zmiany lokalne

git checkout . 
Achal
źródło
Jest to zdecydowanie najłatwiejszy sposób, o ile nie masz absolutnie żadnej pracy lokalnej, którą chciałbyś zaoszczędzić. Jeśli zastosowałeś niewłaściwe ukrywanie do gałęzi lub konflikty scalania trafień, których nie chcesz rozwiązać, jest to szybki i łatwy sposób na cofnięcie go przez całkowite przywrócenie zestawu roboczego do ostatniego zatwierdzenia oddziału.
Shadoninja
2

Oprócz odpowiedzi @Greg Bacon, w przypadku gdy pliki binarne zostały dodane do indeksu i były częścią skrytki za pomocą

git stash show -p | git apply --reverse

może spowodować

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

Dodanie --binaryrozwiązuje problem, ale niestety jeszcze nie dowiedzieliśmy się, dlaczego.

 git stash show -p --binary | git apply --reverse
MHosafi
źródło
0

Jest to dodatek do powyższych odpowiedzi, ale dodaje wyszukiwanie skrytki git na podstawie wiadomości, ponieważ numer skrytki może się zmienić po zapisaniu nowych skrytek. Napisałem kilka funkcji 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. Utwórz skrytkę z nazwą (wiadomość) $ git stash save "my stash"
  2. Aby zastosować nazwany $ apply "my stash"
  3. Aby usunąć nazwaną skrytkę $ remove "my stash"
niezwykłe życie
źródło
0

Możesz podążać za obrazem, który udostępniłem, aby odblokować, jeśli przypadkowo stuknąłeś ukrywanie.

Amanpreet Singh
źródło