Oh Shit, Git!?!

Git ist schwer: Fehler zu machen ist leicht, und herauszufinden wie man sie wieder behebt ist am Anfang fast unmöglich. Auch die Dokumentation hilft oft nicht weiter, weil man erst die passenden Begriffe kennen muss, mit denen man sein Problem lösen kann.

Deswegen folgen hier einige Situationen, in denen ich mich schon befunden habe, und wie ich da wieder rausgekommen bin – alles in simpler Sprache.

Oh shit, ich habe etwas komplett verkackt! Bitte sag mir, dass git eine magische Zeitmaschine eingebaut hat!?!

git reflog
# Du siehst eine Liste mit allem, was du in
# git getan hast, in allen Branches.
# Jeder Eintrag hat einen Index: HEAD@{index}
# Finde den Eintrag VOR demjenigen, der alles
# kaputt gemacht hat
git reset HEAD@{index}
# Alles ist jetzt wieder wie es vorher war

Damit kannst du Dateien zurückholen, die du gelöscht hast, oder Dinge rückgängig machen, die dein Repo zerstört haben, oder einen nicht geglückten Merge oder einfach zu einem Stand zurückkehren, als bestimmte Dinge noch funktioniert haben. Ich nutze reflog wirklich sehr häufig. Vielen Dank an die vielen, vielen, vielen Leute, die vorgeschlagen haben, es hier aufzunehmen.

Oh shit, ich habe schon commited und dann gemerkt dass ich eine kleine Änderung vergessen habe!

# Mach deine Änderung
git add . # oder füge einzelne Dateien hinzu
git commit --amend --no-edit
# Jetzt enthält dein letzter Commit auch die neuen Änderungen!
# WARNUNG: Niemals solltest du "--amend" bei einem 
# Commit verwenden, der schon gepusht wurde (es sei denn
# du bist der einzige Entwickler in dem Repo)

Normalerweise passiert mir das, wenn ich commite und dann erst Tests oder Linter laufen lasse. Dann fallen irgendwelche kleinen Formatierungsfehler auf, zum Beispiel ein vergessenes Leerzeichen. Man könnte die Änderung auch als neuen Commit erstellen und dann mit rebase -i beide Commits zusammenführen, aber das hier ist tausendmal schneller.

Warnung: Du solltest niemals das "--amend"-Flag verwenden, wenn dein Commit schon gepusht wurde. Verwende das nur bei lokalen Commits, ansonsten wird es kompliziert.

Oh shit, Ich muss die letzte Commit-Message ändern!

git commit --amend
# Anschließend öffnet sich dein normaler Editor und
# du kannst eine neue Commit-Message eingeben

Immer diese nervigen Anforderungen für den Aufbau von Commit-Messages.

Oh shit, ich habe aus Versehen etwas auf master commited, das eigentlich auf einen eigenen Branch gehört

# Erstelle einen neuen Branch mit dem Stand des master
git branch neuer-branch-name
# Entferne den letzten Commit vom master
# und wechsel zum neuen Branch
git reset HEAD~ --hard
git checkout neuer-branch-name
# Dein Commit lebt jetzt in dem neuen Branch weiter :)

Hinweis: Das funktioniert nicht, wenn du den Commit schon auf einen öffentlichen Branch gepusht hast. Wenn du vorher schon mehr Dinge probiert hast, musst du vielleicht git reset HEAD@{anzahl-der-commits} statt HEAD~ verwenden. Vielen Dank an die vielen vielen Leute, die vorgeschlagen haben wie man dieses Problem an schnellsten löst – ich kannte diese Lösung noch nicht.

Oh shit, ich habe auf dem falschen Branch commited!

# Mach den letzten Commit rückgängig, aber erhalte die 
# Änderungen
git reset HEAD~ --soft
git stash
# Navigiere zum richtigen Branch
git checkout name-des-richtigen-branch
git stash pop
git add . # oder füge einzelne Dateien hinzu
git commit -m "Deine Nachricht hier"
# Jetzt sind die Änderungen auf dem richtigen Branch

Viele haben vorgeschlagen cherry-pick hierfür zu verwenden. Das ist auch absolut okay, also wähle die Variante, die dir besser gefällt!

git checkout name-des-richtigen-branch
# Wähle den letzten Commit vom master
git cherry-pick master
# Und lösche den Commit vom master
git checkout master
git reset HEAD~ --hard

Oh shit, ich wollte einen Diff anzeigen lassen, aber er ist leer?!

Wenn du dir sicher bist, dass du Dateien geändert hast, aber diff trotzdem nichts anzeigt, dann hast du die Dateien wahrcheinlich schon ge-add-et und musst deswegen ein spezielles Flag verwenden.

