Frage Wie kann man einen verlorenen Vorrat in Git wiederherstellen?


Ich benutze häufig git stash und git stash pop um Änderungen in meinem Arbeitsbaum zu speichern und wiederherzustellen. Gestern hatte ich einige Änderungen in meinem Arbeitsbaum, die ich verstaut und gepoppt hatte, und dann habe ich weitere Änderungen an meinem Arbeitsbaum vorgenommen. Ich würde gerne zurückgehen und die verdeckten Veränderungen von gestern Revue passieren lassen, aber git stash pop scheint alle Verweise auf das zugehörige Commit zu entfernen.

Ich weiß das, wenn ich es benutze git stash dann .git / refs / stash enthält die Referenz des Commits, das zum Erstellen des Stash verwendet wurde. Und .git / logs / refs / stash enthält das ganze Versteck. Aber diese Referenzen sind vorbei git stash pop. Ich weiß, dass das Commit immer noch in meinem Repository ist, aber ich weiß nicht, was es war.

Gibt es eine einfache Möglichkeit, die Stash-Commit-Referenz von gestern wiederherzustellen?

Beachten Sie, dass dies für mich heute nicht kritisch ist, da ich tägliche Backups habe und zum Arbeitsbaum von gestern zurückkehren kann, um meine Änderungen zu erhalten. Ich frage, weil es einen leichteren Weg geben muss!


1331
2017-09-18 01:59


Ursprung


Antworten:


Wenn Sie es gerade erst geöffnet haben und das Terminal noch offen ist, werden Sie es tun habe immer noch den Hash-Wert von gedruckt git stash pop auf dem Bildschirm (Danke, Dolda)

Ansonsten können Sie es für Linux und Unix verwenden:

git fsck --no-reflog | awk '/dangling commit/ {print $3}'

und für Windows:

git fsck --no-reflog | select-string 'dangling commit' | foreach { $bits = $_ -split ' '; echo $bits[2];}

Dies zeigt Ihnen alle Commits an den Spitzen Ihres Commit-Graphen, die nicht mehr von einem Zweig oder Tag referenziert werden - jede verlorene Commit, einschließlich jeder Stash Commit, die Sie jemals erstellt haben, wird irgendwo in diesem Graphen sein.

Der einfachste Weg, den gewünschten Stash-Commit zu finden, ist wahrscheinlich, diese Liste an zu übergeben gitk:

gitk --all $( git fsck --no-reflog | awk '/dangling commit/ {print $3}' )

Dadurch wird ein Repository-Browser gestartet, der Sie anzeigt jedes einzelne Commit im Repositoryunabhängig davon, ob es erreichbar ist oder nicht.

Sie können ersetzen gitk da mit sowas git log --graph --oneline --decorate wenn Sie ein schönes Diagramm auf der Konsole über eine separate GUI-App bevorzugen.

Um Stash-Commits zu erkennen, suchen Sie nach Commit-Nachrichten dieser Form:

WIP an etwas Verzweiflung: commithash Einige alte Commit-Nachrichten

Hinweis: Die Commit-Nachricht wird nur in dieser Form vorliegen (beginnend mit "WIP on"), wenn Sie zu diesem Zeitpunkt keine Nachricht gesendet haben git stash.

Sobald Sie den Hash der gewünschten Commit kennen, können Sie ihn als Stash verwenden:

git stash apply $ stash_hash

Oder Sie können das Kontextmenü in verwenden gitk um Verzweigungen für unerreichbare Commits zu erstellen, an denen Sie interessiert sind. Danach können Sie mit allen normalen Tools machen, was Sie wollen. Wenn Sie fertig sind, blasen Sie diese Zweige einfach wieder weg.


2151
2017-09-18 11:38



Wenn Sie das Terminal nicht schließen, sehen Sie sich einfach die Ausgabe von an git stash pop und Sie haben die Objekt-ID des gelöschten Stash. Es sieht normalerweise so aus:

$ git stash pop
[...]
Dropped refs/stash@{0} (2ca03e22256be97f9e40f08e6d6773c7d41dbfd1)

(Beachten Sie, dass git stash drop produziert auch die gleiche Linie.)

Um diesen Vorrat zurück zu bekommen, lauf einfach git branch tmp 2cae03eund du wirst es als Zweig bekommen. Um dies in einen Stash zu konvertieren, führe folgendes aus:

git stash apply tmp
git stash

Wenn Sie es als Zweig haben, können Sie es auch frei manipulieren. zum Beispiel, um es zu pflücken oder zu verschmelzen.


597
2017-10-21 03:13



Ich wollte nur diesen Zusatz zur akzeptierten Lösung erwähnen. Es war für mich nicht sofort offensichtlich, als ich diese Methode zum ersten Mal ausprobierte (vielleicht hätte es sein sollen), aber um den Stash aus dem Hash-Wert zu übernehmen, benutze einfach "git stash apply":

$ git stash apply ad38abbf76e26c803b27a6079348192d32f52219

Als ich neu bei Git war, war mir das nicht klar, und ich versuchte verschiedene Kombinationen von "Git-Show", "Git-Anwendung", "Patch", etc.


231
2018-03-03 20:28



Ich habe gerade einen Befehl erstellt, der mir geholfen hat, mein verlorenes Stash-Commit zu finden:

for ref in `find .git/objects | sed -e 's#.git/objects/##' | grep / | tr -d /`; do if [ `git cat-file -t $ref` = "commit" ]; then git show --summary $ref; fi; done | less

