1684 Stimmen

Wie kann ich git reset --hard HEAD~1 rückgängig machen?

Ist es möglich, die durch den folgenden Befehl verursachten Änderungen rückgängig zu machen? Wenn ja, wie?

git reset --hard HEAD~1

15 Stimmen

Ich habe eine vollständige Anleitung zur Wiederherstellung eines verlorenen Commits mit Git geschrieben. Es gibt sogar Illustrationen :-) [Check it out][fixLink] [fixLink]: programblings.com/2008/06/07/

39 Stimmen

--hard verwirft unbestätigte Änderungen. Da diese nicht von Git verfolgt werden, gibt es keine Möglichkeit, sie mit Git wiederherzustellen.

0 Stimmen

24voto

Jörg W Mittag Punkte 349574

Wenn Sie Ihr Repository noch nicht in den Müll geworfen haben (z. B. mit git repack -d o git gc (aber beachten Sie, dass die Garbage Collection auch automatisch erfolgen kann), dann ist Ihr Commit immer noch da - er ist nur nicht mehr über den HEAD erreichbar.

Sie können versuchen, Ihren Commit zu finden, indem Sie sich die Ausgabe von git fsck --lost-found .

Neuere Versionen von Git verfügen über ein so genanntes "reflog", das alle Änderungen an den Referenzdateien protokolliert (im Gegensatz zu den Änderungen am Inhalt des Repositorys). So wird zum Beispiel jedes Mal, wenn Sie Ihren HEAD wechseln (d.h. jedes Mal, wenn Sie eine git checkout zu wechseln), die protokolliert werden. Und, natürlich, Ihr git reset manipulierte auch den HEAD, so dass dies ebenfalls protokolliert wurde. Sie können auf ältere Zustände Ihrer Refs auf ähnliche Weise zugreifen wie auf ältere Zustände Ihres Repositorys, indem Sie eine @ Zeichen anstelle eines ~ , wie git reset HEAD@{1} .

Es hat eine Weile gedauert, bis ich den Unterschied zwischen HEAD@{1} und HEAD~1 verstanden habe, deshalb hier eine kleine Erklärung:

git init
git commit --allow-empty -mOne
git commit --allow-empty -mTwo
git checkout -b anotherbranch
git commit --allow-empty -mThree
git checkout master # This changes the HEAD, but not the repository contents
git show HEAD~1 # => One
git show HEAD@{1} # => Three
git reflog

Also, HEAD~1 bedeutet "Gehe zu dem Commit vor dem Commit, auf das HEAD gerade zeigt", während HEAD@{1} bedeutet: "Gehe zu der Übergabe, auf die HEAD gezeigt hat, bevor er auf den aktuellen Punkt gezeigt hat".

So können Sie Ihre verlorene Übertragung leicht finden und wiederherstellen.

2 Stimmen

Eine andere Erklärung, die meiner Meinung nach klarer wäre: HEAD~1 bedeutet "zum Elternteil von HEAD gehen", während HEAD@{1} "einen Schritt zurück in der Geschichte von HEAD gehen" bedeutet.

1 Stimmen

Das Problem ist, dass der Begriff "Geschichte" in VCS wirklich überladen ist. Eine andere Möglichkeit, dies auszudrücken, wäre, dass ~ rückwärts geht in Geschichte schreiben , während @ rückwärts in chronologische oder zeitliche Geschichte . Aber keine der drei Versionen ist besonders gut.

0 Stimmen

@kizzx2 (und Jorg), diese 3 Erklärungen sind zusammengenommen sehr hilfreich - danke

20voto

CodeWizard Punkte 108377

Bevor wir antworten, sollten wir einige Hintergrundinformationen hinzufügen, um zu erklären, was dies ist HEAD .

First of all what is HEAD?

HEAD ist einfach ein Verweis auf die aktuelle Übertragung (latest) auf dem aktuellen Zweig.
Es kann nur eine einzige HEAD zu jedem beliebigen Zeitpunkt. (ausgenommen git worktree )

Der Inhalt von HEAD ist gespeichert in .git/HEAD und enthält die 40 Bytes SHA-1 der aktuellen Übertragung.


detached HEAD

Wenn Sie nicht auf dem neuesten Stand sind - was bedeutet, dass HEAD auf eine frühere Übertragung in der Historie verweist, heißt es detached HEAD .

enter image description here

In der Befehlszeile sieht es dann so aus - SHA-1 anstelle des Zweignamens, da die HEAD nicht auf die Spitze des aktuellen Zweigs zeigt

enter image description here


Ein paar Möglichkeiten, wie man sich von einem abgetrennten HEAD erholen kann:


git checkout

git checkout <commit_id>
git checkout -b <new branch> <commit_id>
git checkout HEAD~X // x is the number of commits t go back

Dadurch wird ein neuer Zweig ausgecheckt, der auf den gewünschten Commit verweist.
Dieser Befehl führt einen Checkout zu einem bestimmten Commit durch.
An dieser Stelle können Sie eine Verzweigung erstellen und ab diesem Punkt mit der Arbeit beginnen.

# Checkout a given commit. 
# Doing so will result in a `detached HEAD` which mean that the `HEAD`
# is not pointing to the latest so you will need to checkout branch
# in order to be able to update the code.
git checkout <commit-id>

# create a new branch forked to the given commit
git checkout -b <branch name>

git reflog

Sie können jederzeit die reflog auch.
git reflog werden alle Änderungen angezeigt, die die HEAD und das Auschecken des gewünschten Reflog-Eintrags setzt die HEAD zurück zu diesem Commit.

Jedes Mal, wenn der HEAD geändert wird, wird ein neuer Eintrag in der reflog

git reflog
git checkout HEAD@{...}

So gelangen Sie zurück zu Ihrer gewünschten Verpflichtung

enter image description here


_git reset HEAD --hard <commit_id>_

"Bewegen" Sie Ihren Kopf zurück zum gewünschten Commit.

# This will destroy any local modifications.
# Don't do it if you have uncommitted work you want to keep.
git reset --hard 0d1d7fc32

# Alternatively, if there's work to keep:
git stash
git reset --hard 0d1d7fc32
git stash pop
# This saves the modifications, then reapplies that patch after resetting.
# You could get merge conflicts, if you've modified things which were
# changed since the commit you reset to.
  • Anmerkung: ( Seit Git 2.7 )
    können Sie auch die git rebase --no-autostash auch.


git revert <sha-1>

"Rückgängig machen" des angegebenen Commits oder Commit-Bereichs.
Der Befehl reset macht alle Änderungen, die in der gegebenen Übertragung vorgenommen wurden, "rückgängig".
Ein neuer Commit mit dem rückgängig gemachten Patch wird übertragen, während der ursprüngliche Commit ebenfalls in der Historie verbleibt.

# add new commit with the undo of the original one.
# the <sha-1> can be any commit(s) or commit range
git revert <sha-1>

Dieses Schema veranschaulicht, welcher Befehl was tut.
Wie Sie sehen können, gibt es reset && checkout ändern die HEAD .

enter image description here

1 Stimmen

Es scheint, dass Ihr git reset HEAD --hard <commit_id> Das Beispiel stammt aus stackoverflow.com/questions/4114095/ - Wenn das der Fall ist, könnten Sie bitte die Quellenangabe einfügen?

12voto

martin Punkte 271

Ich weiß, dass dies ein alter Thread ist... aber da viele Leute nach Möglichkeiten suchen, Dinge in Git rückgängig zu machen, denke ich, dass es immer noch eine gute Idee sein kann, hier weiterhin Tipps zu geben.

Wenn Sie ein "git add" ausführen oder in der Git-GuI etwas von links oben nach links unten verschieben, wird der Inhalt der Datei in einem Blob gespeichert, und der Inhalt der Datei kann aus diesem Blob wiederhergestellt werden.

Es ist also möglich, eine Datei wiederherzustellen, auch wenn sie nicht übertragen wurde, aber hinzugefügt worden sein muss.

git init  
echo hello >> test.txt  
git add test.txt  

Jetzt ist der Blob erstellt, aber er wird vom Index referenziert, so dass er mit git fsck nicht aufgelistet wird, bis wir ihn zurücksetzen. Wir setzen also zurück...

git reset --hard  
git fsck  

erhalten Sie einen baumelnden Klecks ce013625030ba8dba906f756967f9e9ca394464a

git show ce01362  

gibt Ihnen den Inhalt der Datei "hello" zurück

Um nicht referenzierte Commits zu finden, habe ich irgendwo einen Tipp gefunden, der dies vorschlägt.

gitk --all $(git log -g --pretty=format:%h)  

Ich habe es als Werkzeug in der Git-GUI und es ist sehr praktisch.

1 Stimmen

+1. Wie bereits in stackoverflow.com/a/21350689/6309 , git fsck --lost-found kann helfen.

6voto

Maciek Łoziński Punkte 764

Ich habe gerade einen Hard Reset für das falsche Projekt durchgeführt. Was mir das Leben gerettet hat, war die lokale Historie von Eclipse. IntelliJ Idea soll auch eine haben, und so kann Ihr Editor, es lohnt sich zu überprüfen:

  1. Eclipse-Hilfethema zur lokalen Geschichte
  2. http://wiki.eclipse.org/FAQ_Where_is_the_workspace_local_history_stored%3F

1 Stimmen

Jetbrains CLion local history ist großartig und hat mir 2 Stunden Arbeit erspart :)

5voto

neuron Punkte 1184

Ich habe ein kleines Skript erstellt, um das Auffinden des gesuchten Commits etwas zu erleichtern:

git fsck --lost-found | grep commit | cut -d ' ' -f 3 | xargs -i git show \{\} | egrep '^commit |Date:'

Ja, man kann es mit awk oder ähnlichem wesentlich hübscher machen, aber es ist einfach und ich brauchte es einfach. Vielleicht spart jemand anderes 30 Sekunden.

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