Wie kann man einen Git-Stash-Konflikt ohne Commit lösen?

495

Wie in dieser Frage gestellt , möchte ich auch wissen, wie ein Konflikt gelöst werden kann, git stash popohne dass alle Änderungen an einem Commit hinzugefügt werden (genau wie bei "git stash pop" ohne Konflikt).

Mein aktueller Ansatz ist sehr unkühl, weil ich es so mache:

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

[Update] Eine Möglichkeit, es zu reproduzieren:

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

27.06.2016: Dem Beispiel wurde eine neue Datei mit dem Namen "Third" hinzugefügt, um zu zeigen, dass Problemumgehungen wie die Lösung von scy nur für leere HEADs funktionieren, aber das anfängliche Problem nicht beheben, dass der HEAD nicht den gleichen Inhalt hat wie für einen git stash popohne Konflikt.

Sven
quelle
Sie haben also git addIhre gelösten Konfliktdateien, die sie effektiv im Index bereitstellen, und möchten sie nicht in unserem Index haben?
Romain
Ja, das ist richtig. Ich möchte nur das Verhalten, git stash popdas auftritt , wenn kein Konflikt auftritt (aber mit der Benachrichtigung, welche Dateien zusammengeführt werden müssen).
Sven
2
Die Antwort darauf scheint hier zu sein: stackoverflow.com/questions/3945826/git-stash-questions . In der gewählten Antwort erklärt Adam im 4. Kommentar, warum Git dies tut.
Patrick
@Patrick Vielen Dank für diese Informationen - so scheint es, dass es keine Lösung geben wird, weil es "von Entwurf" ist
Sven

Antworten:

509

Folge keinen anderen Antworten

Nun, du kannst ihnen folgen :). Ich denke jedoch nicht, dass das Festschreiben und anschließende Zurücksetzen des Zweigs zum Entfernen dieses Festschreibens und ähnlicher Problemumgehungen, die in anderen Antworten vorgeschlagen wurden, der saubere Weg ist, um dieses Problem zu lösen.

Saubere Lösung

Die folgende Lösung scheint mir viel sauberer zu sein und wird auch vom Git selbst vorgeschlagen - versuchen Sie, sie git statusmit einem Konflikt im Repository auszuführen :

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

Machen wir also, was Git vorschlägt (ohne nutzlose Commits zu machen):

  1. Lösen Sie die Konflikte manuell (oder mithilfe eines Zusammenführungstools , siehe unten).
  2. Verwenden Sie git resetdiese Option, um Konflikte als gelöst zu markieren und die Änderungen aufzuheben. Sie können es ohne Parameter ausführen und Git entfernt alles aus dem Index. Sie müssen nicht vorher ausführen git add.
  3. Entfernen Sie zum Schluss den Stash mit git stash drop, da Git dies bei Konflikten nicht tut.

Übersetzt in die Kommandozeile:

$ git stash pop

# ...resolve conflict(s)

$ git reset

$ git stash drop

Erläuterung des Standardverhaltens

Es gibt zwei Möglichkeiten, Konflikte als gelöst zu kennzeichnen: git addund git reset. Während git resetdie Konflikte als gelöst markiert und Dateien aus dem Index entfernt werden, git addwerden die Konflikte auch als gelöst markiert, die Dateien bleiben jedoch im Index.

Das Hinzufügen von Dateien zum Index nach Behebung eines Konflikts ist absichtlich. Auf diese Weise können Sie die Änderungen vom vorherigen Stash und die Änderungen unterscheiden, die Sie nach der Lösung des Konflikts vorgenommen haben. Wenn es Ihnen nicht gefällt, können Sie jederzeit git resetalles aus dem Index entfernen.

Werkzeuge zusammenführen

Ich empfehle dringend, eines der 3-Wege-Merge-Tools zur Lösung von Konflikten zu verwenden, z. B. KDiff3 , Meld usw., anstatt dies manuell zu tun. Normalerweise werden alle oder die meisten Konflikte automatisch selbst gelöst. Das spart enorm viel Zeit!

