W3docs

git rebase -i (interaktiv)

Lerne den interaktiven Rebase mit git rebase -i: Commits squashen, umbenennen, bearbeiten, löschen und neu anordnen. Mit vollständiger Befehlsreferenz.

Was ist interaktiver Rebase

Interaktiver Rebase, ausgeführt mit git rebase -i, ermöglicht es dir, eine Reihe von Commits umzuschreiben, bevor du sie teilst. Er öffnet eine bearbeitbare "To-do-Liste" der Commits, in der du Zeile für Zeile entscheidest, was mit jedem einzelnen passiert — beibehalten, die Nachricht umformulieren, in einen anderen einfalten, aufteilen, neu anordnen oder löschen. Er baut auf dem normalen git rebase auf, gibt dir aber die Kontrolle über jeden einzelnen Schritt.

Diese Seite erklärt, wie du einen interaktiven Rebase startest, welche Befehle du in der To-do-Liste verwenden kannst, die häufigsten Arbeitsabläufe (Squashing, Umbenennen, Neuanordnen, Löschen und Aufteilen von Commits), wie du vorgehst, wenn etwas schiefläuft, und die eine Regel, die alles sicher macht.

Eine interaktive Rebase-To-do-Liste, die Commits squasht und umbenennt

Ein Commit ist ein gespeicherter Schnappschuss deiner Arbeit; HEAD ist ein Zeiger auf den Commit, auf dem du dich aktuell befindest. „Geschichte umschreiben" bedeutet, neue Commits zu erzeugen, die bestehende ersetzen — Git bearbeitet einen Commit nie direkt, deshalb erhält jeder umgeschriebene Commit einen brandneuen Hash.

Einen interaktiven Rebase starten

Weise den Befehl auf den Commit vor dem ersten, den du bearbeiten möchtest — der Rebase wird alles danach erneut abspielen. Um die letzten drei Commits zu überarbeiten:

git rebase -i HEAD~3

HEAD~3 bedeutet „drei Commits vor HEAD". Du kannst auch einen expliziten Commit angeben (git rebase -i a1b2c3d) oder bei einem Branch alles seit seiner Abspaltung von einem anderen Branch rebasen (git rebase -i main).

Git öffnet deinen konfigurierten Editor mit einer Zeile pro Commit, ältester zuerst (umgekehrt zu git log):

pick a1b2c3d add login form
pick b2c3d4e fix typo
pick c3d4e5f more css tweaks

Unterhalb der Liste fügt Git ein auskommentiertes Kurzreferenzblatt aller Befehle ein. Du änderst das Wort am Anfang jeder Zeile, um eine Aktion festzulegen, kannst die Zeilen optional neu anordnen, speicherst dann und schließt. Git spielt die Commits von oben nach unten gemäß deinen Anweisungen ab. Wenn du die Datei unverändert speicherst (oder alle Zeilen löschst), tut der Rebase nichts und hält an.

Die To-do-Listen-Befehle

Jede Zeile beginnt mit einem Befehl. Das sind die am häufigsten verwendeten:

BefehlKurzWirkung
pickpCommit unverändert übernehmen.
rewordrCommit übernehmen, aber die Nachricht bearbeiten.
editeAm Commit anhalten, um den Inhalt zu ändern (amenden, aufteilen oder Dateien hinzufügen).
squashsIn den vorherigen Commit einfalten und beide Nachrichten zusammenführen.
fixupfWie squash, aber die Nachricht dieses Commits verwerfen.
dropdDen Commit vollständig entfernen (die Zeile zu löschen hat denselben Effekt).
execxEinen Shell-Befehl (z. B. Tests) an diesem Punkt im Rebase ausführen.

Es gibt keinen reorder-Befehl — du ordnest Commits neu an, indem du die Zeilen in der To-do-Liste einfach nach oben oder unten verschiebst. Zeilen werden von oben nach unten angewendet, also ist die Reihenfolge, die du hinterlässt, die Reihenfolge, in der Git sie erstellt.

Commits zusammenführen (Squashing)

Eine häufige Aufräumaktion ist das Einfalten mehrerer kleiner Commits in einen einzigen. Markiere den ersten als pick und den Rest als squash (oder fixup, um ihre Nachrichten zu verwerfen):

pick a1b2c3d add login form
squash b2c3d4e fix typo
fixup c3d4e5f more css tweaks

squash/fixup führen immer aufwärts zusammen, also in die Zeile darüber. Wenn du speicherst, kombiniert Git die drei in einen einzigen Commit. Da b2c3d4e gesquasht wurde, öffnet Git einen zweiten Editor mit beiden Commit-Nachrichten, damit du eine saubere Nachricht schreiben kannst; das fixup von c3d4e5f bringt seine Änderungen mit ein, verwirft aber seine Nachricht stillschweigend.

Wenn du nur kleine „Hoppla"-Commits in einen früheren einfalten möchtest, schau dir git commit --fixup an (siehe git commit --amend und git rebase -i --autosquash), das die Zeilen automatisch für dich markiert.

