15%

15% auf alle Hosting-Dienste sparen

Teste deine Fähigkeiten und erhalte Rabatt auf jeden Hosting-Plan

Benutze den Code:

Skills
Anfangen
22.10.2024

Git Reset vs. Git Checkout vs. Git Revert: Ein vollständiger technischer Leitfaden

Das Verständnis des Unterschieds zwischen git reset, git checkout und git revert ist für jeden Entwickler, der mit Versionskontrolle arbeitet, unerlässlich. Kurz gesagt: git reset schreibt die Historie um, indem der HEAD-Zeiger verschoben wird; git checkout navigiert zwischen Branches, Commits oder Dateien, ohne die Historie zu verändern; und git revert macht einen Commit rückgängig, indem ein neuer inverser Commit erstellt wird, wobei die Historie intakt bleibt. Die Wahl des falschen Befehls — insbesondere auf einem gemeinsam genutzten Branch — kann die Commit-Historie Ihres Teams beschädigen oder zu unwiederbringlichem Datenverlust führen.

Dieser Leitfaden geht über die oberflächliche Syntax hinaus und erklärt die internen Git-Mechanismen, den genauen Zustand Ihres Working Trees und Index nach jeder Operation sowie die realen Szenarien, in denen jeder Befehl die richtige (oder katastrophal falsche) Wahl ist.

Wie Git den Zustand verwaltet: Die drei Bäume

Bevor Sie Befehle vergleichen, benötigen Sie ein solides mentales Modell davon, wie Git den Zustand verfolgt. Git arbeitet über drei verschiedene Ebenen:

  • Working Directory — die Dateien, die Sie auf der Festplatte sehen und bearbeiten.
  • Staging-Bereich (Index) — ein Snapshot dessen, was in den nächsten Commit einfließen wird.
  • Commit-Historie (HEAD) — die Kette unveränderlicher Commit-Objekte, die in .git/ gespeichert sind.

Jeder Rückgängig-Befehl in Git zielt auf eine oder mehrere dieser Ebenen ab. Die Verwechslung zwischen reset, checkout und revert entsteht fast immer dadurch, dass man nicht weiß, welche Ebenen ein bestimmter Befehl berührt.

git reset: Lokale Historie umschreiben

git reset verschiebt den HEAD-Zeiger des aktuellen Branches auf einen angegebenen Commit. Abhängig vom übergebenen Modus-Flag kann es auch den Index und das Working Directory aktualisieren. Es handelt sich um eine historienschreibende Operation, die bei Verwendung mit --hard als destruktiv behandelt werden sollte.

Reset-Modi erklärt

git reset --soft <commit>   # Move HEAD only; index and working tree unchanged
git reset --mixed <commit>  # Move HEAD + reset index; working tree unchanged (default)
git reset --hard <commit>   # Move HEAD + reset index + reset working tree
ModusHEAD verschobenIndex zurückgesetztWorking Tree zurückgesetztÄnderungen erhalten
--softJaNeinNeinStaged und unstaged
--mixedJaJaNeinNur unstaged
--hardJaJaJaKeine — dauerhaft verloren

Praktische Anwendungsfälle

Commits vor einem Push zusammenfassen. Wenn Sie drei unordentliche Work-in-Progress-Commits haben, die noch nicht gepusht wurden, fasst git reset --soft HEAD~3 diese zurück in den Index zusammen, sodass Sie sie als einen einzigen sauberen Commit neu committen können.

Eine versehentlich hinzugefügte Datei aus dem Staging entfernen. Das Ausführen von git reset HEAD <file> (oder git reset ohne Commit-Referenz) entfernt eine Datei aus dem Index, ohne das Working Directory zu berühren — in der Wirkung identisch mit git restore --staged <file> in Git 2.23+.

Wiederherstellung nach einem fehlgeschlagenen lokalen Merge. git reset --hard ORIG_HEAD stellt den Zustand wieder her, der unmittelbar vor einem Merge bestand, da Git das Pre-Merge-HEAD automatisch in ORIG_HEAD schreibt.

Kritische Gefahr: Pushen nach einem Reset

Wenn Sie einen Branch zurücksetzen, der bereits zu einem Remote gepusht wurde, und dann einen Force-Push durchführen, wird jeder Mitarbeiter, dessen lokaler Branch diesen Remote verfolgt, eine divergierte Historie haben. Dies ist eine der häufigsten Ursachen für verlorene Commits in Team-Umgebungen. Führen Sie niemals git reset gefolgt von git push --force auf einem gemeinsam genutzten Branch aus, ohne ausdrückliche Abstimmung im Team.

