git stash blunder: git stash pop i zakończył się konfliktami scalania

200

Zrobiłem git stash popi skończyłem z konfliktami scalania. Usunąłem pliki z systemu plików i zrobiłem to git checkouttak, jak pokazano poniżej, ale wydaje się, że pliki nadal nie są scalone. Następnie spróbowałem zastąpić pliki i git checkoutpowtórzyć ten sam wynik. Próbowałem wymusić to -fflagą. Każda pomoc będzie mile widziana!

chirag-patels-macbook-pro:haloror patelc75$ git status
app/views/layouts/_choose_patient.html.erb: needs merge
app/views/layouts/_links.html.erb: needs merge
# On branch prod-temp
# Changes to be committed:
#   (use "git reset HEAD <file>..." to unstage)
#
#       modified:   db/schema.rb
#
# Changed but not updated:
#   (use "git add <file>..." to update what will be committed)
#   (use "git checkout -- <file>..." to discard changes in working directory)
#
#       unmerged:   app/views/layouts/_choose_patient.html.erb
#       unmerged:   app/views/layouts/_links.html.erb

chirag-patels-macbook-pro:haloror patelc75$ git checkout app/views/layouts/_choose_patient.html.erb
error: path 'app/views/layouts/_choose_patient.html.erb' is unmerged
chirag-patels-macbook-pro:haloror patelc75$ git checkout -f app/views/layouts/_choose_patient.html.erb
warning: path 'app/views/layouts/_choose_patient.html.erb' is unmerged
Chirag Patel
źródło
Uwaga: przywrócenie stanu przedgit stash apply/pop powinno być łatwiejsze z Git 2,5 (Q2 2015), ponieważ drzewo pracuje teraz musi być czyste: zobacz moją odpowiedź poniżej
VonC

Odpowiedzi:

219

Zobacz man git merge ( JAK ROZWIĄZYWAĆ KONFLIKTY ):

Po obejrzeniu konfliktu możesz zrobić dwie rzeczy:

  • Zdecyduj się nie łączyć. Jedyne potrzebne oczyszczenia to zresetowanie pliku indeksu do zatwierdzenia HEAD w celu cofnięcia 2. i wyczyszczenie zmian w drzewku roboczym dokonanych przez 2. i 3 .; git-reset - można do tego użyć twardego.

  • Rozwiąż konflikty. Git zaznaczy konflikty w działającym drzewie. Zmodyfikuj pliki do kształtu i dodaj je do indeksu. Użyj git commit, aby przypieczętować umowę.

I w ramach PRAWDZIWEGO POŁĄCZENIA (aby zobaczyć, do czego odnoszą się 2. i 3.):

Kiedy nie jest oczywiste, jak pogodzić zmiany, dzieje się tak:

  1. Wskaźnik HEAD pozostaje taki sam.

  2. Referencja MERGE_HEAD jest ustawiona tak, aby wskazywała na drugą głowę oddziału.

  3. Ścieżki, które zostały scalone w sposób czysty, są aktualizowane zarówno w pliku indeksu, jak iw drzewie roboczym.

  4. ...

Tak więc: użyj, git reset --hardjeśli chcesz usunąć zmiany ukryte w działającym drzewie, lub git resetjeśli chcesz po prostu wyczyścić indeks i pozostawić konflikty w działającym drzewie do scalenia ręcznie.

Pod man git stash ( OPCJE, pop ) możesz przeczytać dodatkowo:

Stosowanie stanu może zakończyć się niepowodzeniem w przypadku konfliktów; w takim przypadku nie jest usuwany z listy skrytek. Musisz rozwiązać konflikty ręcznie i później ręcznie wywołać zrzut git.

tanascius
źródło
9
W rzeczywistości, nawet po upuszczeniu skrytki, nadal jest możliwe (choć trudniejsze) jej odzyskanie, ponieważ zestaw zmian nadal istnieje w repozytorium. stackoverflow.com/search?q=git+recover+dropped+stash
phils
3
@nalply: czy to dobrze czy źle? Zachęcam do poprawienia mojej odpowiedzi, w której przede wszystkim jej nie zrozumiałeś ...
tanascius
1
Myślę, że rewizja kodu źródłowego jest złożoną domeną problemową. Łatwo się pomylić. Nadal uważam, że twoja odpowiedź jest dobra, ponieważ potwierdziła moje podejście.
dokładnie
1
Nie tylko bardzo pomogło mi uświadomić sobie, że skrytka nie została usunięta, jak zakładałem, ale to wyjaśnia, dlaczego moja skrytka rosła, nawet gdy byłem pewien, że nie zapomniałem odzyskać z niej rzeczy.
Thor84no
11
„Zastosowanie stanu może zakończyć się niepowodzeniem w przypadku konfliktów; w takim przypadku nie jest usuwane z listy ukrytych”. To, moim zdaniem, najważniejsza część tego wpisu. Zastanów się nad edytowaniem swojej odpowiedzi, aby umieścić ją na początku wraz ze słowem DON'T PANIC dużymi, przyjaznymi literami. (+1 już.) Dzięki.
Patrick M
42

Przydarzyło mi się coś podobnego. Nie chciałem jeszcze przygotowywać plików, więc dodałem je git addi dopiero wtedy zrobiłem git reset. Zasadniczo to właśnie dodało, a następnie wyreżyserowało moje zmiany, ale wyczyściło nieuporządkowane ścieżki.

