Jak rozwiązać konflikt git stash bez zatwierdzania?

494

Jak zadano w tym pytaniu , chcę również wiedzieć, jak rozwiązać konflikt git stash popbez dodawania wszystkich modyfikacji do zatwierdzenia (tak jak robi to „git stash pop” bez konfliktu).

Moje obecne podejście jest bardzo nieciekawe, ponieważ robię to w ten sposób:

git stash pop -> CONFLICT
git stash drop
[resolve conflict]
[add conflict files]
git reset HEAD <all files that are in commit-mode>

[Aktualizacja] Sposób na jego odtworzenie:

mkdir foo; cd foo; git init
echo "1" > one
echo "2" > two
git add -A; git commit -m "first"
echo "1.1" > one
echo "2.1" > two
git stash
echo "2.2" > two
git commit -a -m "second"
echo "Only this file would stay in HEAD without the conflict" > third
git add third
git stash pop
git status

2016-06-27: Dodano nowy plik o nazwie „trzeci” do przykładu, aby pokazać, że obejścia takie jak rozwiązanie scy działają tylko dla pustych HEAD, ale nie naprawiają początkowego problemu, że HEAD nie ma takiej samej treści jak na git stash popbez konfliktu.

Sven
źródło
Więc masz git addrozwiązane pliki konfliktu, skutecznie umieszczasz je w indeksie i nie chcesz ich mieć w naszym indeksie?
Romain
Tak to prawda. Chcę tylko zachowania, które występuje git stash pop, gdy nie występuje konflikt (ale z powiadomieniem, które pliki należy scalić).
Sven
2
Wydaje się, że odpowiedź na to pytanie znajduje się tutaj: stackoverflow.com/questions/3945826/git-stash-questions . W wybranej odpowiedzi, w czwartym komentarzu, Adam wyjaśnia, dlaczego git to robi.
Patrick
@Patrick Dziękuję za te informacje - więc wydaje się, że nie będzie dostępne żadne rozwiązanie, ponieważ jest „zgodne z projektem”
Sven

Odpowiedzi:

507

Nie podążaj za innymi odpowiedziami

Możesz ich śledzić :). Ale nie sądzę, że wykonanie zatwierdzenia, a następnie zresetowanie gałęzi w celu usunięcia tego zatwierdzenia i podobnych obejść sugerowanych w innych odpowiedziach to czysty sposób na rozwiązanie tego problemu.

Czyste rozwiązanie

Poniższe rozwiązanie wydaje mi się znacznie prostsze i sugeruje je sam Git - spróbuj wykonać git statusw repozytorium z konfliktem:

Unmerged paths:
  (use "git reset HEAD <file>..." to unstage)
  (use "git add <file>..." to mark resolution)

Zróbmy więc to, co sugeruje Git (bez robienia bezużytecznych zatwierdzeń):

  1. Ręcznie (lub przy użyciu narzędzia do scalania , patrz poniżej) rozwiąż konflikt (y).
  2. Służy git resetdo oznaczania konfliktu (ów) jako rozwiązanych i wycofywania zmian. Możesz go wykonać bez żadnych parametrów, a Git usunie wszystko z indeksu. Nie musisz wykonywaćgit add wcześniej .
  3. Na koniec usuń skrytkę za pomocą git stash drop, ponieważ Git nie robi tego w przypadku konfliktu.

Przetłumaczone na wiersz poleceń:

$ git stash pop

# ...resolve conflict(s)

$ git reset

$ git stash drop

Objaśnienie zachowania domyślnego

Istnieją dwa sposoby oznaczania konfliktów jako rozwiązane: git addi git reset. Chociaż git resetoznacza konflikty jako rozwiązane i usuwa pliki z indeksu, git addoznacza również konflikty jako rozwiązane, ale utrzymuje pliki w indeksie.

Celowe jest dodawanie plików do indeksu po rozwiązaniu konfliktu. W ten sposób możesz odróżnić zmiany od poprzedniej skrytki i zmiany wprowadzone po rozwiązaniu konfliktu. Jeśli ci się nie podoba, zawsze możesz użyćgit reset usunąć wszystko z indeksu.

Scal narzędzia

Zdecydowanie polecam użycie dowolnego z 3-kierunkowych narzędzi scalania do rozwiązywania konfliktów, np. KDiff3 , Meld itp., Zamiast robić to ręcznie. Zwykle automatycznie rozwiązuje wszystkie lub większość konfliktów. To ogromna oszczędność czasu!