# Dangerous on shared branches — use only on private/local branches
git reset --hard HEAD~2
git push --force origin feature/my-branch

git checkout: Navigation ohne Historienänderung

git checkout ist ein vielseitiger Befehl, der den Working Tree wechselt, um einem Branch, einem bestimmten Commit oder einer einzelnen Datei zu entsprechen. Er ändert die Commit-Historie nicht. In Git 2.23 und später wurden seine Aufgaben in git switch (für Branches) und git restore (für Dateien) aufgeteilt, aber git checkout bleibt voll funktionsfähig und ist in Produktionsumgebungen nach wie vor dominant.

Syntax-Referenz

git checkout <branch_name>          # Switch to an existing branch
git checkout -b <new_branch>        # Create and switch to a new branch
git checkout <commit_hash>          # Enter detached HEAD state at a specific commit
git checkout -- <file_name>         # Discard working directory changes to a file
git checkout <commit_hash> -- <file> # Restore a single file from a specific commit

Detached HEAD-Zustand: Was er wirklich bedeutet

Wenn Sie git checkout <commit_hash> ausführen, verschiebt Git HEAD so, dass es direkt auf ein Commit-Objekt statt auf eine Branch-Referenz zeigt. Dies wird als Detached HEAD-Zustand bezeichnet. Alle Commits, die Sie in diesem Zustand machen, sind von keinem Branch aus erreichbar — sie sind verwaist und werden schließlich von Git durch Garbage Collection entfernt, es sei denn, Sie erstellen einen Branch, um sie zu erfassen.

git checkout 4f7a2c1          # HEAD now points directly to commit 4f7a2c1
git checkout -b hotfix/patch  # Rescue those commits by creating a branch

Ein häufiges reales Szenario: Ein Entwickler checkt einen alten Commit aus, um eine Regression zu testen, macht versehentlich eine Korrektur, committet sie und wechselt dann zurück zu main — wobei die Korrektur vollständig verloren geht, da sie nie an einen Branch gebunden war.

Eine einzelne Datei aus der Historie wiederherstellen

Eine der am häufigsten unterschätzten Formen von git checkout ist die gezielte Dateiwiederherstellung:

git checkout HEAD~3 -- src/config/database.php

Dies zieht database.php in dem Zustand, wie er vor drei Commits existierte, direkt in Ihren Index und Ihr Working Directory, ohne andere Dateien zu berühren oder HEAD zu verschieben. Es ist das chirurgische Äquivalent eines vollständigen Branch-Wechsels.

git revert: Sicheres Rückgängigmachen für gemeinsame Historien

git revert erstellt einen neuen Commit, der den inversen Diff eines angegebenen Commits anwendet. Der ursprüngliche Commit bleibt in der Historie unberührt. Dies ist der einzige sichere Rückgängig-Mechanismus für Commits, die bereits zu einem gemeinsam genutzten Remote-Branch gepusht wurden, da er die Historie nicht umschreibt — sondern erweitert.

Syntax-Referenz

git revert HEAD                  # Revert the most recent commit
git revert <commit_hash>         # Revert a specific commit by hash
git revert HEAD~3..HEAD          # Revert a range of commits (creates multiple revert commits)
git revert -n <commit_hash>      # Stage the revert without committing (--no-commit)

Das –no-commit-Flag: Reverts bündeln

Beim Rückgängigmachen mehrerer Commits kann das Erstellen eines Revert-Commits pro ursprünglichem Commit das Log verschmutzen. Das -n– (oder --no-commit-)Flag staged alle Umkehrungen ohne Commit, sodass Sie diese in einem einzigen Revert-Commit bündeln können:

git revert -n HEAD~4..HEAD
git commit -m "Revert: roll back broken authentication refactor"

Reverts von Merge-Commits erfordern besondere Sorgfalt

Das Rückgängigmachen eines Merge-Commits erfordert die Angabe des Mainline-Elternteils mit dem -m-Flag, da Git wissen muss, welche Seite des Merges als die „korrekte” Historie behandelt werden soll:

git revert -m 1 <merge_commit_hash>

Hier bezeichnet -m 1 den ersten Elternteil (typischerweise den Branch, in den gemergt wurde) als Mainline. Das Weglassen dieses Flags bei einem Merge-Commit führt dazu, dass Git einen Fehler auslöst. Dies ist ein häufiger Stolperstein beim Rückgängigmachen eines fehlerhaften Release-Merges in CI/CD-Pipelines.