Eine Commit-Nachricht umbenennen

Um einen Tippfehler zu korrigieren oder eine Nachricht zu präzisieren, ohne den Code zu ändern, markiere die Zeile mit reword:

pick a1b2c3d add login form
reword b2c3d4e fix tpyo
pick c3d4e5f more css tweaks

Git spielt a1b2c3d unverändert ab, hält dann an und öffnet einen Editor mit der alten Nachricht von b2c3d4e, damit du sie neu schreiben kannst, und fährt dann fort. Die Änderungen des Commits bleiben unberührt — nur die Nachricht (und ihr Hash) ändert sich.

Commits neu anordnen und löschen

Um die Reihenfolge zu ändern, verschiebe die Zeilen. Um einen Commit zu löschen, markiere ihn mit drop oder lösche die Zeile. Diese To-do-Liste ordnet den CSS-Tweak vor dem Tippfehler-Fix an und löscht den Tippfehler-Commit vollständig:

pick a1b2c3d add login form
pick c3d4e5f more css tweaks
drop b2c3d4e fix typo

Das Löschen oder Neuanordnen kann Konflikte verursachen, wenn ein späterer Commit von dem abhängig war, den du entfernt oder verschoben hast — Git hält dann an und lässt dich sie auflösen.

Einen Commit aufteilen

Um einen großen Commit in mehrere aufzuteilen, markiere ihn mit edit. Git hält bei diesem Commit an, wobei er bereits angewendet ist; du machst dann den Commit rückgängig, behältst aber die Änderungen, und commitest sie in kleineren Teilen erneut:

# rebase pauses on the commit marked 'edit'
git reset HEAD~          # move the commit's changes back to the working tree
git add login.js
git commit -m "add login form markup"
git add styles.css
git commit -m "style the login form"
git rebase --continue    # resume the rest of the rebase

git reset HEAD~ macht den letzten Commit rückgängig, lässt aber seine Änderungen in deinen Dateien (siehe git reset), sodass du sie als separate, kleinere Commits stagen und committen kannst.

Abschließen oder Abbrechen

Wenn ein Schritt einen Konflikt verursacht, hält Git an, damit du ihn auflösen kannst. Bearbeite die konfliktbehafteten Dateien, stage die Korrekturen mit git add und fahre fort:

git rebase --continue

Wenn du bei einem Konflikt entscheidest, dass ein bestimmter Commit gar nicht angewendet werden soll, verwende git rebase --skip. Um den gesamten Rebase abzubrechen und genau dorthin zurückzukehren, wo du gestartet bist:

git rebase --abort

Selbst nachdem ein Rebase abgeschlossen ist, gehen die ursprünglichen Commits nicht sofort verloren — sie bleiben über git reflog eine Zeit lang erreichbar, was das Sicherheitsnetz ist, wenn du rebasest und es bereust.

Ein Wort der Vorsicht

Interaktiver Rebase schreibt die Geschichte um — die resultierenden Commits erhalten neue Hashes. Das ist ideal, um deinen eigenen Branch aufzuräumen, bevor du einen Pull Request öffnest, aber rebase niemals Commits, die andere bereits gepullt haben. Das Umschreiben gemeinsamer Geschichte zwingt alle anderen dazu, divergierende Kopien abzugleichen, und das Pushen des Ergebnisses erfordert einen Force-Push (git push --force-with-lease). Die goldene Regel: Lokal rebasen, öffentlich mergen.

Wenn du nur den allerletzten Commit ändern musst, brauchst du meist keinen vollständigen Rebase — git commit --amend ist einfacher. Um einen einzelnen Commit von woanders auf deinen Branch zu kopieren, siehe git cherry-pick.

Ein vollständiges Squash-Beispiel

Hier ist eine vollständige Sequenz, die du in einem leeren Ordner ausführen kannst, um Squashing in Aktion zu sehen. Sie erstellt vier Commits und faltet die letzten drei in einen einzigen ein:

git init -b main demo && cd demo
git config user.email [email protected]
git config user.name You

echo "init"  > base && git add base && git commit -m "initial commit"
echo "a"     > f    && git add f    && git commit -m "add login form"
echo -e "a\nb" > f  && git add f    && git commit -m "fix typo"
echo -e "a\nb\nc" > f && git add f  && git commit -m "more css tweaks"

git log --oneline      # four commits
git rebase -i HEAD~3   # mark line 2 'squash', line 3 'fixup', save
git log --oneline      # now: "initial commit" + one combined commit

Nach dem Rebase zeigt git log --oneline nur noch zwei Commits — den initialen Commit und einen einzigen kombinierten Commit — und die Datei f enthält weiterhin alle drei Zeilen (a, b, c). Die Arbeit ist identisch; nur die Commit-Geschichte ist übersichtlicher.

Übung

Übung
Welche Aussagen über den interaktiven Rebase sind korrekt?
Welche Aussagen über den interaktiven Rebase sind korrekt?
Was this page helpful?