Dies listet alle Objekte in der .git / objects-Baumstruktur auf, sucht nach den Objekten, die vom Typ commit sind, und zeigt dann eine Zusammenfassung der einzelnen Objekte an. Von diesem Punkt an war es nur eine Frage der Durchsicht der Commits, ein passendes "WIP on work" zu finden: 6a9bb2 ("work" ist mein Zweig, 619bb2 ist ein neuer Commit).

Ich stelle fest, dass ich dieses Problem nicht habe, wenn ich "git stash apply" anstelle von "git stash pop" verwende, und wenn ich "git stash save" verwende Botschaft"Dann könnte das Commit leichter zu finden gewesen sein.

Update: Mit Nathans Idee wird das kürzer:

for ref in `git fsck --unreachable | grep commit | cut -d' ' -f3`; do git show --summary $ref; done | less

68
2017-09-18 02:10



Um die Liste der Stashes zu erhalten, die sich noch in Ihrem Repository befinden, aber nicht mehr erreichbar sind:

git fsck --unreachable | grep commit | cut -d" " -f3 | xargs git log --merges --no-walk --grep=WIP

Wenn du deinem Stash einen Titel gegeben hast, ersetze "WIP" in -grep=WIP am Ende des Befehls mit einem Teil Ihrer Nachricht, z.B. -grep=Tesselation.

Der Befehl grepping für "WIP", weil die Standard-Commit-Nachricht für einen Stash in der Form ist WIP on mybranch: [previous-commit-hash] Message of the previous commit.


56
2018-05-04 06:42



git fsck --unreachable | grep commit sollte das sha1 zeigen, obwohl die Liste, die es zurückgibt, ziemlich groß sein könnte. git show <sha1> zeigt an, ob es das gewünschte Commit ist.

git cherry-pick -m 1 <sha1> wird das Commit auf den aktuellen Zweig zusammenführen.


36
2017-09-18 02:08



Wenn du einen verlorenen Stash wiederherstellen willst, musst du zuerst den Hash deines verlorenen Stash finden.

Wie Aristoteles Pagaltzis vorgeschlagen hat git fsck sollte dir helfen.

Persönlich benutze ich meine log-all Alias, die mir jedes Commit (wiederherstellbare Commits) anzeigt, um eine bessere Sicht auf die Situation zu haben:

git log --graph --decorate --pretty=oneline --abbrev-commit --all $(git fsck --no-reflogs | grep commit | cut -d' ' -f3)

Sie können eine noch schnellere Suche durchführen, wenn Sie nur nach "WIP on" -Nachrichten suchen.

Sobald du dein sha1 kennst, änderst du einfach dein Stash-Reflog, um das alte Stash hinzuzufügen:

git update-ref refs/stash ed6721d

Wahrscheinlich werden Sie eine verknüpfte Nachricht bevorzugen -m

git update-ref -m "$(git log -1 --pretty=format:'%s' ed6721d)" refs/stash ed6721d

Und Sie werden das sogar als Alias ​​verwenden wollen:

restash = !git update-ref -m $(git log -1 --pretty=format:'%s' $1) refs/stash $1

23
2018-06-23 14:20



Ich mochte den Ansatz von Aristoteles, aber ich benutzte GITK nicht gern ... wie ich es gewohnt bin, GIT von der Kommandozeile aus zu benutzen.

Stattdessen nahm ich die dangling commits und gab den Code in eine DIFF-Datei zur Überprüfung in meinem Code-Editor aus.

git show $( git fsck --no-reflog | awk '/dangling commit/ {print $3}' ) > ~/stash_recovery.diff

Jetzt können Sie die resultierende diff / txt-Datei (in Ihrem Home-Ordner) in Ihren TXT-Editor laden und den tatsächlichen Code und die resultierende SHA anzeigen.

Dann benutze es einfach

git stash apply ad38abbf76e26c803b27a6079348192d32f52219

15
2018-01-07 20:17



In OSX mit git v2.6.4 starte ich einfach git stash drop aus Versehen, dann fand ich es unter den Schritten

Wenn Sie den Namen des Stash kennen, dann verwenden Sie:

$ git fsck --unreachable | grep commit | cut -c 20- | xargs git show | grep -B 6 -A 2 <name of the stash>

ansonsten finden Sie die ID aus dem Ergebnis manuell mit:

$ git fsck --unreachable | grep commit | cut -c 20- | xargs git show

Wenn Sie die Commit-ID gefunden haben, drücken Sie einfach den Git Stash apply {commit-id}

Hoffe das hilft jemandem schnell


12
2018-06-09 13:19



Windows PowerShell entspricht gitk:

gitk --all $(git fsck --no-reflog | Select-String "(dangling commit )(.*)" | %{ $_.Line.Split(' ')[2] })

Es gibt wahrscheinlich einen effizienteren Weg, dies in einer Pipe zu tun, aber das macht den Job.


11
2018-01-07 23:22



Ich möchte zu der akzeptierten Lösung einen weiteren guten Weg hinzufügen, um alle Änderungen zu durchlaufen, wenn Sie entweder gitk nicht verfügbar haben oder kein X für die Ausgabe.

git fsck --no-reflog | awk '/dangling commit/ {print $3}' > tmp_commits

for h in `cat tmp_commits`; do git show $h | less; done

Dann erhalten Sie alle Diffs für diese Hashes nacheinander angezeigt. Drücken Sie 'q', um zum nächsten Diff zu gelangen.


10
2018-01-04 12:32