David Ferenczy Rogožan
źródło
32
@kamalpal wydaje się być potrzebny, gdy git stash popnie powiedzie się konflikt.
Emile Bergeron
21
@kamalpal tak, Git nawet powiadamia, że ​​skrytka nie została upuszczona w przypadku konfliktu. Pytanie dotyczyło takiej sprawy, więc naprawdę musisz wykonać,git stash drop chyba że chcesz zachować tę skrytkę.
David Ferenczy Rogožan
@ DavidFerenczyRogožan Git wcale mnie nie powiadomił, że nie upuścił wpisu skrytki. Wersja 2.17.1 tutaj.
Robert Siemer
298

Załóżmy, że masz taki scenariusz, w którym przechowujesz zmiany, aby wyciągnąć je z miejsca pochodzenia. Być może dlatego, że lokalne zmiany znajdują się debug: truew pliku ustawień. Teraz ciągniesz i ktoś wprowadził tam nowe ustawienie, tworząc konflikt.

git status mówi:

# On branch master
# Unmerged paths:
#   (use "git reset HEAD <file>..." to unstage)
#   (use "git add/rm <file>..." as appropriate to mark resolution)
#
#   both modified:      src/js/globals.tpl.js
no changes added to commit (use "git add" and/or "git commit -a")

W porządku. Postanowiłem pójść zgodnie z sugestią Gita: rozwiązałem konflikt i zobowiązałem się:

vim src/js/globals.tpl.js
# type type type …
git commit -a -m WIP   # (short for "work in progress")

Teraz moja kopia robocza jest w stanie, który chcę, ale utworzyłem zatwierdzenie, którego nie chcę mieć. Jak mogę pozbyć się tego zatwierdzenia bez modyfikowania mojej kopii roboczej? Czekaj, jest na to popularne polecenie!

git reset HEAD^

Moja kopia robocza nie została zmieniona, ale zatwierdzenia WIP już nie ma. Właśnie tego chciałem! (Pamiętaj, że nie używam --softtutaj, ponieważ jeśli w Twojej skrytce znajdują się automatycznie scalone pliki, są one automatycznie przemieszczane i dlatego pliki te zostaną ponownie ustawione później reset).

Ale pozostała jeszcze jedna rzecz: Strona podręcznika dla git stash popprzypomina nam, że „Zastosowanie stanu może zakończyć się niepowodzeniem w przypadku konfliktów; w tym przypadku nie jest usuwane z listy skrytek. Trzeba rozwiązać konflikty ręcznie i git stash droppóźniej ręcznie zadzwonić ”. Tak właśnie robimy teraz:

git stash drop

I zrobione.

scy
źródło
34
Jest po prostu wiele brzydoty odziedziczonej po celowym wykonaniu resetowania HEAD ^ ... dla czegoś, co powinno wpłynąć tylko na działające drzewo.
6
Dlaczego po prostu nie rozwiązywać konflikty, a potem git add <resolved conflict files>następuje git reset HEAD?
BoltzmannBrain
Dzięki za sugestię, ale to nie rozwiązuje początkowego problemu, że nie jest to takie samo zachowanie, jak git stash popbez konfliktu. Po prostu dodaj kolejny plik do HEAD przed wykonaniem konfliktu, git stash popa następnie git commit -a -m WIPdodaj nowy plik do zatwierdzenia. Ale bez konfliktu tylko nowy plik pozostanie w HEAD, ale nie git stash poppliki.
Sven
7
Nie sądzę, że najpierw trzeba zatwierdzić, a potem cofnąć zatwierdzenie. Po prostu zresetuj od Dawida Ferenczyka odpowiedź zrobi to samo
vladkras,
3
Dla użytkowników systemu Windows ^jest on używany jako specjalna kontynuacja linii i pozostawi Cię siedzącego na Więcej? monit zamiast wykonania polecenia. Zamiast używać: git reset --soft HEAD~1. Zobacz, jak-do-i-delete-unpushed-git-commits?
mrfelis,
87

Zamiast dodawać zmiany wprowadzone w celu rozwiązania konfliktu, można użyć go git reset HEAD filedo rozwiązania konfliktu bez wprowadzania zmian.

Może być jednak konieczne dwukrotne uruchomienie tego polecenia. Raz oznaczono konflikt jako rozwiązany, a raz cofnął się o zmiany wprowadzane przez procedurę rozwiązywania konfliktu.

