1101 Stimmen

Wie kann ich eine einzelne Datei (oder Änderungen an einer Datei) aus einem Git-Stash extrahieren?

Ist es möglich, eine einzelne Datei oder ein Diff einer Datei aus einem Git Stash zu extrahieren, ohne das Stash Changeset zu löschen?

1552voto

Jakub Narębski Punkte 286531

Auf der Deppenhaufen manpage können Sie (im Abschnitt "Diskussion", gleich nach der Beschreibung von "Optionen") lesen, dass:

Ein Stash wird als Commit dargestellt, dessen Baum den Zustand des Stashs aufzeichnet. Arbeitsverzeichnisses aufzeichnet, und sein erster Elternteil ist die Übergabe an HEAD, als der Stash erstellt wurde.

So können Sie den Vorrat (z.B. stash@{0} ist der erste / oberste Stash) als Merge-Commit und verwenden:

$ git diff stash@{0}^1 stash@{0} -- <filename>

Erläuterung: stash@{0}^1 ist der erste Elternteil des angegebenen Verstecks, der, wie in der obigen Erklärung angegeben, der Commit ist, bei dem die Änderungen versteckt wurden. Wir verwenden diese Form von "git diff" (mit zwei Commits), weil stash@{0} / refs/stash ist ein Merge-Commit, und wir müssen Git mitteilen, gegen welches Elternteil wir vergleichen wollen. Noch kryptischer:

$ git diff stash@{0}^! -- <filename>

sollte ebenfalls funktionieren (siehe git rev-parse Manpage zur Erklärung von rev^! Syntax, im Abschnitt "Angabe von Bereichen").

Ebenso können Sie Git-Checkout um eine einzelne Datei aus dem Versteck zu prüfen:

$ git checkout stash@{0} -- <filename>

oder sie unter einem anderen Dateinamen zu speichern:

$ git show stash@{0}:<full filename>  >  <newfile>

ou

$ git show stash@{0}:./<relative filename> > <newfile>

( Hinweis dass hier <voller Dateiname> der vollständige Pfadname einer Datei relativ zum obersten Verzeichnis eines Projekts ist (denken Sie: relativ zu stash@{0} )).


Sie müssen möglicherweise Folgendes schützen stash@{0} aus der Shell-Expansion, d.h. Verwendung "stash@{0}" o 'stash@{0}' .

19 Stimmen

Das ist ziemlich cool... Ich habe nicht wirklich Ich habe nicht verstanden, wie stash funktioniert, bis ich Ihre Antwort gelesen habe (die mich zu dem Zusatz git-checkout geführt hat). Ich habe wirklich nicht verstanden, dass Git bei einem Stash ZWEI Commits speichert - einen für den Status des Index und einen für den Status der Arbeitskopie, die ein Merge zwischen dem Index und dem ursprünglichen HEAD ist. Das erklärt die seltsamen Bäume, die ich gesehen habe, wenn ich das Repository mit "gitk --all" anzeige, wenn Stashes vorhanden sind.

6 Stimmen

Meistens finde ich, dass die Git-Checkout-Anwendung der beste Weg ist, um das zu erreichen, was ich tun wollte. Ich war jedoch neugierig und überprüfte git checkout Man-Seite. Es kann die Datei nicht an einem anderen Ort ablegen. Es gibt einen Hinweis darauf in: stackoverflow.com/questions/888414/

121 Stimmen

$ git checkout stash@{0} -- <Dateiname> ist sehr nützlich, danke

85voto

Tim Henigan Punkte 57320

Wenn Sie git stash apply statt git stash pop wird der Vorrat auf Ihren Arbeitsbaum übertragen, aber der Vorrat bleibt erhalten.

Wenn Sie dies getan haben, können Sie add / commit die gewünschte Datei und setzen Sie dann die übrigen Änderungen zurück.

4 Stimmen

Um ein bestimmtes Versteck zu öffnen: git stash pop stash@{0} (Liste der versteckten Änderungen: git stash list )

0 Stimmen

