git rebase
Commits auf einer anderen Basis erneut anwenden
git rebase verschiebt oder fasst eine Folge von Commits auf einen neuen Basis-Commit zusammen. Oft nutzt man es für eine lineare Projekthistorie, indem die Commits eines Feature-Branches auf dem neuesten main neu abgespielt werden. Anders als merge schreibt rebase die Historie um und erzeugt neue Commits mit anderen SHAs. Der interaktive Rebase (-i) lässt dich Commits vor dem Neu-Abspielen zusammenfassen, umsortieren, bearbeiten oder verwerfen.
Syntax
git rebase [-i | --interactive] [<options>] [--exec <cmd>] [--onto <newbase> | --keep-base] [<upstream> [<branch>]]
git rebase [-i | --interactive] [<options>] [--exec <cmd>] [--onto <newbase>] --root [<branch>]
git rebase (--continue | --skip | --abort | --quit | --edit-todo | --show-current-patch)Optionen
Die richtige Option wählen
git rebase und git merge im Vergleich
Verstehen, wann rebase und wann merge zum Integrieren passt
| Befehl | Aspekt | Git Rebase | Git Merge |
|---|---|---|---|
History | Linear (schreibt Commits um) | Bewahrt abweichende Historie | |
Commits | Erzeugt NEUE Commits mit anderen SHAs | Bewahrt Original-Commits + Merge-Commit | |
Destructive | Ja – ändert Commit-Hashes | Nein – fügt nur einen Merge-Commit hinzu | |
Conflicts | Pro Commit beim Neu-Abspielen gelöst | Einmal am Merge-Punkt gelöst | |
Best for | Lokale/private Branches vor dem Push | Öffentliche/geteilte Branches | |
Traceability | Integrationspunkte schwerer erkennbar | Klare Spur der Branch-Integration |
Workflow-Beispiele
git fetch originDie neuesten Änderungen vom Remote holen
git checkout featureAuf deinen Feature-Branch wechseln
git rebase origin/mainDeine Commits auf dem neuesten main neu abspielen
git push --force-with-leaseDen rebasten Branch pushen (nur wenn er nicht geteilt ist)
git log --onelineZählen, wie viele Commits zusammengefasst werden
git rebase -i HEAD~5Interaktiver Rebase der letzten 5 Commits
(in editor) pick, squash, squash...Den ersten behalten, den Rest hineinfassen
(edit combined message)Eine saubere Commit-Nachricht schreiben
(make your fix)Das Problem im Code beheben
git commit --fixup=<commit-hash>Einen Fixup-Commit für das Ziel erzeugen
git rebase --autosquash mainAutosquash ordnet und fasst automatisch zusammen (seit Git 2.44 ohne -i)
git rebase -i HEAD~4Interaktiver Rebase der letzten 4 Commits
(in editor) reorder linesCommit-Zeilen an neue Positionen verschieben
save and close editorGit spielt sie in der neuen Reihenfolge ab
git rebase -i HEAD~3Interaktiven Rebase starten
(mark commit with 'edit')Beim aufzuteilenden Commit anhalten
git reset HEAD^Commit rückgängig machen, Änderungen ungestagt im Arbeitsverzeichnis behalten
git add file1 && git commit -m 'Part 1'Ersten kleineren Commit erstellen
git add file2 && git commit -m 'Part 2'Zweiten kleineren Commit erstellen
git rebase --continueMit den übrigen Commits weitermachen
git reflogDen Commit vor dem Rebase finden
git reset --hard HEAD@{n}Auf den Zustand vor dem Rebase zurücksetzen
Fehlerbehebung
KONFLIKT beim Rebase
Ursache: Änderungen in deinem Commit kollidieren mit dem Basis-Branch
Bearbeite die Dateien, um die Konflikte zu lösen, git add, dann git rebase --continue
git add <resolved-files> && git rebase --continueCannot rebase: You have unstaged changes
Ursache: Das Arbeitsverzeichnis hat nicht committete Änderungen
Committe, stashe oder nutze --autostash für die nicht committeten Änderungen
git rebase --autostash mainCommit wird nach dem Rebase leer
Ursache: Die Änderungen dieses Commits existieren schon im Ziel-Branch
Ein einfacher Rebase lässt ihn automatisch weg; ein interaktiver hält an – mit --skip weglassen oder mit 'git commit --allow-empty' behalten
git rebase --skipRebase führt zu vielen Konflikten
Ursache: Der Branch ist weit von der Basis abgewichen
Nutze stattdessen merge, oder brich ab und rebase in kleineren Schritten
git rebase --abortCommits nach dem Rebase verloren
Ursache: Die Original-Commits sind verwaist (nicht gelöscht, nur nicht mehr referenziert)
Finde und rette die Original-Commits über das Reflog
git reflog && git branch recovery HEAD@{n}Push nach dem Rebase abgelehnt (non-fast-forward)
Ursache: Rebase hat Commits umgeschrieben, daher enthält dein Branch die Historie der Remote-Kopie nicht mehr
Nutze --force-with-lease für einen sichereren Force-Push (es verweigert, wenn inzwischen jemand anderes gepusht hat)
git push --force-with-leasegit rebase meldet „Current branch is up to date“
Ursache: Keine Commits zum Neu-Abspielen – der Branch basiert schon auf dem Ziel
Nutze -f, um trotzdem zu rebasen, wenn du neue Hashes brauchst
git rebase -f mainDie To-do-Liste des interaktiven Rebase ist leer
Ursache: Keine Commits im angegebenen Bereich
Prüfe deinen Bereich – nutze HEAD~n oder gib den richtigen Upstream an
git log --oneline main..HEADTipps & Stolperfallen
Best Practices
- ✓Rebase nie Commits, die in ein geteiltes Repository gepusht wurden – das zwingt alle, ihre Branches von Hand zu reparieren
- ✓Nutze immer 'git rebase --abort', wenn Konflikte zu komplex werden – du kannst es dann anders versuchen
- ✓Nutze den interaktiven Rebase (-i), um Commits vor dem Push oder einem Pull Request aufzuräumen
- ✓Nutze eventuell '--autostash', damit nicht committete Änderungen beim Rebase automatisch behandelt werden
- ✓Nutze 'git commit --fixup=<hash>' mit '--autosquash' für einen saubereren Fixup-Workflow
- ✓Führe nach dem Rebase die Tests aus, um sicherzugehen, dass die rebasten Commits noch funktionieren
- ✓Nutze '-x npm test', um nach jedem neu abgespielten Commit automatisch die Tests auszuführen
- ✓Halte Rebases klein – rebase oft, statt Branches weit auseinanderlaufen zu lassen
- ✓Nutze 'git reflog', wenn ein Rebase schiefgeht – die Original-Commits werden nie sofort gelöscht
- ✓Nutze bei öffentlichen/geteilten Branches lieber merge statt rebase, um die Historie zu bewahren
- ✓Nutze beim Pushen rebaster Branches zur Sicherheit '--force-with-lease' statt '--force'
- ✓Schreibe beim Zusammenfassen eine neue, aussagekräftige Commit-Nachricht, die alle zusammengefassten Commits beschreibt
Häufige Fehler
- ✗Commits rebasen, die schon in ein geteiltes Repository gepusht wurden. Das schreibt die Historie um und zwingt alle anderen, ihre Branches von Hand zu reparieren.
- ✗Vergessen, gelöste Konflikte vor --continue zu stagen. Führe auf gelöste Dateien immer zuerst 'git add' aus.
- ✗--skip leichtfertig nutzen, wodurch die Änderungen des Commits aus dem rebasten Branch verschwinden. Nur nutzen, wenn du einen Commit absichtlich entfernen willst.
- ✗Nicht verstehen, dass Rebase NEUE Commits mit anderen Hashes erzeugt. Die Original-Commits werden verwaist.
- ✗Mit nicht committeten Änderungen im Arbeitsverzeichnis rebasen. Nutze --autostash oder stashe vorher von Hand.
FAQ
Merge bewahrt die Historie durch einen Merge-Commit, beide Branch-Historien bleiben intakt. Rebase schreibt die Historie um, indem es deine Commits auf einem anderen Branch neu abspielt – das ergibt eine lineare Historie. Nutze merge für geteilte Branches, rebase zum lokalen Aufräumen.
Rebase ändert Commit-Hashes. Haben andere auf deinen ursprünglichen Commits aufgebaut, weicht ihre Historie von deiner ab. Sie müssen ihre Branches von Hand reparieren, was fehleranfällig und frustrierend ist.
Finde mit 'git reflog' den Commit vor dem Rebase (such die alte Branch-Spitze) und stelle ihn mit 'git reset --hard HEAD@{n}' wieder her. Standardmäßig bleiben die Original-Commits 30 Tage über das Reflog erreichbar. Direkt nach einem Rebase funktioniert auch 'git reset --hard ORIG_HEAD'.
Im interaktiven Rebase: 'pick' behält den Commit unverändert, 'squash' fasst ihn mit dem vorigen zusammen (beide Nachrichten bleiben), 'fixup' fasst zusammen, verwirft aber die Nachricht, 'reword' behält den Commit, lässt dich aber die Nachricht bearbeiten.
Führe 'git rebase -i HEAD~n' aus, wobei n die Zahl der Commits ist. Lass im Editor 'pick' beim ersten Commit stehen und ändere die übrigen in 'squash' oder 'fixup'. Speichern und die kombinierte Commit-Nachricht bearbeiten.
--onto verpflanzt Commits auf eine andere Basis. Zum Beispiel verschiebt „git rebase --onto main feature~3 feature“ nur die letzten 3 Commits von feature auf main und lässt frühere aus.
Bearbeite die Konfliktdateien, um sie zu lösen, führe 'git add' auf die gelösten Dateien aus, dann 'git rebase --continue'. Wird es zu chaotisch, bringt dich 'git rebase --abort' in den Zustand vor dem Rebase zurück.
--preserve-merges wurde in Git 2.34 entfernt (git scheitert jetzt mit „--preserve-merges was replaced by --rebase-merges“). Nutze stattdessen --rebase-merges (-r), um Merge-Commits und Branch-Struktur beim Rebase zu erhalten. Es baut die Merge-Topologie auf der neuen Basis nach.
Ja, nutze 'git rebase -i' und markiere Commits, die bleiben sollen, mit 'pick', und solche, die weg sollen, mit 'drop'. Oder gib mit --onto genau den Bereich an, der verschoben wird.
Der Hash eines Commits wird aus Inhalt, Nachricht, Autor, Datum UND Eltern-Commit berechnet. Da Rebase den Elternteil ändert, bekommen alle folgenden Commits neue Hashes, auch wenn ihr Inhalt identisch ist.