Jako dodatkowe wyjaśnienie zwróć uwagę, że git stashpowoduje to dwa lub trzy zatwierdzenia. Wartość domyślna to dwa; otrzymasz trzy, jeśli użyjesz pisowni opcji --alllub --include-untracked.
Te dwa lub trzy zatwierdzenia są wyjątkowe pod jednym ważnym względem: nie znajdują się na żadnej gałęzi. Git lokalizuje je za pomocą specjalnej nazwy stash. 1 Najważniejsze jest jednak to, co Git pozwala - i sprawia, że - robisz z tymi dwoma lub trzema zatwierdzeniami. Aby to zrozumieć, musimy przyjrzeć się temu, co jest w tych zatwierdzeniach.
Co jest w skrytce
Każde zatwierdzenie może zawierać jedno lub więcej zatwierdzeń nadrzędnych . Tworzą one wykres, na którym późniejsze zatwierdzenia wskazują na wcześniejsze. Skrytka normalnie zawiera dwa zatwierdzenia, które lubię wywoływać w iprzypadku zawartości indeksu / obszaru przemieszczania oraz zawartości wdrzewa roboczego. Pamiętaj również, że każde zatwierdzenie zawiera migawkę. W normalnym zatwierdzeniu ten obraz stanu jest tworzony z zawartości indeksu / obszaru przemieszczania. Zatem izatwierdzenie jest w rzeczywistości całkowicie normalnym zatwierdzeniem! Po prostu nie ma go na żadnej gałęzi:
...--o--o--o <-- branch (HEAD)
|
i
Jeśli robisz zwykły magazyn, git stashkod robi to wteraz, kopiując wszystkie śledzone pliki drzewa roboczego (do tymczasowego indeksu pomocniczego). Git ustawia pierwszego rodzica tego wzatwierdzenia, aby wskazywał na HEADzatwierdzenie, a drugi rodzic, aby wskazywał na zatwierdzenie i. Na koniec stashwskazuje na to wzatwierdzenie:
...--o--o--o <-- branch (HEAD)
|\
i-w <-- stash
Jeśli dodasz --include-untrackedlub --all, Git wykona dodatkowe zatwierdzenie, upomiędzy tworzeniem ii w. Zawartością migawki usą te pliki, które nie są śledzone, ale nie są ignorowane ( --include-untracked) lub pliki, które nie są śledzone, nawet jeśli są ignorowane ( --all). Ten dodatkowy upopełnić ma żadnego rodzica, a następnie, gdy git stashmarki w, ustawia w„s trzeciego rodzica tego udokonać, aby uzyskać:
...--o--o--o <-- branch (HEAD)
|\
i-w <-- stash
/
u
W tym momencie Git usuwa również wszystkie pliki drzewa roboczego, które znalazły się w uzatwierdzeniu (używając git cleando tego).
Przywracanie skrytki
Kiedy idziesz odzyskać skrytkę, możesz jej użyć --indexlub nie. To mówi git stash apply(lub któregokolwiek z poleceń, które używają wewnętrznie apply, jak pop), że powinien on używaći popełnić próbować zmodyfikować swój aktualny indeks. Ta modyfikacja jest wykonywana za pomocą:
git diff <hash-of-i> <hash-of-i's-parent> | git apply --index
(mniej więcej; jest kilka drobiazgów, które przeszkadzają w realizacji podstawowej idei).
Jeśli pominiesz --index, git stash applycałkowicie zignoruje izatwierdzenie.
Jeśli skrytka ma tylko dwa zatwierdzenia, git stash applymoże teraz zastosować wzatwierdzenie. Robi to przez wywołanie git merge2 (bez zezwalania na zatwierdzenie lub traktowanie wyniku jako normalnego scalania), używając oryginalnego zatwierdzenia, na którym został utworzony schowek ( irodzica i wpierwszego rodzica) jako podstawy scalania, wjako --theirscommit, a Twoje aktualne (HEAD) commit jako cel scalenia. Jeśli połączenie się powiedzie, wszystko jest w porządku - cóż, przynajmniej tak uważa Git - i git stash applysamo się powiedzie. Jeśli git stash popużywałeś skrytki, kod teraz ją upuszcza . 3 Jeśli scalanie nie powiedzie się, Git deklaruje, że zastosowanie nie powiodło się. Jeśli użyłeśgit stash pop, kod zachowuje skrytkę i dostarcza ten sam stan błędu, co w przypadku git stash apply.
Ale jeśli masz trzecie zatwierdzenie - jeśli uw skrytce, którą stosujesz, jest zatwierdzenie - wszystko się zmienia! Nie ma możliwości udawania, że uzatwierdzenie nie istnieje. 4 Git nalega na wyodrębnienie wszystkich plików z tego uzatwierdzenia do bieżącego drzewa roboczego. Oznacza to, że pliki nie mogą w ogóle istnieć lub mieć taką samą zawartość, jak w uzatwierdzeniu.
Aby to się stało, możesz użyć git cleansiebie - ale pamiętaj, że nieśledzone pliki (zignorowane lub nie) nie istnieją w repozytorium Git, więc upewnij się, że wszystkie te pliki można zniszczyć! Możesz też utworzyć katalog tymczasowy i przenieść tam pliki na przechowanie - lub nawet zrobić inny git stash save -ulub git stash save -a, ponieważ będą one działać git cleanza Ciebie. Ale to po prostu pozostawia ci inny ustyl, którym możesz zająć się później.
1 Tak jest w rzeczywistości refs/stash. Ma to znaczenie, jeśli utworzysz gałąź o nazwie stash: pełna nazwa gałęzi to refs/heads/stash, więc nie są one w konflikcie. Ale nie rób tego: Git nie będzie miał nic przeciwko, ale będziesz się mylić. :-)
2git stash kod faktycznie korzysta git merge-recursivebezpośrednio tutaj. Jest to konieczne z wielu powodów, a także ma efekt uboczny polegający na tym, że Git nie traktuje tego jako scalenia podczas rozwiązywania konfliktów i zatwierdzania.
3 Dlatego też zalecamy unikanie git stash pop, na korzyść git stash apply. Masz szansę przejrzeć, co zostało zastosowane, i zdecydować, czy faktycznie zostało zastosowane poprawnie. Jeśli nie, nadal masz swoją skrytkę, co oznacza, że możesz jej użyć git stash branchdo perfekcyjnego odzyskania wszystkiego. Cóż, zakładając brak tego nieznośnego uzobowiązania.
4 Naprawdę powinno być: git stash apply --skip-untrackedczy coś. Powinien też istnieć wariant, który oznaczałby upuszczenie wszystkich tych uplików ze zmianami do nowego katalogu , np git stash apply --untracked-into <dir>. Być może.
git stash show -p | git apply --3