Możliwe, że powinien istnieć tryb resetowania, który wykonuje obie te rzeczy jednocześnie, chociaż nie ma go teraz.

ComputerDruid
źródło
2
Tryb resetowania jest tym, którego szukam - inne obejścia są podobne do opisanego przeze mnie i nie są praktyczne dla więcej niż 5 plików.
Sven
25
Następnie użyj „git stash drop”, aby zakończyć „git stash pop”.
David Liu,
2
Chociaż pytanie nie wymaga tego wprost, przydatne może być zaktualizowanie odpowiedzi w celu włączenia „zrzutu git stash”, ponieważ skrytka nie jest automatycznie odrzucana w przypadku konfliktu.
Abhishek Pathak
29
git checkout stash -- .

pracował dla mnie.

Uwaga : może to być niebezpieczne, ponieważ nie próbuje scalić zmian ze skrytki do kopii roboczej, ale zamiast tego zastępuje ją ukrytymi plikami. Abyś mógł stracić swoje niezaangażowane zmiany.

Stevenspiel
źródło
Pomogło to, gdy „git pull --autostash” wprowadza niechciane zatwierdzenia scalania i skrytkę kasowania git -. bezwarunkowo nadpisuje konflikty ze skrytki
Alec Istomin
11
git add .
git reset

git add . wyreżyseruje WSZYSTKIE pliki, mówiąc git, że rozwiązałeś konflikt

git reset usunie scenę z WSZYSTKICH przemieszczanych plików bez tworzenia zatwierdzenia

Aaron Goldman
źródło
To właściwie nie jest zła odpowiedź, to prawie tak jak git add -uwtedygit reset
ebob
4

Wygląda na to, że może to być odpowiedź, której szukasz, nie próbowałem tego jeszcze osobiście, ale wygląda na to, że może to załatwić sprawę. Za pomocą tego polecenia GIT spróbuje zastosować zmiany takie, jakie były wcześniej, bez próby dodania wszystkich do zatwierdzenia.

git stash apply --index

oto pełne wyjaśnienie:

http://git-scm.com/book/en/Git-Tools-Stashing

Marco Ponti
źródło
Dzięki za tę wskazówkę, ale to nie pomoże, gdy już to zrobiłem git stash pop- czy jest sposób, aby to cofnąć i zrobić, git stash apply --indexgdy się dowiem, że git stash popwpadnie w konflikt?
Sven
Dodałem przykład, jak to zrobić - wyobraź sobie, że edytujesz więcej niż 10 plików, więc nie wiesz, który z nich zmodyfikowałeś poza schowkiem.
Sven
3
Jeśli spojrzysz na dół tego posta TUTAJ, to powiesz, że jeśli uruchomisz git stash popi skończy się to konfliktami, skrytka nie zostanie usunięta ... więc możesz uruchomić, git reset --hardaby cofnąć pop, a następnie wypróbować rozwiązanie, które zasugerowałem.
Marco Ponti
Właśnie wypróbowałem to i nie działa, gdy plik jest w stanie konfliktu. Nawet jeśli konflikt zostanie naprawiony ręcznie.
Sam3k
2

git stash branchbędzie działał, który tworzy dla ciebie nową gałąź, sprawdza zatwierdzenie, w którym byłeś, kiedy ukryłeś swoją pracę, ponownie ją stosuje, a następnie upuszcza ukrytą skrzynkę, jeśli zostanie pomyślnie zastosowana. sprawdź to

kochać
źródło
2

Najszybszym sposobem, jaki udało mi się znaleźć, jest rozwiązanie konfliktu, a następnie zrobienie git add -u, a następnie zrobienie git reset HEAD, co nawet nie wymaga zatwierdzenia.

zakłócacz
źródło
1

Według git stash pytania , po rozwiązaniu konfliktu, git add <file>są właściwym działaniem.

Po przeczytaniu tego komentarza zrozumiałem, że zmiany są automatycznie dodawane do indeksu (zgodnie z projektem). Dlatego git add <file>kończy proces rozwiązywania konfliktu.

samgrigg
źródło
-1

To nie jest najlepszy sposób, aby to zrobić, ale działa:

$ git stash apply
$ >> resolve your conflict <<
$ >> do what you want to do with your code <<
$ git checkout HEAD -- file/path/to/your/file
Bishwas Mishra
źródło
ta odpowiedź wydaje mi się file/path/to/your/filezupełnie błędna, ponieważ
odrzuciłaby