David Ferenczy Rogožan
quelle
32
@kamalpal es scheint nötig zu sein, wenn git stash popes mit Konflikten versagt.
Emile Bergeron
21
@kamalpal Ja, Git benachrichtigt Sie sogar darüber, dass Stash in einem Konfliktfall nicht gelöscht wurde. Und die Frage war über einen solchen Fall, also müssen Sie wirklich ausführen, esgit stash drop sei denn, Sie möchten diesen Vorrat behalten.
David Ferenczy Rogožan
@ DavidFerenczyRogožan Git hat mich überhaupt nicht benachrichtigt, dass der Stash-Eintrag nicht gelöscht wurde. Version 2.17.1 hier.
Robert Siemer
298

Angenommen, Sie haben dieses Szenario, in dem Sie Ihre Änderungen aufbewahren, um sie vom Ursprung abzurufen. Möglicherweise, weil Ihre lokalen Änderungen nur debug: truein einigen Einstellungsdateien enthalten sind. Jetzt ziehen Sie und jemand hat dort eine neue Einstellung eingeführt, die einen Konflikt erzeugt.

git status sagt:

# 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")

Okay. Ich entschied mich für das, was Git vorschlug: Ich löste den Konflikt und verpflichtete mich:

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

Jetzt befindet sich meine Arbeitskopie in dem gewünschten Zustand, aber ich habe ein Commit erstellt, das ich nicht haben möchte. Wie kann ich dieses Commit entfernen, ohne meine Arbeitskopie zu ändern? Warten Sie, es gibt einen beliebten Befehl dafür!

git reset HEAD^

Meine Arbeitskopie wurde nicht geändert, aber das WIP-Commit ist weg. Genau das wollte ich! (Beachten Sie, dass ich nicht benutze--soft hier , denn wenn sich in Ihrem Vorrat automatisch zusammengeführte Dateien befinden, werden diese automatisch bereitgestellt, sodass diese Dateien nachher erneut bereitgestellt werden reset.)

Aber noch etwas ist übrig: Die Manpage für git stash poperinnert uns daran, dass "das Anwenden des Status mit Konflikten fehlschlagen kann; in diesem Fall wird es nicht aus der Stash-Liste entfernt. Sie müssen die Konflikte von Hand lösen und anschließend git stash dropmanuell aufrufen ." Genau das machen wir jetzt:

git stash drop

Und fertig.

schüchtern
quelle
34
Es ist nur eine Menge ererbter Hässlichkeit, absichtlich einen Reset-Reset-HEAD ^ ... für etwas durchführen zu müssen, das nur den Arbeitsbaum betreffen sollte.
6
Warum nicht einfach die Konflikte lösen und dann git add <resolved conflict files>folgen git reset HEAD?
BoltzmannBrain
Vielen Dank für den Vorschlag, aber dies behebt nicht das anfängliche Problem, dass dies nicht das gleiche Verhalten wie git stash popohne Konflikt ist. Fügen Sie einfach eine weitere Datei zu HEAD hinzu, bevor Sie den Konflikt ausführen, git stash popund git commit -a -m WIPfügen Sie dann auch die neue Datei zum Commit hinzu. Ohne einen Konflikt würde jedoch nur die neue Datei in HEAD verbleiben, nicht jedoch die git stash popDateien.
Sven
7
Ich denke nicht, dass es notwendig ist, zuerst ein Commit durchzuführen und dann das Commit rückgängig zu machen. Einfach von Dawid Ferenczy zurücksetzen Antwort wird das gleiche tun
vladkras
3
Für Windows-Benutzer ^wird das als spezielle Zeilenfortsetzung verwendet und lässt Sie an einem More sitzen? Eingabeaufforderung statt Ausführung des Befehls. Verwenden Sie stattdessen : git reset --soft HEAD~1. Sehen Sie, wie-ich-lösche-unpushed-git-Commits?
Mrfelis
87

Anstatt die Änderungen hinzuzufügen, die Sie zur Lösung des Konflikts vornehmen, können Sie sie verwenden git reset HEAD file den Konflikt auch ohne Bereitstellung Ihrer Änderungen lösen.

Möglicherweise müssen Sie diesen Befehl jedoch zweimal ausführen. Einmal, um den Konflikt als gelöst zu markieren und einmal, um die Änderungen aufzuheben, die von der Konfliktlösungsroutine vorgenommen wurden.

Es ist möglich, dass es einen Reset-Modus gibt, der beide Dinge gleichzeitig ausführt, obwohl es derzeit keinen gibt.