git diff --staged

Das gehört zur Kategorie ¯\_(ツ)_/¯ (Ja, ich weiß dass das Verhalten ein Feature ist, aber für Einsteiger ist das super verwirrend!)

Oh shit, ich muss einen Commit rückgängig machen, der schon 5 Commits zurückliegt!

# Finde den betreffenden Commit
git log
# Verwende die Pfeiltasten um in der History zu scrollen
# und kopiere dir den Hash des betreffenden Commits
git revert [betreffender hash]
# git erstellt einen neuen Commit, der den gewählten
# Commit rückgängig macht. Du musst dafür noch eine
# Commit-Message eingeben oder einfach abspeichern

Man muss also doch nicht alten Code auswählen und in die aktuellen Dateien einfügen, um Änderungen rückgängig zu machen. Wenn du einen Bug commited hast, kannst du also den ganzen commit mit revert wieder zurücknehmen.

Du kannst auch nur die Änderungen in einer einzigen Datei rückgängig machen, anstatt eines ganzen Commits. Aber in typischer Git-Manier sind das natürlich komplett andere Befehle. Wäre ja sonst auch zu einfach!

Oh shit, ich muss Änderungen an einer einzigen Datei rückgängig machen!

# Finde den Hash eines Commits vor deinen Änderungen
git log
# Verwende die Pfeiltasten um in der History zu scrollen
# und kopiere dir den entsprechenden Hash
git checkout [gewählter hash] -- pfad/zur/datei
# Die alte Version ist jetzt wiederhergestellt
git commit -m "Wow, rückgängig machen ohne Copy & Paste"

Als ich das herausgefunden habe, war das für mich ein riesiges Ding! Ernsthaft, auf welchem verdammten Planeten macht es Sinn, den Befehl zum rückgängig machen von Änderungen in einer Datei checkout -- zu nennen :shakes-fist-at-linus-torvalds:

Scheiß Unordnung, ich gebe auf!

cd ..
sudo rm -r scheiss-git-repo
git clone https://some.github.url/scheiss-git-repo.git
cd scheiss-git-repo

Danke an Eric V. für diesen Tipp. Alle Beschwerden über die Verwendung von sudo bitte an ihn schicken.

Aber mal ernsthaft: wenn dein Branch soo verhunzt ist, dass du den Stand deines Repos auf den Stand auf dem Git-Server zurücksetzen musst, dann solltest du das hier ausprobieren. Aber aufpassen, denn diese Kommandos lassen sich nicht rückgängig machen!

# Hole den neusten Stand vom Server
git fetch origin
git checkout master
git reset --hard origin/master
# Lösche alle Dateien und Ordner, die noch nicht 
# eingecheckt wurden
git clean -d --force
# Wiederhole checkout/reset/clean für jeden verhunzten Branch

*Disclaimer: Diese Seite soll keine umfangreiche Dokumentation sein. Ja, es gibt andere Wege um dieselben Dinge zu erreichen, vielleicht auch elegantere. Aber ich habe diese Schritte durch Trial and Error und nach vielem Fluchen und Ausrasten zusammengetragen, und hatte eben die verrückte Idee, sie auch in der entsprechenden Ausdrucksweise zu teilen. Take it or leave it!

Vielen Dank an alle, die sich freiwillig gemeldet haben, um die Website in neue Sprachen zu übersetzen. Ihr seid die Besten! Michael Botha (af) · Khaja Md Sher E Alam (bn) · Eduard Tomek (cs) · Moritz Stückler (de) · Franco Fantini (es) · Hamid Moheb (fa) · Senja Jarva (fi) · Michel (fr) · Alex Tzimas (gr) · Elad Leev (he) · Aryan Sarkar (hi) · Ricky Gultom (id) · fedemcmac (it) · Meiko Hori (ja) · Zhunisali Shanabek (kk) · Gyeongjae Choi (ko) · Rahul Dahal (ne) · Martijn ten Heuvel (nl) · Łukasz Wójcik (pl) · Davi Alexandre (pt_BR) · Catalina Focsa (ro) · Daniil Golubev (ru) · Nemanja Vasić (sr) · Björn Söderqvist (sv) · Kitt Tientanopajai (th) · Taha Paksu (tr) · Andriy Sultanov (ua) · Tao Jiayuan (zh) . Mit zusätzlicher Hilfe von Allie Jones · Artem Vorotnikov · David Fyffe · Frank Taillandier · Iain Murray · Lucas Larson · Myrzabek Azil

Wenn Sie beim Hinzufügen einer Übersetzung in Ihre Sprache helfen möchten, senden Sie einen PR auf GitHub