Aaron
źródło
4
Wydaje się to lepsze niż używanie, reset --hardponieważ nie zastępuje plików (z wyjątkiem plików z problemami z scalaniem). Dzięki!
sinelaw,
Nie chciałem jeszcze etapować plików, więc dodałem je - czy nie addprzenosi zawartości z drzewa roboczego do indeksu? Nie sądzę, że rozumiem, dlaczego twoja odpowiedź działa z opisu.
Drew Noakes,
2
git addwystawia je na scenę, ale git resetco robię zaraz potem, je wystawia. Zasadniczo usuwa niezamieszane ścieżki i przywraca mnie do mojego normalnego drzewa roboczego, udając git.
Aaron,
3
Nie trzeba się git addjeśli masz zamiar git reset. W git resetrzeczywistości „cofa się” git add. git reset( --mixed<- domyślnie) skutecznie nie dotyka katalogu roboczego, więc dokładnie to, co było w twoim katalogu roboczym, scalaj konflikty i wszystkie, pozostawia się w spokoju. Indeks (i technicznie główka oddziału) jest jednak resetowany (bez odwołania, do którego resetuje się z powrotem HEAD, co prawdopodobnie oznacza brak zmiany dla głowy oddziału i skutecznie cofa wszelkie zmiany git adddokonane w indeksie, a także kasuje stan nie połączonych ścieżek) .
bambams
3
Sekwencja , edytować / postanowienie , git reseti git stash dropdziała dobrze. Robi to, co git stash popzrobiłby bez konfliktów. Wydaje się, że git addnie jest to potrzebne; chociaż może się przydać, masz wiele plików z konfliktami. Po rozwiązaniu każdego z nich można je dodawać i git statusśledzić.
artless noise
13

Jeśli, podobnie jak ja, zwykle chcesz zastąpić zawartość katalogu roboczego zawartością ukrytych plików, a nadal pojawia się konflikt, to chcesz rozwiązać konflikt przy użyciu git checkout --theirs -- .katalogu głównego.

Następnie możesz git resetprzenieść wszystkie zmiany z indeksu do katalogu roboczego, ponieważ najwyraźniej w przypadku konfliktu zmiany w plikach nie będących w konflikcie pozostają w indeksie.

Możesz także uruchomić git stash drop [<stash name>]później, aby pozbyć się skrytki, ponieważ git stash popnie usuwa jej w przypadku konfliktu.

Pedro Gimeno
źródło
2

Zauważ, że Git 2.5 (II kwartał 2015 r.) przyszły Git może próbować uniemożliwić ten scenariusz.

Zobacz commit ed178ef, autor: Jeff King ( peff), 22 kwietnia 2015.
(Scalony przez Junio ​​C Hamano - gitster- w commit 05c3967 , 19 maja 2015)

Uwaga: Zostało to cofnięte. Patrz poniżej .

stash: wymaga czystego indeksu do zastosowania / pop

Problem

Jeśli stash apply/popumieściłeś zawartość w indeksie i uruchomiłeś „ ”, możemy natrafić na konflikt i umieścić nowe wpisy w indeksie.
Powrót do pierwotnego stanu jest w tym momencie trudny, ponieważ narzędzia takie jak „git reset --keep” zdmuchną wszystko, co zostało ustawione .

Innymi słowy:

git stash pop/apply” zapomniałem się upewnić, że nie tylko działające drzewo jest czyste, ale także indeks jest czysty.
To ostatnie jest ważne, ponieważ aplikacja ukryta może powodować konflikty, a indeks będzie używany do rozwiązywania konfliktów.

Rozwiązanie

Możemy uczynić to bezpieczniejszym, odmawiając zastosowania w przypadku zmian etapowych.

Oznacza to, że jeśli wcześniej istniały scalenia z powodu zastosowania skrytki na zmodyfikowanych plikach (dodanych, ale nie zatwierdzonych), teraz nie byłyby to żadne scalenia, ponieważ zastosowanie / skasowanie skrytki natychmiast zatrzymałoby się z:

Cannot apply stash: Your index contains uncommitted changes.

Zmuszenie do zatwierdzenia zmian oznacza, że ​​w przypadku scalenia możesz łatwo przywrócić stan początkowy (przed git stash apply/pop) za pomocą git reset --hard.


Zobacz zatwierdzenie 1937610 (15 czerwca 2015 r.) I zatwierdzenie ed178ef (22 kwietnia 2015 r.) Przez Jeff King ( peff) .
(Połączone przez Junio ​​C Hamano - gitster- in commit bfb539b , 24 czerwca 2015)

To zatwierdzenie było próbą poprawy bezpieczeństwa stosowania skrytki, ponieważ proces aplikacji może tworzyć konfliktowe wpisy indeksu, po czym trudno jest przywrócić pierwotny stan indeksu.

Niestety szkodzi to niektórym typowym przepływom pracy wokół „ git stash -k”, takich jak:

git add -p       ;# (1) stage set of proposed changes
git stash -k     ;# (2) get rid of everything else
make test        ;# (3) make sure proposal is reasonable
git stash apply  ;# (4) restore original working tree

Jeśli „git zatwierdzasz” między krokami (3) i (4), to po prostu działa. Jeśli jednak te kroki są częścią przechwytywania poprzedzającego zatwierdzenie, nie masz takiej możliwości (musisz przywrócić pierwotny stan bez względu na to, czy testy przeszły, czy nie).

VonC
źródło