ComputerDruide
quelle
2
Der Reset-Modus ist der, nach dem ich suche - andere Problemumgehungen sind wie die von mir beschriebene und für mehr als 5 Dateien nicht praktikabel.
Sven
25
Und benutze danach "git stash drop", um den "git stash pop" zu beenden.
David Liu
2
Obwohl die Frage dies nicht explizit verlangt, kann es nützlich sein, die Antwort so zu aktualisieren, dass sie "git stash drop" enthält, da der Stash im Falle eines Konflikts nicht automatisch gelöscht wird.
Abhishek Pathak
29
git checkout stash -- .

arbeitete für mich.

Hinweis : Dies kann gefährlich sein, da nicht versucht wird, die Änderungen aus dem Stash in Ihre Arbeitskopie einzufügen, sondern sie stattdessen mit den verstauten Dateien überschreibt . So können Sie Ihre nicht festgeschriebenen Änderungen verlieren.

Stevenspiel
quelle
Dies half, wenn "git pull --autostash" unerwünschte Zusammenführungs-Commits und git checkout stash - einführt. überschreibt bedingungslos Konflikte aus Stash
Alec Istomin
11
git add .
git reset

git add . wird ALLE Dateien bereitstellen, die git mitteilen, dass Sie den Konflikt gelöst haben

git reset hebt ALLE bereitgestellten Dateien auf, ohne ein Commit zu erstellen

Aaron Goldman
quelle
Dies ist eigentlich keine schlechte Antwort, es ist ziemlich ähnlich wie git add -udamalsgit reset
Ebob
4

Es scheint, dass dies die Antwort ist, nach der Sie suchen. Ich habe dies noch nicht persönlich versucht, aber es scheint, als würde es den Trick tun. Mit diesem Befehl versucht GIT, die Änderungen wie zuvor anzuwenden, ohne alle für das Festschreiben hinzuzufügen.

git stash apply --index

Hier ist die vollständige Erklärung:

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

Marco Ponti
quelle
Vielen Dank für diesen Hinweis, aber das hilft nicht, wenn ich es bereits getan habe git stash pop- oder gibt es eine Möglichkeit, dies rückgängig zu machen und zu tun, git stash apply --indexwenn ich herausgefunden habe, dass git stash popes zu einem Konflikt kommen wird?
Sven
Ich habe ein Beispiel hinzugefügt, wie dies erstellt werden kann. Stellen Sie sich vor, Sie bearbeiten mehr als 10 Dateien, sodass Sie nicht wissen, welche davon Sie außerhalb des Stashs geändert haben.
Sven
3
Wenn Sie sich das Ende dieses Beitrags HIER ansehen , heißt es, dass wenn Sie ausgeführt werden git stash popund es zu Konflikten kommt, der Stash nicht entfernt wird. Sie können also ausführen git reset --hard, um den Pop rückgängig zu machen, und dann die von mir vorgeschlagene Lösung ausprobieren.
Marco Ponti
Ich habe es gerade versucht und es funktioniert nicht, nachdem sich eine Datei im Konfliktzustand befindet. Auch wenn Sie den Konflikt manuell beheben.
Sam3k
2

git stash branchwill works, das einen neuen Zweig für Sie erstellt, überprüft das Commit, bei dem Sie Ihre Arbeit gespeichert haben, wendet Ihre Arbeit dort erneut an und löscht das Stash, wenn es erfolgreich angewendet wird. Überprüfen Sie dies

hegen
quelle
2

Der schnellste Weg, den ich gefunden habe, besteht darin, den Konflikt zu lösen, dann zu tun git add -uund dann zu tun git reset HEAD, ohne dass ein Commit erforderlich ist.

Störsender
quelle
1

Laut git stash sind Fragen nach Behebung des Konflikts git add <file>die richtige Vorgehensweise.

Nachdem ich diesen Kommentar gelesen hatte , wurde mir klar, dass die Änderungen automatisch zum Index hinzugefügt werden (beabsichtigt). Deshalb ist git add <file>der Konfliktlösungsprozess abgeschlossen.

Samgrigg
quelle
-1

Es ist nicht der beste Weg, aber es funktioniert:

$ 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
quelle
Diese Antwort scheint mir einfach falsch zu sein, da sie alle Änderungen an file/path/to/your/fileAFAIU
oromoiluig