Webentwicklung

Den letzten Commit in Git rückgängig machen, ohne Arbeit zu verlieren

Wie du den letzten Commit mit reset, revert und amend rückgängig machst, was du nutzt, wenn er schon gepusht ist, und wie du einen verlorenen Commit zurückholst.

Um den letzten Commit in Git rückgängig zu machen, hast du je nach dem, was du behalten willst, drei Möglichkeiten: git reset --soft HEAD~1 entfernt den Commit, behält die Änderungen aber im Index; git reset --hard HEAD~1 entfernt Commit und Änderungen; und git revert HEAD erzeugt einen neuen Commit, der den vorherigen aufhebt, ohne die Historie umzuschreiben. Das macht ihn zur sicheren Wahl, wenn du bereits gepusht hast.

Im Folgenden siehst du, wann du welche Variante nutzt, wie du einen Commit korrigierst statt ihn zu löschen (--amend) und wie du einen vermeintlich verlorenen Commit mit git reflog wiederherstellst.

Zuerst: Hast du gepusht?

Diese Frage entscheidet alles Weitere.

  • Du hast nicht gepusht (der Commit existiert nur auf deinem Rechner): Du kannst die Historie mit git reset oder --amend umschreiben, ohne jemanden zu stören.
  • Du hast auf einen gemeinsamen Branch gepusht: Schreibe die Historie nicht um. Nutze git revert, das einen neuen Commit hinzufügt, statt den bestehenden zu löschen. Erzwingst du nach einem Reset einen Push, hat der Rest des Teams eine andere Historie als du, und Konflikte sind garantiert.

Option 1: git reset (lokal rückgängig machen)

git reset verschiebt die Branch-Referenz (HEAD) auf einen früheren Commit. HEAD~1 bedeutet „ein Commit vor dem aktuellen“. Was mit den Änderungen dieses Commits passiert, hängt vom Modus ab:

# Entfernt den Commit; die Änderungen bleiben im Index (staged)
git reset --soft HEAD~1

# Entfernt den Commit; die Änderungen bleiben im Arbeitsverzeichnis, nicht im Index (Standardmodus)
git reset --mixed HEAD~1
git reset HEAD~1

# Entfernt den Commit UND verwirft die Änderungen. Nur über reflog umkehrbar.
git reset --hard HEAD~1
Modus Löscht den Commit? Behält die Änderungen? Wo landen sie?
--soft Ja Ja Im Index, bereit für einen neuen Commit
--mixed (Standard) Ja Ja Im Arbeitsverzeichnis, nicht im Index
--hard Ja Nein Werden verworfen

Ein typischer Fall: Du hast zu früh committet und willst noch etwas hinzufügen. git reset --soft HEAD~1, fehlende Dateien hinzufügen und erneut committen.

Um mehrere Commits rückgängig zu machen, ändere die Zahl: HEAD~3 geht drei zurück.

Option 2: git commit –amend (korrigieren statt löschen)

Willst du nur die Nachricht des letzten Commits ändern oder eine vergessene Datei hinzufügen, musst du ihn nicht rückgängig machen:

# Nur die Nachricht ändern
git commit --amend -m "Korrigierte Nachricht"

# Eine vergessene Datei zum letzten Commit hinzufügen, Nachricht behalten
git add vergessene-datei.js
git commit --amend --no-edit

--amend ersetzt den letzten Commit durch einen neuen (mit anderem Hash). Es ist also ein Umschreiben der Historie: Dieselbe Regel gilt, nicht verwenden, wenn du bereits auf einen gemeinsamen Branch gepusht hast.

Option 3: git revert (rückgängig machen ohne Umschreiben)

git revert erzeugt einen neuen Commit, der die umgekehrten Änderungen des angegebenen Commits anwendet. Die Historie behält sowohl den ursprünglichen Commit als auch seine Aufhebung, deshalb ist es auf gemeinsamen Branches sicher.

# Letzten Commit aufheben und den Editor für die Nachricht öffnen
git revert HEAD

# Dasselbe, ohne Editor
git revert --no-edit HEAD

# Einen bestimmten Commit per Hash aufheben
git revert a1b2c3d

Ist der aufzuhebende Commit ein Merge, musst du mit -m 1 angeben, welcher Elternteil erhalten bleibt; die Dokumentation zu git-revert erklärt es im Detail.

Wenn du gepusht hast und trotzdem umschreiben musst

Es gibt Situationen, in denen ein Reset nach dem Push unvermeidbar ist (zum Beispiel hast du versehentlich ein Passwort gepusht und musst es aus der Historie entfernen). Dann:

git reset --hard HEAD~1
git push --force-with-lease

--force-with-lease ist --force vorzuziehen: Es überschreibt den Remote-Branch nur, wenn seit deinem letzten fetch niemand gepusht hat, und verhindert so, dass du fremde Arbeit versehentlich löschst. Informiere das Team, denn alle müssen ihre Kopie aktualisieren. Und denk daran: Ein veröffentlichtes Geheimnis gilt als kompromittiert und muss rotiert werden, auch wenn du es aus der Historie entfernst.

Ich habe reset –hard ausgeführt und brauche den Commit zurück

git reflog protokolliert alle Stellen, auf die HEAD in den letzten Wochen gezeigt hat, einschließlich Commits, die auf keinem Branch mehr liegen:

git reflog
# a1b2c3d HEAD@{0}: reset: moving to HEAD~1
# e4f5g6h HEAD@{1}: commit: Formularvalidierung hinzufügen
# ...

# Zum Zustand vor dem Reset zurückkehren
git reset --hard e4f5g6h

Solange Git seine Garbage Collection nicht ausgeführt hat (standardmäßig bleiben unreferenzierte Objekte mindestens 30 Tage im Reflog), ist der Commit noch da.

Welcher Befehl: Zusammenfassung

Ich will… Befehl
Den Commit mit mehr Änderungen neu machen (nicht gepusht) git reset --soft HEAD~1
Die Dateien vor dem Commit noch einmal bearbeiten (nicht gepusht) git reset HEAD~1
Commit und Änderungen verwerfen (nicht gepusht) git reset --hard HEAD~1
Nachricht ändern oder Datei hinzufügen (nicht gepusht) git commit --amend
Einen bereits veröffentlichten Commit rückgängig machen git revert HEAD
Einen Commit nach falschem Reset wiederherstellen git reflog + git reset --hard <hash>

Fazit

Bevor du einen Commit rückgängig machst, frage dich, ob du ihn schon geteilt hast. Wenn nicht, geben dir git reset (im passenden Modus) oder --amend volle Kontrolle. Wenn ja, hält git revert die Historie für das ganze Team konsistent. Und was auch passiert: git reflog ist das Sicherheitsnetz, in Git einen Commit wirklich zu verlieren ist sehr schwer.

Quellen und Referenzen

  1. Offizielle Dokumentation: git-reset git-scm.com
  2. Offizielle Dokumentation: git-revert git-scm.com
  3. Offizielle Dokumentation: git-commit (Option --amend) git-scm.com
  4. Offizielle Dokumentation: git-reflog git-scm.com
  5. Pro Git (offizielles Buch): Dinge rückgängig machen git-scm.com
Artikel in Webentwicklung