Ich hatte eine Reihe von inszenierten und nicht inszenierten Änderungen und wollte schnell zu einem anderen Zweig wechseln und dann zurückwechseln.
Also habe ich meine Änderungen inszeniert mit:
$ git stash push -a
(Im Nachhinein hätte ich wahrscheinlich --include-untracked
stattdessen verwenden können --all
)
Als ich dann ging, um das Versteck zu öffnen, bekam ich eine Menge Fehler in der Art von:
$ git stash pop
foo.txt already exists, no checkout
bar.txt already exists, no checkout
...
Could not restore untracked files from stash entry
Es scheint keine Änderungen aus dem Vorrat wiederherzustellen.
Ich habe es auch versucht, $ git stash branch temp
aber das zeigt die gleichen Fehler.
Ich habe einen Weg gefunden, um dies zu umgehen:
$ git stash show -p | git apply
Katastrophe vorerst abgewendet, aber dies wirft einige Fragen auf.
Warum ist dieser Fehler überhaupt aufgetreten und wie vermeide ich ihn beim nächsten Mal?
git stash show -p | git apply --3
git stash show
und als Rettungsdateien einzeln auf :$ git show stash@{0}:your/stashed/file.txt > your_rescued_file.txt
. Dadurch wird die Datei aus dem Stash abgerufen und unter einem anderen Namen gespeichert. Jetzt können Sie sicher mit geeigneten Rettungsmethoden experimentieren (siehe Antworten unten). Wenn die Dinge in die Irre gehen, haben Sie Ihre geretteten Dateien immer als letzte Ressource.Antworten:
Beachten Sie als zusätzliche Erklärung, dass
git stash
entweder zwei oder drei Festschreibungen vorgenommen werden. Der Standardwert ist zwei; Sie erhalten drei, wenn Sie die Schreibweise der Optionen--all
oder verwenden--include-untracked
.Diese zwei oder drei Commits sind in einer wichtigen Hinsicht besonders: Sie befinden sich in keinem Zweig. Git findet sie über den speziellen Namen
stash
. 1 Das Wichtigste ist jedoch, was Git Ihnen mit diesen zwei oder drei Commits ermöglicht - und bringt . Um dies zu verstehen, müssen wir uns ansehen, was in diesen Commits enthalten ist.Was ist in einem Vorrat
Jedes Commit kann ein oder mehrere übergeordnete Commits auflisten. Diese bilden ein Diagramm, in dem spätere Festschreibungen auf frühere verweisen. Der Stash enthält normalerweise zwei Commits, die ich gerne
i
für den Inhalt des Index- / Staging-Bereichs undw
für den Inhalt des Arbeitsbaums aufrufe. Denken Sie auch daran, dass jedes Commit einen Snapshot enthält. Bei einem normalen Commit wird dieser Snapshot aus dem Inhalt des Index- / Staging-Bereichs erstellt. Dasi
Commit ist also in der Tat ein ganz normales Commit! Es ist einfach nicht auf einem Zweig:Wenn Sie einen normalen Stash
git stash
erstellen,w
kopiert der Code jetzt alle nachverfolgten Arbeitsbaumdateien (in einen temporären Hilfsindex). Git setzt das erste übergeordnetew
Element dieses Commits auf dasHEAD
Commit und das zweite übergeordnete Element auf das Commiti
. Zuletzt wirdstash
auf diesesw
Commit hingewiesen:Wenn Sie
--include-untracked
oder hinzufügen--all
, macht Gitu
zwischen dem Erstellen voni
und ein zusätzliches Commitw
. Der Snapshot-Inhalt füru
sind Dateien, die nicht verfolgt, aber nicht ignoriert werden (--include-untracked
), oder Dateien, die nicht verfolgt werden, selbst wenn sie ignoriert werden (--all
). Dieses zusätzlicheu
Commit hat kein übergeordnetes Element. Wenn es dann erstelltgit stash
wirdw
, wirdw
das dritte übergeordnete Element für diesesu
Commit festgelegt, sodass Sie Folgendes erhalten:Git auch an dieser Stelle, entfernt alle Arbeit Baum - Dateien , die in der Liquidation
u
begehen (mit ,git clean
das zu tun).Ein Versteck wiederherstellen
Wenn Sie einen Stash wiederherstellen , haben Sie die Möglichkeit
--index
, ihn zu verwenden oder nicht zu verwenden. Dies teiltgit stash apply
(oder einem der intern verwendeten Befehleapply
, z. B.pop
) mit, dass das Commit verwendet werden soll ,i
um zu versuchen, Ihren aktuellen Index zu ändern. Diese Änderung erfolgt mit:(mehr oder weniger; es gibt eine Reihe von Details, die der Grundidee hier im Wege stehen).
Wenn Sie dies weglassen
--index
, wirdgit stash apply
das Festschreiben vollständig ignorierti
.Wenn der Stash nur zwei Commits hat,
git stash apply
kann dasw
Commit jetzt angewendet werden . Es tut dies durch Aufrufe vongit merge
2 (ohne dass es das Ergebnis als eine normale merge zu begehen oder zu behandeln), auf das die ursprünglichen commit Verwendung der Vorrat hergestellt wurde (i
s Elternteil, undw
"erste Mutter s) als merge Base,w
wie die--theirs
Commit, und Ihr aktuelles (HEAD) Commit als Ziel der Zusammenführung. Wenn die Zusammenführung erfolgreich ist, ist alles in Ordnung - zumindest glaubt Git das - und dasgit stash apply
selbst ist erfolgreich. Wenn Sie verwendetgit stash pop
die Stash anwenden, wird der Code jetzt fällt das Versteck. 3 Wenn die Zusammenführung fehlschlägt, erklärt Git, dass die Anwendung fehlgeschlagen ist. Wenn du benutzt hastgit stash pop
Der Code behält den Stash bei und liefert den gleichen Fehlerstatus wie fürgit stash apply
.Aber wenn Sie dieses dritte Commit haben - wenn
u
das von Ihnen angewendete Stash ein Commit enthält - ändern sich die Dinge! Es gibt keine Möglichkeit, so zu tun, als ob dasu
Commit nicht existiert. 4 Git besteht darauf, alle Dateien aus diesemu
Commit in den aktuellen Arbeitsbaum zu extrahieren . Dies bedeutet, dass die Dateien entweder überhaupt nicht vorhanden sein dürfen oder denselben Inhalt wie beimu
Festschreiben haben dürfen.Um dies zu erreichen, können Sie sich
git clean
selbst verwenden - aber denken Sie daran, dass nicht verfolgte Dateien (ignoriert oder nicht) keine andere Existenz in einem Git-Repository haben. Stellen Sie also sicher, dass diese Dateien alle zerstört werden können! Sie können auch ein temporäres Verzeichnis erstellen und die Dateien zur sicheren Aufbewahrung dorthin verschieben - oder sogar ein anderesgit stash save -u
odergit stash save -a
, da diesegit clean
für Sie ausgeführt werden. Aber das lässt Sie nur mit einem anderenu
Stash zurück, mit dem Sie sich später befassen müssen.1 Das ist in der Tat
refs/stash
. Dies ist wichtig, wenn Sie einen Zweig mit dem Namen erstellenstash
: Der vollständige Name des Zweigs lautetrefs/heads/stash
, sodass diese nicht in Konflikt stehen. Aber tu das nicht: Git macht es nichts aus, aber du wirst dich verwirren. :-)2 Der
git stash
Code wirdgit merge-recursive
hier tatsächlich direkt verwendet . Dies ist aus mehreren Gründen erforderlich und hat auch den Nebeneffekt, dass Git es nicht als Zusammenführung behandelt, wenn Sie Konflikte lösen und festschreiben.3 Deshalb empfehle ich
git stash pop
, zugunsten von zu vermeidengit stash apply
. Sie haben die Möglichkeit zu überprüfen, was angewendet wurde, und zu entscheiden, ob es tatsächlich richtig angewendet wurde. Wenn nicht, haben Sie immer noch Ihren Vorrat, was bedeutet, dass Siegit stash branch
alles perfekt wiederherstellen können. Nun, vorausgesetzt, das Fehlen dieses lästigenu
Commits.4 Es sollte wirklich geben:
git stash apply --skip-untracked
oder so. Es sollte auch eine Variante geben, die bedeutet, dass alle dieseu
Festschreibungsdateien in einem neuen Verzeichnis abgelegt werden , zgit stash apply --untracked-into <dir>
. B. vielleicht.quelle
--index
:git stash apply --index
?git stash save --all
, dann sofortgit stash apply
, aber einige Dateien fehlten, weil ich sie umbenannt und dann erneut erstellt habe (vor dem Verstecken). Was geholfen hat war:git checkout stash@{0} -- .
Ich werde mich nicht einmal darum kümmern,git checkout stash^3 -- .
weil jetzt alles in Ordnung zu sein scheint. Es ist schade, dass ich keine Zeit habe, wirklich zu verstehen, was los war. Vielen Dank.Ich habe es geschafft, Ihr Problem neu zu erstellen. Wenn Sie nicht verfolgte Dateien speichern und diese Dateien dann erstellen (in Ihrem Beispiel
foo.txt
undbar.txt
), haben Sie anscheinend lokale Änderungen an nicht verfolgten Dateien, die beim Anwenden überschrieben werdengit stash pop
.Um dieses Problem zu umgehen, können Sie den folgenden Befehl verwenden. Dadurch werden nicht gespeicherte lokale Änderungen außer Kraft gesetzt. Seien Sie also vorsichtig.
Hier sind einige weitere Informationen, die ich im vorherigen Befehl gefunden habe .
quelle
--all
/-a
ignorierte Dateien verwenden , sodass dies relevant sein kann.git merge --squash --strategy-option=theirs stash
Ansatz in diesem Fall besser ist).already exists, no checkout
), überprüfen Sie meine Antwort unten.Um die Antwort von Daniel Smith zu erweitern : Dieser Code stellt nur die verfolgten Dateien wieder her, selbst wenn Sie sie beim Erstellen des Stashs verwendet haben
--include-untracked
(oder-u
). Der vollständige Code ist:git checkout stash -- . git checkout stash^3 -- . git stash drop # Optional to unstage the changes (auto-staged by default). git reset
Dadurch werden die nachverfolgten Inhalte (in
stash
) und die nicht nachverfolgten Inhalte (in ) vollständig wiederhergestellt undstash^3
anschließend der Stash gelöscht. Ein paar Anmerkungen:git checkout
, werden sie alle automatischgit reset
bereitgestellt , daher habe ich hinzugefügt , um alles zu entfernen.stash@{0}
undstash@{0}^3
in meinen Tests funktioniert es mit oder ohne@{0}
Quellen:
stash^3
Commit)quelle
Abgesehen von anderen Antworten habe ich einen kleinen Trick gemacht
git stash apply
(Kann einen beliebigen Befehl verwenden, z. B. anwenden, Pop usw.)quelle