Miałem kilka zmian etapowych i niestacjonarnych i chciałem szybko przełączyć się na inną gałąź, a następnie z powrotem.
Więc inscenizowałem swoje zmiany za pomocą:
$ git stash push -a
(Z perspektywy czasu prawdopodobnie mógłbym użyć --include-untracked
zamiast --all
)
Potem, kiedy poszedłem do schowka, dostaję mnóstwo błędów w rodzaju:
$ git stash pop
foo.txt already exists, no checkout
bar.txt already exists, no checkout
...
Could not restore untracked files from stash entry
Wygląda na to, że ze skrytki nie przywrócono żadnych zmian.
Też próbowałem, $ git stash branch temp
ale to pokazuje te same błędy.
Znalazłem sposób na obejście tego, którego miałem użyć:
$ git stash show -p | git apply
Na razie uniknięto katastrofy, ale to rodzi pewne pytania.
Dlaczego ten błąd wystąpił w pierwszej kolejności i jak mogę go uniknąć następnym razem?
git stash show -p | git apply --3
git stash show
i ponad plików ratowniczych jeden po drugim:$ git show stash@{0}:your/stashed/file.txt > your_rescued_file.txt
. Spowoduje to pobranie pliku ze skrytki i zapisanie go pod inną nazwą. Teraz możesz bezpiecznie eksperymentować z odpowiednimi metodami ratunkowymi (patrz odpowiedzi poniżej). Jeśli coś pójdzie nie tak, zawsze masz uratowane pliki jako ostatni zasób.Odpowiedzi:
Jako dodatkowe wyjaśnienie zwróć uwagę, że
git stash
powoduje to dwa lub trzy zatwierdzenia. Wartość domyślna to dwa; otrzymasz trzy, jeśli użyjesz pisowni opcji--all
lub--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
i
przypadku zawartości indeksu / obszaru przemieszczania oraz zawartościw
drzewa 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. Zatemi
zatwierdzenie jest w rzeczywistości całkowicie normalnym zatwierdzeniem! Po prostu nie ma go na żadnej gałęzi:Jeśli robisz zwykły magazyn,
git stash
kod robi tow
teraz, kopiując wszystkie śledzone pliki drzewa roboczego (do tymczasowego indeksu pomocniczego). Git ustawia pierwszego rodzica tegow
zatwierdzenia, aby wskazywał naHEAD
zatwierdzenie, a drugi rodzic, aby wskazywał na zatwierdzeniei
. Na koniecstash
wskazuje na tow
zatwierdzenie:Jeśli dodasz
--include-untracked
lub--all
, Git wykona dodatkowe zatwierdzenie,u
pomiędzy tworzeniemi
iw
. Zawartością migawkiu
są 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 dodatkowyu
popełnić ma żadnego rodzica, a następnie, gdygit stash
markiw
, ustawiaw
„s trzeciego rodzica tegou
dokonać, aby uzyskać:W tym momencie Git usuwa również wszystkie pliki drzewa roboczego, które znalazły się w
u
zatwierdzeniu (używającgit clean
do tego).Przywracanie skrytki
Kiedy idziesz odzyskać skrytkę, możesz jej użyć
--index
lub nie. To mówigit stash apply
(lub któregokolwiek z poleceń, które używają wewnętrznieapply
, jakpop
), że powinien on używaći
popełnić próbować zmodyfikować swój aktualny indeks. Ta modyfikacja jest wykonywana za pomocą:(mniej więcej; jest kilka drobiazgów, które przeszkadzają w realizacji podstawowej idei).
Jeśli pominiesz
--index
,git stash apply
całkowicie zignorujei
zatwierdzenie.Jeśli skrytka ma tylko dwa zatwierdzenia,
git stash apply
może teraz zastosowaćw
zatwierdzenie. Robi to przez wywołaniegit merge
2 (bez zezwalania na zatwierdzenie lub traktowanie wyniku jako normalnego scalania), używając oryginalnego zatwierdzenia, na którym został utworzony schowek (i
rodzica iw
pierwszego rodzica) jako podstawy scalania,w
jako--theirs
commit, 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 - igit stash apply
samo się powiedzie. Jeśligit stash pop
uż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 przypadkugit stash apply
.Ale jeśli masz trzecie zatwierdzenie - jeśli
u
w skrytce, którą stosujesz, jest zatwierdzenie - wszystko się zmienia! Nie ma możliwości udawania, żeu
zatwierdzenie nie istnieje. 4 Git nalega na wyodrębnienie wszystkich plików z tegou
zatwierdzenia do bieżącego drzewa roboczego. Oznacza to, że pliki nie mogą w ogóle istnieć lub mieć taką samą zawartość, jak wu
zatwierdzeniu.Aby to się stało, możesz użyć
git clean
siebie - 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ć innygit stash save -u
lubgit stash save -a
, ponieważ będą one działaćgit clean
za Ciebie. Ale to po prostu pozostawia ci innyu
styl, którym możesz zająć się później.1 Tak jest w rzeczywistości
refs/stash
. Ma to znaczenie, jeśli utworzysz gałąź o nazwiestash
: pełna nazwa gałęzi torefs/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ć. :-)2
git stash
kod faktycznie korzystagit merge-recursive
bezpoś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 branch
do perfekcyjnego odzyskania wszystkiego. Cóż, zakładając brak tego nieznośnegou
zobowiązania.4 Naprawdę powinno być:
git stash apply --skip-untracked
czy coś. Powinien też istnieć wariant, który oznaczałby upuszczenie wszystkich tychu
plików ze zmianami do nowego katalogu , npgit stash apply --untracked-into <dir>
. Być może.źródło
--index
:git stash apply --index
?git stash save --all
, potem natychmiast to zrobiłemgit stash apply
, ale niektórych plików brakowało, ponieważ zmieniłem ich nazwy, a następnie utworzyłem ponownie (przed przechowywaniem). Pomogło:git checkout stash@{0} -- .
nawet nie będę się tym przejmować,git checkout stash^3 -- .
ponieważ teraz wszystko wydaje się OK. Szkoda, że nie mam czasu, aby naprawdę zrozumieć, co się dzieje. Dzięki.Udało mi się odtworzyć Twój problem. Wygląda na to, że jeśli ukryjesz niezamierzone pliki, a następnie utworzysz te pliki (w swoim przykładzie
foo.txt
ibar.txt
), będziesz mieć lokalne zmiany w nieśledzonych plikach, które zostaną nadpisane po zastosowaniugit stash pop
.Aby obejść ten problem, możesz użyć następującego polecenia. Spowoduje to zastąpienie wszelkich niezapisanych zmian lokalnych, więc bądź ostrożny.
Oto dodatkowe informacje, które znalazłem na temat poprzedniego polecenia .
źródło
--all
/-a
będzie obejmować ignorowane pliki , więc może to być istotne.git merge --squash --strategy-option=theirs stash
w tym przypadku podejście jest lepsze).already exists, no checkout
), sprawdź moją odpowiedź poniżej.Aby rozwinąć odpowiedź Daniela Smitha : ten kod przywraca tylko śledzone pliki, nawet jeśli użyłeś
--include-untracked
(lub-u
) podczas tworzenia skrytki. Wymagany pełny kod to:git checkout stash -- . git checkout stash^3 -- . git stash drop # Optional to unstage the changes (auto-staged by default). git reset
To w pełni przywraca śledzoną zawartość (in
stash
) i nieśledzoną zawartość (instash^3
), a następnie usuwa skrytkę. Kilka uwag:git checkout
powoduje, że wszystkie stają się automatyczniegit reset
przemieszczane , więc dodałem, aby wszystko usunąć ze sceny.stash@{0}
astash@{0}^3
podczas moich testów działa tak samo z lub bez@{0}
Źródła:
stash^3
zatwierdzeniu)źródło
oprócz innych odpowiedzi zrobiłem małą sztuczkę
git stash apply
(można użyć dowolnego polecenia, np. zastosuj, pop itp.)źródło