Wenn andere Dateien im Stash einen Merge-Konflikt verursachen, lässt mich Git nicht auf die gewünschte Datei übertragen :(

4 Stimmen

Dies ist die beste Antwort. Sie müssen nicht mit einem diff erent command (heh), um das zu tun, was git stash apply tun sollte, und Sie müssen sich nicht um irgendwelche seltsamen Nebeneffekte kümmern (git checkout kopiert die exakte Datei in den Stash) oder irgendeine seltsame Syntax auswendig lernen.

81voto

Ram Punkte 14350
$ git checkout stash@{0} -- <filename>

Anmerkungen:

  1. Stellen Sie sicher, dass Sie nach dem "--" ein Leerzeichen setzen und der Parameter Dateiname

  2. Ersetzen Sie die Null (0) durch Ihre spezifische Vorratsnummer. Um eine Vorratsliste zu erhalten, verwenden Sie:

    git stash list

Basierend auf Jakub Narebskis Antwort -- Kürzere Fassung

1 Stimmen

Sie können auch den Namen des Verstecks verwenden git checkout stash^{/'Stash name here'} -- <filename>

2 Stimmen

Dies birgt zwei Risiken: (a) es überschreibt stillschweigend alle noch nicht bereitgestellten lokalen Änderungen, die Sie in dieser Datei haben; und (b) es kopiert die genau Datei aus dem Vorrat, ohne sie mit den Änderungen zusammenzuführen, die seit dem Speichern des Vorrats in Ihrem Zweig vorgenommen wurden. Das kann verwirrend sein, da git stash apply / pop haben keinen dieser Nachteile. Um ein Verhalten zu erreichen, das eher erwartet wird, verwenden Sie eine der git diff -basierten Ansätzen in einigen der anderen Antworten hier.

48voto

Walf Punkte 7428

Editar: Siehe Antwort von cambunctious Das ist im Grunde das, was ich jetzt bevorzuge, weil es nur die Änderungen im Vorrat verwendet, anstatt sie mit dem aktuellen Zustand zu vergleichen. Dadurch wird der Vorgang additiv, und die Wahrscheinlichkeit, dass die Arbeit, die seit der Erstellung des Vorratslagers geleistet wurde, rückgängig gemacht wird, ist wesentlich geringer.

Um dies interaktiv zu tun, müssten Sie zunächst

git diff stash^! -- path/to/relevant/file/in/stash.ext perhaps/another/file.ext > my.patch

...öffnen Sie dann die Patch-Datei in einem Texteditor, ändern Sie sie nach Bedarf und führen Sie dann Folgendes aus

git apply < my.patch

Die Antwort von cambunctious umgeht die Interaktivität, indem sie einen Befehl direkt an den anderen weiterleitet, was in Ordnung ist, wenn Sie wissen, dass Sie alle Änderungen aus dem Versteck haben wollen. Sie können die stash^! auf einen beliebigen Commit-Bereich, der die gewünschten kumulativen Änderungen enthält (überprüfen Sie jedoch zuerst die Ausgabe des Diffs).

Wenn die Anwendung des Patches/Diffs fehlschlägt, können Sie den letzten Befehl ändern in git apply --reject der alle möglichen Änderungen vornimmt und die .rej Dateien, in denen es Konflikte gibt, die es nicht auflösen kann. Die Website .rej Dateien können dann mit wiggle , etwa so:

wiggle --replace path/to/relevant/file/in/stash.ext{,.rej}

Dadurch wird der Konflikt entweder aufgelöst oder Sie erhalten Konfliktmarker, die Sie bei einer Zusammenführung erhalten würden.

Wenn Ihre Distro nicht über wiggle können Sie es einfach bauen:

cd /usr/local/src/
git clone git://git.neil.brown.name/wiggle
cd wiggle/
git checkout v1.3
make install

Vorherige Lösung: Es gibt eine einfache Möglichkeit, Änderungen aus jedem Zweig, einschließlich Stashes, zu erhalten:

$ git checkout --patch stash@{0} path/to/file

Sie können die Dateispezifikation weglassen, wenn Sie viele Teile patchen wollen. Oder lassen Sie patch (aber nicht den Pfad) weg, um alle Änderungen in einer einzigen Datei zu erhalten. Ersetzen Sie 0 mit der Verstecknummer aus git stash list , wenn Sie mehr als eine haben. Beachten Sie, dass dies so ist wie diff und Angebote zur Bewerbung todo Unterschiede zwischen den Zweigen. Um Änderungen von nur einem einzigen Commit/Stash zu erhalten, schauen Sie sich Folgendes an git cherry-pick --no-commit .

1 Stimmen

Wird dabei genau die Datei aus dem Versteck kopiert oder wird sie zusammengeführt? Im Falle des Kopierens gehen alle Änderungen, die Sie seit der Erstellung des Verzeichnisses vorgenommen haben, verloren.

3 Stimmen

@Danijel Read git help checkout . --patch führt eine interaktive Zusammenführung durch und wendet die Hunk(s) an, die Sie in der Shell genehmigen (oder die Sie speichern, wenn Sie sich für e dit the patch). Pfad allein wird die Datei überschreiben, wie ich schrieb, "alle Änderungen".

1 Stimmen

Leichte Verbesserung: git config --global alias.applydiffat '!git checkout --patch "$1" -- $(git diff --name-only "$1"^ "$1")' -- dann tun git applydiffat stash@{4} verwendet nur Dateien, die sich zwischen dem Stash und seinem Parent geändert haben.

36voto

Luboš Turek Punkte 5777

Kurze Antwort

Um die gesamte Datei zu sehen: git show stash@{0}:<filename>

Um den Unterschied zu sehen: git diff stash@{0}^1 stash@{0} -- <filename>

1 Stimmen

Ich glaube nicht, dass es ihm/ihr darum ging, den Vorrat für eine bestimmte Datei einzusehen, sondern nur darum, diese Datei zu knacken.

3 Stimmen

Das ist es, wonach ich gesucht habe. Dann können Sie ersetzen diff avec difftool um Ihr bevorzugtes externes Diff zu verwenden.

1 Stimmen

Mein Git-Repository war beschädigt, aber ich hatte die Dateien versteckt, konnte sie aber wegen der Beschädigung nicht anwenden. Ich war in der Lage, dies zu verwenden und Rohr zu einer neuen Datei, diff es, und ich war gut zu gehen. Ich danke Ihnen!

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X