- Da es bei Git schwierig ist, nach Lösungen zu suchen, wenn man den Namen der Fehlersituation nicht kennt, fasst diese Ressource häufige Befehle nach Recovery-Szenario so zusammen, dass man sie direkt nachschlagen und verwenden kann
- Wenn man ein Repository stark beschädigt hat oder Fehler beim Löschen oder Mergen rückgängig machen muss, kann man mit
git reflog die Arbeitshistorie finden und mit git reset HEAD@{index} zu einem früheren Zustand zurückkehren
- Kleine Korrekturen am letzten Commit oder Änderungen an der Commit-Message lassen sich schnell mit
git commit --amend erledigen; bei Commits, die bereits auf einen öffentlichen/geteilten Branch gepusht wurden, sollte man das jedoch nicht verwenden
- Wenn man auf den falschen Branch committed hat, kann man die Änderungen über den Ablauf
reset, stash, checkout, stash pop oder per cherry-pick verschieben; welche Methode sicher ist, hängt jedoch davon ab, ob bereits gepusht wurde
reset --hard und git clean -d --force, die den Zustand des Remote-Repositorys erzwingen, können sogar nicht getrackte Dateien löschen, daher sollte man vor der Ausführung genau prüfen
Warum Git-Fehler schwer zu beheben sind
- Bei Git passieren Fehler leicht, und um ein Problem zu beheben, muss man oft bereits die nötigen Begriffsnamen kennen, um danach suchen zu können
- Diese Ressource fasst häufige unangenehme Situationen in Git mit einfach verständlichem Englisch und Befehlsbeispielen zusammen
- Sie ist keine vollständige Referenz; es kann auch andere Wege geben, dieselbe Aufgabe zu erledigen
Ein Repository auf einen früheren Zustand zurücksetzen
- Wenn man ein Repository stark beschädigt hat oder gelöschte Inhalte wiederherstellen möchte, prüft man mit
git reflog die Arbeitshistorie
git reflog
# Man kann eine Liste der Git-Aktionen über alle Branches hinweg sehen
# Jeder Eintrag hat einen Index in der Form HEAD@{index}
git reset HEAD@{index}
reflog kann in folgenden Situationen genutzt werden
- Wiederherstellung versehentlich gelöschter Inhalte
- Entfernen eines Versuchs, der das Repository beschädigt hat
- Wiederherstellung nach einem schlechten Merge
- Rückkehr zu einem Zeitpunkt, an dem tatsächlich noch alles funktionierte
Den letzten Commit korrigieren
- Wenn direkt nach dem letzten Commit eine kleine Korrektur ergänzt werden muss, verwendet man
git commit --amend --no-edit
# Nach den Änderungen
git add . # oder einzelne Dateien hinzufügen
git commit --amend --no-edit
- Dieser Befehl nimmt die neuen Änderungen in den letzten Commit auf
- Man könnte dieselbe Änderung auch als neuen Commit erstellen und anschließend mit
rebase -i zusammenführen, aber amend ist deutlich schneller
- Bei Commits, die bereits auf einen öffentlichen/geteilten Branch gepusht wurden, sollte man
amend nicht verwenden
- Um nur die Message des letzten Commits zu ändern, verwendet man folgenden Befehl
git commit --amend
# Commit-Message gemäß den Anweisungen ändern
Wenn man auf den falschen Branch committed hat
- Wenn man versehentlich auf
master committed hat, der Commit aber auf einen neuen Branch gehört hätte, erstellt man aus dem aktuellen Zustand einen neuen Branch und entfernt den letzten Commit von master
git branch some-new-branch-name
git reset HEAD~ --hard
git checkout some-new-branch-name
- Diese Methode ist nicht geeignet für Commits, die bereits auf einen öffentlichen/geteilten Branch gepusht wurden
- Wenn man vorher bereits andere Versuche unternommen hat, kann statt
HEAD~ eine Form wie HEAD@{number-of-commits-back} nötig sein
- Wenn man komplett auf den falschen Branch committed hat, kann man die Änderungen über den Ablauf
reset --soft, stash, checkout, stash pop verschieben
git reset HEAD~ --soft
git stash
git checkout name-of-the-correct-branch
git stash pop
git add . # oder einzelne Dateien hinzufügen
git commit -m "your message here"
- In derselben Situation kann man auch
cherry-pick verwenden
git checkout name-of-the-correct-branch
git cherry-pick master
git checkout master
git reset HEAD~ --hard
Änderungen und ältere Commits rückgängig machen
- Wenn man Dateien geändert hat,
git diff aber leer ist, wurden die Änderungen möglicherweise bereits gestaged; dann ist das Flag --staged nötig
git diff --staged
- Um Änderungen von vor einigen Commits rückgängig zu machen, sucht man mit
git log den Hash und führt git revert aus
git log
git revert [saved hash]
git revert erstellt einen neuen Commit, der den betreffenden Commit rückgängig macht
- Wenn nicht der gesamte Commit, sondern nur eine bestimmte Datei zurückgesetzt werden soll, verwendet man den Ablauf, bei dem die alte Version der Datei in den Index übernommen und anschließend committed wird
git log
git checkout [saved hash] -- path/to/file
git commit -m "Wow, you don't have to copy-paste to undo"
Den Zustand des Remote-Repositorys erzwingen
- Statt das Repository zu löschen und erneut zu klonen, kann man Git-Befehle verwenden, um es an den Zustand des Remote-Repositorys anzugleichen
git fetch origin
git checkout master
git reset --hard origin/master
git clean -d --force
git reset --hard origin/master setzt den Branch auf den Zustand des Remote-master
git clean -d --force löscht nicht getrackte Dateien und Verzeichnisse
- Für jeden beschädigten Branch muss man
checkout, reset und clean wiederholen
- Diese Aktionen sind destruktiv und nicht wiederherstellbar, daher ist vor der Ausführung Vorsicht geboten
Umfang und Beiträge
- Diese Ressource ist keine vollständige Git-Referenz, sondern eine Sammlung praktischer Recovery-Abläufe, die durch Trial-and-Error gefunden wurden
- Wer beim Hinzufügen von Übersetzungen helfen möchte, kann auf GitHub einen PR einreichen
1 Kommentare
Hacker-News-Kommentare
Es gibt ein paar Dinge, die ich ändern würde: Ich würde immer
git switchstattgit checkoutverwenden undreset --hardmöglichst vermeiden.Wenn man zum Beispiel „versehentlich auf master committet hat, obwohl der Commit auf einen neuen Branch hätte gehört“, kann man das mit
git branch some-new-branch-name,git switch -d HEAD~,git switch -C master,git switch some-new-branch-nameerledigen.Wenn man „auf den falschen Branch committet hat“, würde ich auf den richtigen Branch mit
git switchwechseln und danngit cherry-pick master,git switch -d master~,git switch -C masterverwenden.Und für „alles aufgeben und zum Remote-Stand zurückkehren“ würde ich es so aufbauen:
git fetch origin,git restore -WS .,git clean -d --force,git switch -d origin/master,git switch -C masterSelbst wenn man das Git-Modell gut versteht, sind solche Rezepte nicht intuitiv, und man muss auch noch die sonderbaren Verhaltensweisen der einzelnen Befehle kennen.
Zum Beispiel gibt es zwar schon
git switch -c some-new-branch-name, aber ein Befehl wiegit move-branch master HEAD~, der nur den Branch auf einen anderen Commit verschiebt, wäre viel intuitiver.git checkoutliebergit switchundgit restorezu verwenden, aber diese Befehle wurden erst in Git v2.23 eingeführt, und dieses Release ist ungefähr 5 Jahre alt.Auf der Hilfeseite steht immer noch die Warnung
THIS COMMAND IS EXPERIMENTAL. THE BEHAVIOR MAY CHANGE..Natürlich steht diese Warnung schon fast seit der Einführung des Befehls dort, und nach 5 Jahren könnte man wohl aufhören, das noch experimentell zu nennen.
Trotzdem ist
git checkoutabwärtskompatibler, und man kann es auch so sehen, dass die ursprüngliche Git-Nutzung aus der Zeit widerspiegelt, in der diese Website entstanden ist.https://github.com/git/git/blob/757161efcca150a9a96b312d9e78...
https://github.com/git/git/releases/tag/v2.23.0
https://github.com/git/git/commit/4e43b7ff1ea4b6f16b93a432b6...
git add .zu lehren.Bestimmte Dateien explizit anzugeben lässt weniger Raum für spätere „Oh Mist“-Momente.
Ich würde gern wissen, warum
switchbesser alscheckoutsein soll und warum manreset --hardnicht verwenden sollte.reset --hardvermeiden“ gemeint ist.Mich würde konkret interessieren, warum es in der Praxis nicht ausreichen soll; ich benutze es ziemlich oft zusammen mit
alias git-restore-file='git restore --source=HEAD --', und es scheint gut zu funktionieren.Wenn man Git lernt, sollte man anfangen, GUI-Clients als Standardweg zu empfehlen.
Damit wäre ein Drittel dieser Probleme gelöst, und ein weiteres Drittel würde gar nicht erst entstehen.
Wenn man später entscheidet, dass die Kommandozeile schneller ist, kann man sie dann immer noch benutzen; zuerst müssen die Leute sehen, wie man visuell mit dem Baum interagiert.
Ich persönlich mag fork.dev, aber die Clients heutzutage sind im Großen und Ganzen ähnlich.
Mit Magit sind Dinge wie „Cherry-Pick abbrechen“ innerhalb der Oberfläche auffindbar, und dafür gibt es dieselben Tastenkürzel wie für andere „X abbrechen“-Aktionen.
Wenn ich nur die Git-Kommandozeile gehabt hätte, hätte ich gar nicht gewusst, wo ich anfangen soll.
Ich habe bei interaktiven Rebase-Vorgängen auch schon Commits gelöscht, die ich nicht hätte löschen dürfen, aber da bei jedem Startpunkt eines Rebase ein über den Reflog erreichbarer Snapshot entsteht, kann man einen verpfuschten Rebase sicher zurückdrehen.
Die Reflog-Oberfläche von Magit ist dieselbe wie die Log-Oberfläche, sodass ich mich dort auch beim ersten Mal nicht verirrt habe; mit der Git-CLI hätte ich wahrscheinlich nicht verstanden, was gerade passiert.
Mir gefällt, dass
jj, wenn man es ohne Argumente ausführt, den relevanten Teil des Commit-Baums und die aktuelle Position zeigt.Man sieht auf einen Blick den Commit, an dem man gerade arbeitet, verbundene Branches und deren Verlauf, andere aktive Branches im Repository sowie die Nachricht und den Änderungsstatus jedes Commits, was hervorragend dabei hilft, wieder Orientierung zu gewinnen.
Aber fast niemand hört darauf, und am Ende quälen sie sich mit der CLI herum, ruinieren ihre Branches, fallen hinter main zurück und bekommen Angst vor Rebase.
In einer UI ließe sich vieles per Drag-and-Drop oder auf ähnliche Weise lösen, und so wirkt es fast wie eine Form von Selbstquälerei.
Auch wenn die Oberfläche schrecklich war, war es für die Kommunikation einfacher, dieselbe Oberfläche zu verwenden wie die anderen im Team, und auch Online-Material zur Problemlösung ging meist vom „üblichen Weg“ aus und ließ sich daher leichter nutzen.
Dass Git im April 2025 schon 20 Jahre alt wird, fühlt sich ziemlich seltsam an
Ich war damals dabei und erinnere mich noch daran, wie ich überlegte, ob ich git, darcs oder bazaar lernen sollte, um SVN oder CVS zu ersetzen
Ich weiß nicht mehr, ob ich auch Mercurial ausprobiert habe
Ich frage mich, ob der „GitHub-Effekt“ den Bedarf an neuen Marktteilnehmern bei Versionsverwaltungssystemen praktisch abgewürgt hat
Vielleicht war das Yak-Shaving irgendwann einfach weit genug getrieben
Ich bin vollständig auf jj umgestiegen, und durch die Git-Kompatibilität muss ich nicht darauf warten, dass andere mitziehen
Ich bin von mehreren Aspekten von GitHub zunehmend frustriert und hoffe, dass irgendwann alle auch darüber hinausgehen, aber der Weg dorthin wirkt nicht besonders einfach
SVN ist intuitiv und funktioniert in 99 % der Fälle gut genug, sodass man es den Leuten nicht extra „beibringen“ muss
Ich wünschte, wir würden alle aufhören, den 1337-Hacker zu spielen, und anerkennen, dass Git für die meisten ein überdimensioniertes Werkzeug ist
Ich glaube, ich habe ein ziemlich gutes mentales Modell davon, was Git macht, aber sobald die Befehle auch nur ein bisschen komplexer werden, kann ich mir die Argumente nicht merken
Die Befehle sind weder leicht auffindbar noch leicht zu merken
Ich weiß nicht, ob die Text-UI schlecht ist oder ob es einfach grundsätzlich schwierig ist, die Manipulation von Bäumen in Textform zu beschreiben
Komplexe Bäume per Text zu manipulieren, ist nicht einfach, und die Text-UI ist objektiv schlecht: https://stevelosh.com/blog/2013/04/git-koans/
Schön zu sehen, dass in diesem Thread Suchergebnisse für hg und Mercurial auftauchen
Ich kann immer noch kaum glauben, dass Mercurial die Kriege der verteilten Versionsverwaltung verloren hat, denn ich halte es für das bessere Werkzeug
Es ist benutzbar, stabil, praxiserprobt und wird aktiv gepflegt
Es kommt dem Motto „Sei die Veränderung, die du sehen willst“ nahe, also nutze es einfach
Formulierungen wie „es hat verloren“ sind kontraproduktiv, und die implizite Abschreckung solcher Aussagen hält die Akzeptanz von Mercurial niedrig
Hosting ist zumindest bei Sourcehut und heptapod.host möglich
Ich betreibe auch eine private Heptapod-Instanz; das ist ein GitLab-Fork mit nativer Mercurial-Unterstützung, und es funktioniert einfach
Git war für mich immer eine dieser Technologien, die in vieler Hinsicht nicht der Intuition folgen und deshalb nie richtig im Kopf bleiben
Wenn man es nicht schon lange benutzt, muss man für fast jede Aufgabe wahrscheinlich Google bemühen oder die man-Seiten lesen
Gerade wenn man den Schrecken erlebt hat, eine große Codebasis in SVN mit vielen Branches zu verwalten und wieder zusammenzuführen, merkt man, dass Git in diesem Punkt absurd viel besser ist
Für jemanden, der direkt mit Git einsteigt, mag die Lernkurve deutlich steiler sein, aber ich finde es trotzdem manchmal schwer zu verstehen, woran die Leute scheitern
Wenn man dafür den eingebauten Weg über
filter-branchnimmt, bekommt man nach langer Verzögerung eine Warnung, man solle lieber Control+C drücken und das Third-Party-Python-Skriptfilter-repoherunterladenNicht gerade etwas, worauf ich stolz bin, aber meine häufigste Git-Operation für den Fall „ich habe es kaputtgemacht“ ist: lokales Repository löschen, neu klonen und die Änderungen erneut anwenden
Das funktioniert in 95 % der Fälle hervorragend, und für den Rest bitte ich die DevOps-Leute um Hilfe
cp -R .git ../git-backupWenn ich es richtig schlimm vermassle, kann ich einfach das gesamte
.git-Verzeichnis durch die alte Kopie ersetzenDas ist viel schneller, als herauszufinden, wie man eine bestimmte Aktion oder ein ganzes Bündel von Aktionen korrekt rückgängig macht
Was die Leute bei Git meiner Meinung nach unbedingt verinnerlichen sollten, ist, dass Git ein append-only Datenspeicher ist
Um Arbeit ins Repository zu bekommen, muss man committen, und sobald die Arbeit einmal drin ist, lässt sie sich mit Git-Befehlen nicht mehr entfernen
Nach diesem Prinzip funktioniert auch reflog
Egal was man tut, man kann immer zu einem früheren Branch-Zustand zurückkehren und die Arbeit aus dem Datenspeicher wiederherstellen
Wenn man aber nicht committet, kann Git nicht helfen, also sollte man einfach committen
Immer committen, und wenn die Hürde dafür zu groß ist oder man es ständig vergisst, muss man die Werkzeuge verbessern
Wenn man den ganzen Tag Code schreibt, sollte man im Allgemeinen mindestens einmal pro Stunde committen
Nur eine Kleinigkeit, aber jedes Mal, wenn ich
git reflogsehe, lese ich es wie re-flogVielleicht kann ich mir den Befehl deshalb nie richtig merken, weil ich unbewusst nicht an „reference log“ denke
Stattdessen wirkt es so, als würde man Git sagen, irgendetwas wieder günstig zu verkaufen
Ich bin zwar kein Git-Nutzer, aber wenn ich so etwas sehe, denke ich immer stärker, dass
git commitan sich keine Bedeutung hat und nur der Zeitpunkt wichtig ist, an dem ein Commit gepusht oder gemergt wirdÄhnlich wie beim Speichern einer Textdatei
Man schreibt ja auch nicht jedes Mal eine kurze Nachricht, wenn man eine Datei speichert, also kann man es einfach überspringen
Nicht unbedingt kurz; je kleiner die Änderung, desto länger fällt die Erklärung manchmal aus
Für 2–3 Zeilen mit großer Wirkung habe ich auch schon 2–3 Absätze geschrieben
Ein lokaler Commit ist eine Methode, an einem Punkt, an dem alles kompiliert und funktioniert, einen Checkpoint zu erstellen
So kann man Änderungen stashen oder, wenn man etwas kaputtgemacht hat, zu einem funktionierenden Zustand zurückkehren
Vor dem Pushen kann man per Reset in passende Commits aufteilen, sodass die Remote-Historie sauber bleibt und nicht zu einem
wip-Haufen wirdOder man nutzt beim PR einen Squash Merge und bekommt so die Vorteile von beidem
Das bedeutet aber nicht, dass man sinnlose Nachrichten wie
more fixeseingeben mussNormalerweise mache ich einen ersten Commit wie
(WIP) Funktionsname, wiederhole dann Amend-Commits, bis ich zufrieden bin, und entferne am Ende(WIP)aus der NachrichtIch sehe das Git-Revisionslog als etwas Ähnliches wie so ein Tagebuch
Es ist geordneter als ein separates TODO-Dokument und regt dazu an, bereits erledigte Arbeit auf gut lesbare Weise zu beschreiben
Wenn man entscheiden muss, wie weit man zurückgehen will, kann es nützlich sein zu wissen, was man sich beim damaligen Commit gedacht hat, und falls der Ansatz falsch war, hilft es auch bei der nachträglichen Analyse
Wenn Arbeit, die noch nicht gemergt oder gepusht wurde, als separate Änderungen mit einem Ziel organisiert ist, ist es viel einfacher, nur die guten Teile zu behalten, wenn manches davon gut und manches schlecht ist
Technisch gesehen sind Commits trotzdem nicht bedeutungslos
Ohne Commits gibt es auch nichts, was man pushen oder mergen könnte
Auch jenseits der Technik ist es sehr nützlich, in Klartext festzuhalten, warum man etwas ändert
Wenn man solche Erklärungen zu oft schreiben muss, sollte man die Einheit einer „Änderung“ enger fassen oder sorgfältiger auswählen, woran man gleichzeitig arbeitet
Wenn man Git nicht verwendet, frage ich mich, womit dann Versionsverwaltung und Änderungsmanagement gemacht werden