git rebase

Branches und Merges

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)
[ ] optional| oder<arg> Platzhalter... wiederholbar--flag Option

Optionen

Klicke auf eine Option, um sie aufzuklappen

Einsteiger (3)

Den Rebase nach dem Lösen der Konflikte fortsetzen. Führe das aus, nachdem du die gelösten Dateien mit git add gestagt hast.

EmpfohlenDer normale Weg, nach dem Lösen und Stagen von Konflikten fortzusetzen

Beispiel

git rebase --continue

Den Rebase abbrechen und zum ursprünglichen Zustand vor seinem Start zurückkehren. Nutze das, wenn die Konflikte zu komplex sind oder du es dir anders überlegt hast.

EmpfohlenSicherer Notausgang: stellt deinen Branch wie vor dem Rebase wieder her

Beispiel

git rebase --abort

Den aktuellen Commit überspringen und mit dem nächsten weitermachen. Nutze das, wenn ein Commit leer wird oder seine Änderungen nicht mehr gebraucht werden.

Bei BedarfLässt den aktuellen Commit fallen – nur, wenn seine Änderungen wirklich unerwünscht sind

Beispiel

git rebase --skip

Fortgeschritten (3)

Einen Editor öffnen, um Commits vor dem Neu-Abspielen umzusortieren, zusammenzufassen, zu bearbeiten oder zu verwerfen. Der mächtigste Weg, die Historie aufzuräumen.

EmpfohlenDer beste Weg, lokale Commits vor dem Teilen aufzuräumen

Beispiel

git rebase -i HEAD~3

Nicht committete Änderungen vor dem Rebase automatisch stashen und danach wiederherstellen. Erspart das Stashen von Hand.

Bei BedarfPraktisch bei unsauberem Baum, aber das Zurückholen des Stashes kann kollidieren

Beispiel

git rebase --autostash main

Rebase erzwingen, auch wenn der Branch aktuell ist. Erzeugt neue Commits mit neuen Hashes für alle Commits im Bereich.

Bei BedarfNur, wenn du für bereits aktuelle Commits neue Hashes brauchst

Beispiel

git rebase -f main

Erfahren (5)

Commits auf eine andere Basis verpflanzen. So kannst du Commits eines Branches auf einen bestimmten anderen Commit rebasen.

Bei BedarfVerschiebt einen genauen Commit-Bereich auf eine neue Basis – prüfe den Bereich doppelt

Beispiel

git rebase --onto main feature~3 feature

fixup!/squash!-Commits (erstellt mit git commit --fixup oder --squash) automatisch zu ihren Zielen verschieben und einschmelzen. Funktioniert seit Git 2.44 mit und ohne -i.

EmpfohlenPasst zu commit --fixup für müheloses Aufräumen der Historie

Beispiel

git rebase -i --autosquash main

Merge-Commits und Branch-Struktur beim Rebase erhalten. Baut die Merge-Topologie nach, statt die Historie flachzudrücken.

Bei BedarfWenn die Merge-Struktur eines Branches den Rebase überleben muss

Beispiel

git rebase -r main

Nach jedem angewendeten Commit einen Shell-Befehl ausführen. Nützlich, um Tests laufen zu lassen und sicherzustellen, dass jeder Commit baut.

Bei BedarfFührt Tests bei jedem neu angewendeten Commit aus; langsam bei langen Branches

Beispiel

git rebase -i -x 'npm test' main

Alle von HEAD erreichbaren Commits rebasen, einschließlich des Root-Commits. So kannst du die gesamte Historie umschreiben.

Nicht empfohlenSchreibt die ganze Historie ab dem ersten Commit um; selten nötig

Beispiel

git rebase -i --root

Die richtige Option wählen

git rebase und git merge im Vergleich

Verstehen, wann rebase und wann merge zum Integrieren passt

BefehlAspektGit RebaseGit Merge
HistoryLinear (schreibt Commits um)Bewahrt abweichende Historie
CommitsErzeugt NEUE Commits mit anderen SHAsBewahrt Original-Commits + Merge-Commit
DestructiveJa – ändert Commit-HashesNein – fügt nur einen Merge-Commit hinzu
ConflictsPro Commit beim Neu-Abspielen gelöstEinmal am Merge-Punkt gelöst
Best forLokale/private Branches vor dem PushÖffentliche/geteilte Branches
TraceabilityIntegrationspunkte schwerer erkennbarKlare Spur der Branch-Integration

Workflow-Beispiele

1
git fetch origin

Die neuesten Änderungen vom Remote holen

2
git checkout feature

Auf deinen Feature-Branch wechseln

3
git rebase origin/main

Deine Commits auf dem neuesten main neu abspielen

4
git push --force-with-lease

Den rebasten Branch pushen (nur wenn er nicht geteilt ist)

1
git log --oneline

Zählen, wie viele Commits zusammengefasst werden

2
git rebase -i HEAD~5

Interaktiver Rebase der letzten 5 Commits

3
(in editor) pick, squash, squash...

Den ersten behalten, den Rest hineinfassen

4
(edit combined message)

Eine saubere Commit-Nachricht schreiben

1
(make your fix)

Das Problem im Code beheben

2
git commit --fixup=<commit-hash>

Einen Fixup-Commit für das Ziel erzeugen

3
git rebase --autosquash main

Autosquash ordnet und fasst automatisch zusammen (seit Git 2.44 ohne -i)

1
git rebase -i HEAD~4

Interaktiver Rebase der letzten 4 Commits

2
(in editor) reorder lines

Commit-Zeilen an neue Positionen verschieben

3
save and close editor

Git spielt sie in der neuen Reihenfolge ab

1
git rebase -i HEAD~3

Interaktiven Rebase starten

2
(mark commit with 'edit')

Beim aufzuteilenden Commit anhalten

3
git reset HEAD^

Commit rückgängig machen, Änderungen ungestagt im Arbeitsverzeichnis behalten

4
git add file1 && git commit -m 'Part 1'

Ersten kleineren Commit erstellen

5
git add file2 && git commit -m 'Part 2'

Zweiten kleineren Commit erstellen

6
git rebase --continue

Mit den übrigen Commits weitermachen

1
git reflog

Den Commit vor dem Rebase finden

2
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 --continue

Cannot 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 main

Commit 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 --skip

Rebase 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 --abort

Commits 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-lease

git 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 main

Die 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..HEAD

Tipps & 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

A:

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.

A:

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.

A:

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'.

A:

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.

A:

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.

A:

--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.

A:

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.

A:

--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.

A:

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.

A:

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.