Direkter Vergleich: Reset vs. Checkout vs. Revert

Kriterium`git reset``git checkout``git revert`
Ändert Commit-HistorieJaNeinNein (erweitert sie)
Beeinflusst Working DirectoryMit --hard oder --mixedJaJa (über neuen Commit)
Beeinflusst Staging-Bereich (Index)Ja (außer --soft)Nur bei Datei-FormNein
Sicher auf gemeinsamen/Remote-BranchesNeinJa (nur lesend)Ja
Erstellt einen neuen CommitNeinNeinJa
UmkehrbarTeilweise (über ORIG_HEAD)JaJa
Verarbeitet Merge-CommitsNeinJa (Navigation)Ja (mit -m)
Modernes Äquivalent in Git 2.23+Gleichgit switch / git restoreGleich

Wann welcher Befehl verwendet werden sollte: Entscheidungsmatrix

Verwenden Sie git reset wenn:

  • Sie an einem lokalen, nicht gepushten Branch arbeiten und Commits bereinigen, zusammenfassen oder verwerfen möchten.
  • Sie Dateien vor einem Commit aus dem Staging entfernen müssen.
  • Sie einen lokalen Merge rückgängig machen möchten, der noch nicht geteilt wurde.
  • Sie der einzige Entwickler auf einem Feature-Branch sind und dessen Historie vor dem Öffnen eines Pull Requests umschreiben müssen.

Verwenden Sie git checkout wenn:

  • Sie während der aktiven Entwicklung zwischen Branches wechseln müssen.
  • Sie den Zustand des Repositories bei einem historischen Commit inspizieren möchten, ohne etwas zu ändern.
  • Sie eine einzelne Datei auf ihren Zustand bei einem bestimmten Commit zurücksetzen müssen.
  • Sie einen neuen Branch von einem bestimmten Punkt in der Historie erstellen.

Verwenden Sie git revert wenn:

  • Ein Commit bereits zu einem Remote- oder gemeinsam genutzten Branch gepusht wurde.
  • Sie in einem Team arbeiten und eine transparente, nachvollziehbare Historie pflegen müssen.
  • Sie einen bestimmten Commit rückgängig machen müssen, der nicht der aktuellste ist (nicht-linearer Revert).
  • Ihr Projekt Compliance- oder Audit-Anforderungen hat, bei denen das Löschen von Historie verboten ist.

Erweitertes Szenario: Wiederherstellung nach git reset –hard

Wenn Sie versehentlich git reset --hard ausgeführt und Commits verloren haben, sind diese nicht sofort weg. Gits Reflog zeichnet jede Position auf, auf die HEAD gezeigt hat, auch nach einem Hard Reset:

git reflog
# Output example:
# a1b2c3d HEAD@{0}: reset: moving to HEAD~3
# 7e8f9a0 HEAD@{1}: commit: Add payment gateway integration
# ...

git reset --hard HEAD@{1}   # Restore to the commit before the accidental reset

Die Reflog-Einträge laufen standardmäßig nach 90 Tagen ab (gc.reflogExpire), daher ist dieses Wiederherstellungsfenster nicht unbegrenzt. Auf einem Produktionsserver oder einer VPS Hosting-Umgebung, auf der ein selbst gehosteter Git-Dienst wie Gitea oder GitLab läuft, sollten Sie sicherstellen, dass Ihr .git-Verzeichnis in regelmäßige Backup-Routinen einbezogen wird, genau wegen dieses Ablaufs.

Ihre Git-Infrastruktur hosten

Das Betreiben eines selbst gehosteten Git-Servers — ob GitLab CE, Gitea oder Gogs — erfordert zuverlässige Speicher-I/O und konsistente Verfügbarkeit. Eine einzelne beschädigte Pack-Datei oder ein unterbrochener Push während eines git gc-Zyklus kann die Repository-Integrität beschädigen. Für Teams, die mehrere Repositories verwalten, bietet ein Dedicated Server isolierte Ressourcen, vollständigen Root-Zugriff zur Feinabstimmung der Git-Einstellungen core.packedGitWindowSize und pack.threads sowie den NVMe-Durchsatz, der für große Monorepos benötigt wird.

Für kleinere Teams oder einzelne Entwickler, die eine saubere Linux-Umgebung zum Ausführen von Git-Hooks, CI-Skripten und Deployment-Pipelines benötigen, bietet ein VPS mit cPanel eine verwaltete Steuerungsebene zusammen mit vollem SSH-Zugriff — wodurch der Aufwand für die manuelle Serververwaltung entfällt, während die Flexibilität zur Konfiguration von Git-Server-seitigen Hooks und Zugriffskontrollen erhalten bleibt.

Wenn Ihr Workflow automatisierte Deployments beinhaltet, die durch git push ausgelöst werden, ist die Absicherung Ihres Servers mit einem gültigen SSL-Zertifikat unerlässlich — sowohl zur Verschlüsselung von Webhook-Payloads als auch zur Authentifizierung HTTPS-basierter Git-Remotes, ohne die Zertifikatsverifizierung zu deaktivieren.

Wichtige technische Erkenntnisse

  • git reset --hard ist der einzige der drei Befehle, der zu permanentem, unwiederbringlichem Datenverlust führen kann, wenn das Reflog abgelaufen ist.
  • git revert ist der einzige Befehl, der nach einem git push sicher verwendet werden kann, ohne einen Force-Push zu erfordern.
  • Der Detached-HEAD-Zustand durch git checkout <hash> löscht keine Commits — aber alle neuen Commits, die in diesem Zustand gemacht werden, sind verwaist, es sei denn, Sie führen sofort git checkout -b <new_branch> aus.
  • Das -n-Flag bei git revert ist entscheidend für ein sauberes Log beim gleichzeitigen Rückgängigmachen mehrerer Commits.
  • Git 2.23+ teilt git checkout zur Klarheit in git switch und git restore auf — das Verständnis des ursprünglichen Befehls macht beide modernen Alternativen sofort intuitiv.
  • Überprüfen Sie immer Ihren aktuellen Branch mit git status und git log --oneline -5, bevor Sie eine Rückgängig-Operation ausführen.
  • Erzwingen Sie auf gemeinsam genutzter Infrastruktur Branch-Schutzregeln (GitHub, GitLab und Gitea unterstützen dies alle), um git push --force auf main– und release-Branches auf Serverebene zu blockieren.

Häufig gestellte Fragen

Was ist der Unterschied zwischen git reset --soft und git reset --mixed?

Beide verschieben HEAD auf den angegebenen Commit, aber --soft lässt Ihre Änderungen im Index staged, während --mixed (der Standard) auch den Index leert und Änderungen nur im Working Directory belässt. Keine der beiden Optionen berührt Dateien auf der Festplatte.

Kann ich Commits nach git reset --hard wiederherstellen?

Ja, innerhalb des Reflog-Ablaufzeitraums (standardmäßig 90 Tage). Führen Sie git reflog aus, um den Commit-Hash des verlorenen Zustands zu finden, und führen Sie dann git reset --hard <hash> oder git checkout -b recovery <hash> aus, um ihn wiederherzustellen.

Warum erfordert git revert bei einem Merge-Commit das -m-Flag?

Ein Merge-Commit hat zwei Elternteile. Git kann nicht bestimmen, welchen Diff des Elternteils es invertieren soll, ohne dass Sie die Mainline angeben. -m 1 weist Git an, den ersten Elternteil als Trunk zu behandeln und die durch den gemergten Branch eingeführten Änderungen rückgängig zu machen.

Ist git checkout -- <file> dasselbe wie git restore <file>?

Funktional ja — beide verwerfen nicht gestagete Änderungen im Working Directory an einer Datei, indem sie sie aus dem Index wiederherstellen. git restore wurde in Git 2.23 als weniger mehrdeutiger Ersatz eingeführt, aber git checkout -- <file> liefert auf allen Git-Versionen identische Ergebnisse.

Wann sollte ich git reset auf einem Branch absolut niemals verwenden?

Verwenden Sie git reset (insbesondere mit --hard oder --mixed) niemals auf einem Branch, den andere Entwickler bereits geklont oder gepullt haben. Dadurch divergiert ihre lokale Historie von der Remote, was jeden Mitarbeiter dazu zwingt, einen erzwungenen Reset oder Re-Clone durchzuführen — und riskiert, Commits stillschweigend zu verwerfen, die nur auf ihren Rechnern existieren.

15%

15% auf alle Hosting-Dienste sparen

Teste deine Fähigkeiten und erhalte Rabatt auf jeden Hosting-Plan

Benutze den Code:

Skills
Anfangen