Git Rebase: Wie es funktioniert und warum Sie es verwenden sollten
Im Versionskontrollsystem Git gibt es zwei Möglichkeiten, einen Branch mit einem anderen zu kombinieren, die durch unterschiedliche Befehle dargestellt werden:
git merge. Commits aus einem Branch werden in einen anderen übertragen, indem ein Merge-Commit erstellt wird.git rebase. Commits aus einem Branch werden in einen anderen übertragen, wobei die ursprüngliche Reihenfolge der Änderungen beibehalten wird.
Einfach gesagt: Mit git merge werden die Commits eines Branches zu einem zusammengefasst („squashed“), während sie mit git rebase unverändert bleiben, die Branches aber dennoch kombiniert werden.
Der Befehl git rebase ermöglicht also, Commits beider Branches zu einer gemeinsamen Änderungshistorie zusammenzuführen.
Dieses Tutorial behandelt den Befehl git rebase, der für das Umsetzen (Rebasing) von Commits (Änderungen) von einem Branch auf einen anderen verantwortlich ist.
Alle gezeigten Beispiele verwenden Git Version 2.34.1 auf einem Hostman-Server mit dem Betriebssystem Ubuntu 22.04.
Sie können diese Anleitungen verwenden, um Git auf Ihrem Rechner zu installieren:
Was ist Git Rebase Link kopieren
Git Rebase ist ein leistungsstarker Git-Befehl, der hauptsächlich verwendet wird, um Änderungen von einem Branch in einen anderen zu integrieren, indem die Commit-Historie neu geschrieben wird. Im Gegensatz zu git merge, das einen neuen Merge-Commit erstellt und die Historie beider Branches beibehält, verschiebt oder „wiederholt“ git rebase eine Reihe von Commits von einem Branch auf einen anderen. Das Ergebnis ist eine lineare Historie, die so aussieht, als wäre der Feature-Branch direkt auf dem neuesten Commit des Ziel-Branches (z. B. main oder master) entwickelt worden. Dadurch wird die Commit-Historie aufgeräumt und unnötige Merge-Commits entfernt, was eine klarere und besser nachvollziehbare Projektstruktur schafft.
Wie Git Rebase funktioniert Link kopieren
Am besten lässt sich verstehen, wie Rebasing in Git funktioniert, wenn man sich ein abstraktes Repository mit mehreren Branches ansieht. Dabei sollte der Rebase-Vorgang Schritt für Schritt betrachtet werden.
Erstellen von Branches Link kopieren
Angenommen, wir haben ein Repository mit einem einzigen Branch master, der nur einen Commit enthält. Der Branch master sieht folgendermaßen aus:
master
commit_1Dann haben wir auf Basis von master einen neuen Branch hypothesis erstellt, um einige Features zu testen. In diesem neuen Branch haben wir mehrere Commits vorgenommen, die den Code verbessern. Der Branch sieht nun so aus:
hypothesis
commit_4
commit_3
commit_2
commit_1Später haben wir dem Branch master einen weiteren Commit hinzugefügt, um eine Sicherheitslücke dringend zu beheben. Der Branch master sieht jetzt so aus:
master
commit_5
commit_1Unser Repository hat nun zwei Branches:
master
commit_5
commit_1
hypothesis
commit_4
commit_3
commit_2
commit_1Der Branch master ist der Hauptbranch, während hypothesis der sekundäre (abgeleitete) Branch ist. Spätere Commits werden über den früheren aufgelistet, ähnlich wie bei der Ausgabe des Befehls git log.
Branches zusammenführen Link kopieren
Angenommen, wir wollen an dem Feature weiterarbeiten, das wir zuvor in den separaten Branch hypothesis verschoben haben. Dieser Branch enthält jedoch nicht den kritischen Fix, den wir in master vorgenommen haben.
Wir möchten daher den Zustand von hypothesis mit master „synchronisieren“, sodass der Fix-Commit auch im Feature-Branch erscheint. Mit anderen Worten, die Struktur des Repositories soll folgendermaßen aussehen:
master
commit_5
commit_1
hypothesis
commit_4
commit_3
commit_2
commit_5
commit_1Wie man sieht, wiederholt hypothesis jetzt genau die Historie von master, obwohl er ursprünglich vor commit_5 erstellt wurde. Hypothesis enthält also die Historie beider Branches – seine eigene und die von master.
Um dies zu erreichen, müssen wir git rebase verwenden.
Anschließend können die in hypothesis vorgenommenen Änderungen mit dem klassischen Befehl git merge in master zusammengeführt werden, der einen Merge-Commit erstellt.
Danach sieht die Repository-Struktur so aus:
master
commit_merge
commit_5
commit_1
hypothesis
commit_4
commit_3
commit_2
commit_5
commit_1Außerdem kann das Ausführen von git merge nach git rebase die Wahrscheinlichkeit von Konflikten verringern.
Praxis: git rebase Link kopieren
Nachdem wir den theoretischen Teil des git rebase-Befehls behandelt haben, können wir ihn nun in einem echten Repository eines Beispielprojekts testen. Die Struktur des Repositories entspricht dem oben beschriebenen theoretischen Beispiel.
Erstellen eines Repositories Link kopieren
Zuerst erstellen wir ein separates Verzeichnis für das Repository:
mkdir rebaseDann wechseln wir hinein:
cd rebaseNun initialisieren wir das Repository:
git initIn der Konsole sollte eine Standard-Informationsmeldung erscheinen:
hint: Using 'master' as the name for the initial branch. This default branch name
hint: is subject to change. To configure the initial branch name to use in all
hint: of your new repositories, which will suppress this warning, call:
...Und im aktuellen Verzeichnis erscheint ein versteckter Ordner .git, den Sie mit folgendem Befehl anzeigen können:
ls -aDer Parameter -a steht für all und zeigt das Dateisystem im erweiterten Modus an. Sein Inhalt wird sein:
. .. .gitBevor Commits erstellt werden, müssen wir einige grundlegende Benutzerinformationen angeben.
Zuerst den Namen:
git config --global user.name "NAME"Dann die E-Mail-Adresse:
git config --global user.email "NAME@HOST.COM"Den master-Branch befüllen Link kopieren
Mit einfachen Textdateien simulieren wir das Hinzufügen verschiedener Funktionen zum Projekt. Jede neue Funktion wird als separater Commit dargestellt.
Erstellen Sie eine Datei für die erste Funktion:
nano function_1Füllen Sie sie mit folgendem Inhalt:
Function 1Indexieren Sie nun die Änderungen:
git add .Prüfen Sie zur Sicherheit den Indexierungsstatus:
git statusIn der Konsole sollte folgende Meldung erscheinen, die die indexierten Änderungen anzeigt:
On branch master
No commits yet
Changes to be committed:
(use "git rm --cached <file>..." to unstage)
new file: function_1
Nun können wir committen:
git commit -m "commit_1"Die Konsole zeigt eine Bestätigungsmeldung über den erfolgreichen Commit in master an:
[master (root-commit) 4eb7cc3] commit_1
1 file changed, 1 insertion(+)
create mode 100644 function_1Den hypothesis-Branch befüllen Link kopieren
Nun erstellen wir einen neuen Branch namens hypothesis:
git checkout -b hypothesisDer Parameter -b sorgt dafür, dass sofort in den neuen Branch gewechselt wird.
Die Konsole zeigt eine Bestätigungsmeldung an:
Switched to a new branch 'hypothesis'Als Nächstes erstellen wir drei Commits nacheinander mit drei Dateien, analog zu master:
commit_2mit Dateifunction_2und Inhalt: Function 2commit_3mit Dateifunction_3und Inhalt: Function 3commit_4mit Dateifunction_4und Inhalt: Function 4
Wenn wir dann die Commit-Liste prüfen:
git log --onelinezeigt die Konsole folgende Reihenfolge:
d3efb82 (HEAD -> hypothesis) commit_4
c9f57b7 commit_3
c977f16 commit_2
4eb7cc3 (master) commit_1Hier wird der Parameter --oneline verwendet, um die Commit-Informationen in komprimierter Einzeilenform anzuzeigen.
Einen Commit zum master-Branch hinzufügen Link kopieren
Der letzte Schritt besteht darin, dem Hauptbranch master einen weiteren Commit hinzuzufügen. Wechseln Sie zunächst dorthin:
git checkout masterDie Konsole bestätigt den Wechsel:
Switched to branch 'master'Erstellen Sie nun eine weitere Datei:
nano function_5Mit folgendem Inhalt:
Function 5Indexieren Sie die Änderungen:
git add .Und erstellen Sie den neuen Commit:
git commit -m "commit_5"Wenn Sie die Commit-Liste prüfen:
git log --onelinezeigt der master-Branch jetzt zwei Commits:
3df7a00 (HEAD -> master) commit_5
4eb7cc3 commit_1Branches mit git rebase zusammenführen Link kopieren
Um ein Rebase durchzuführen, müssen Sie zuerst in den hypothesis-Branch wechseln:
git checkout hypothesisUnd dann das Rebase ausführen:
git rebase masterNach Abschluss zeigt die Konsole eine Bestätigungsmeldung an:
Successfully rebased and updated refs/heads/hypothesis.Nun können Sie die Commit-Liste prüfen:
git log --onelineDie Konsole zeigt nun die Commits beider Branches in der ursprünglichen Reihenfolge:
8ecfd58 (HEAD -> hypothesis) commit_4
f715aba commit_3
ee47470 commit_2
3df7a00 (master) commit_5
4eb7cc3 commit_1Jetzt enthält der hypothesis-Branch die vollständige Historie des gesamten Repositories.
Konflikte auflösen Link kopieren
Wie bei git merge können auch beim Befehl git rebase Konflikte auftreten, die manuell gelöst werden müssen.
Erzeugen wir absichtlich einen Rebase-Konflikt:
Erstellen Sie im hypothesis-Branch eine weitere Datei:
nano conflictUnd fügen Sie folgenden Text hinzu:
There must be a conflict here!Indexieren Sie die Änderungen:
git add .Erstellen Sie den Commit:
git commit -m "conflict_1"Wechseln Sie nun in den master-Branch:
git checkout masterErstellen Sie eine ähnliche Datei:
nano conflictMit folgendem Inhalt:
There must NOT be a conflict here!Indexieren Sie wieder:
git add .Und committen Sie:
git commit -m "conflict_2"Bearbeiten Sie dann die erstellte Datei erneut:
nano conflictUnd ändern Sie den Inhalt zu:
There definitely must NOT be a conflict here!Indexieren Sie die Änderungen erneut:
git add .Und erstellen Sie einen weiteren Commit:
git commit -m "conflict_3"Wechseln Sie zurück in den hypothesis-Branch:
git checkout hypothesisUnd führen Sie erneut ein Rebase aus:
git rebase masterDie Konsole zeigt eine Konfliktmeldung an:
Auto-merging conflict
CONFLICT (add/add): Merge conflict in conflict
error: could not apply 6003ed7... conflict_1
hint: Resolve all conflicts manually, mark them as resolved with
hint: "git add/rm <conflicted_files>", then run "git rebase --continue".
hint: You can instead skip this commit: run "git rebase --skip".
hint: To abort and get back to the state before "git rebase", run "git rebase --abort".
Could not apply 6003ed7... conflict_1
Git schlägt vor, die Konfliktdatei zu bearbeiten, die Änderungen mit git add zu indexieren und dann das Rebase mit --continue fortzusetzen.
Das tun wir nun:
nano conflictDie Datei enthält zwei widersprückliche Versionen, die in spezielle Markierungen eingefasst sind:
<<<<<<< HEAD
There definitely must NOT be a conflict here!
=======
There must be a conflict here!
>>>>>>> 6003ed7 (conflict_1)Unsere Aufgabe ist es, die überflüssigen Teile zu entfernen und die Datei mit einem endgültigen Text zu füllen:
There must absolutely definitely unanimously NOT be any conflict here!Indexieren Sie die Änderungen:
git add .Und fahren Sie mit dem Rebase fort:
git rebase --continueDanach zeigt die Konsole einen Texteditor an, der es Ihnen ermöglicht, die ursprüngliche Commit-Nachricht des Konflikt-Commits zu bearbeiten:
conflict_1
# Please enter the commit message for your changes. Lines starting
# with '#' will be ignored, and an empty message aborts the commit.
#
# interactive rebase in progress; onto bd7aefc
# Last commands done (4 commands done):
# pick 8ecfd58 commit_4
# pick 6003ed7 conflict_1
# No commands remaining.
# You are currently rebasing branch 'hypothesis' on 'bd7aefc'.
#
# Changes to be committed:
# modified: conflict
#
Die Konsole zeigt anschließend eine Meldung über den erfolgreichen Abschluss des Rebase-Prozesses an:
[detached HEAD 482db49] conflict_1
1 file changed, 1 insertion(+), 1 deletion(-)
Successfully rebased and updated refs/heads/hypothesis.Wenn Sie nun die Commit-Liste im hypothesis-Branch prüfen:
git log --onelinesehen Sie die ursprüngliche Reihenfolge aller vorgenommenen Änderungen:
482db49 (HEAD -> hypothesis) conflict_1
bd5d036 commit_4
407e245 commit_3
948b41c commit_2
bd7aefc (master) conflict_3
d98648d conflict_2
3df7a00 commit_5
4eb7cc3 commit_1Beachten Sie, dass die Commits conflict_2 und conflict_3, die im master-Branch erstellt wurden, in der Historie vor dem Commit conflict_1 erscheinen. Das gilt für alle Commits, die im master-Branch vorgenommen wurden.
Rebasing eines Remote-Repositories Link kopieren
Neben der Arbeit mit lokalen Branches kann Rebase auch beim Herunterladen von Änderungen aus einem Remote-Repository verwendet werden. Dazu fügt man dem Standardbefehl pull die Option --rebase hinzu:
git pull --rebase remote branchDabei gilt:
-
remoteist das Remote-Repository -
branchist der Remote-Branch
Im Wesentlichen entspricht diese Pull-Konfiguration einem git rebase, mit dem Unterschied, dass die Änderungen (Commits), die auf den aktuellen Branch angewendet werden, aus dem Remote-Repository stammen.
Hauptvorteile von Git Rebase Link kopieren
- Lineare Historie
Der Befehl git rebase ermöglicht es, eine lineare Historie des Ziel-Branches zu erstellen, die aus aufeinanderfolgenden Commits besteht. Eine solche Struktur ohne Verzweigungen macht die Historie leichter verständlich und übersichtlicher.
- Weniger Konflikte
Das vorherige Ausführen von git rebase kann die Wahrscheinlichkeit von Konflikten beim Zusammenführen von Branches mit git merge deutlich verringern. Konflikte lassen sich in aufeinanderfolgenden Commits einfacher lösen als in einem einzigen Merge-Commit. Dies ist besonders hilfreich beim Pushen von Branches in Remote-Repositories.
Nachteile von Git Rebase Link kopieren
- Veränderung der Historie
Im Gegensatz zum Mergen überschreibt Rebase Teile der Zielbranch-Historie und entfernt überflüssige Elemente.
- Fehleranfälligkeit
Da Rebase die Commit-Historie erheblich umstrukturieren kann, besteht das Risiko irreversibler Fehler im Repository, wodurch Daten dauerhaft verloren gehen können.
Wann sollte man Git Rebase verwenden Link kopieren
Git rebase ist besonders nützlich, wenn Sie an kleinen oder individuellen Feature-Branches arbeiten, die später in einen gemeinsamen Hauptbranch integriert werden sollen. Es hilft, eine saubere und lineare Historie zu behalten, was insbesondere bei Open-Source-Projekten oder zur besseren Nachvollziehbarkeit von Änderungen wichtig ist.
In Teams mit mehreren Mitwirkenden sollte Rebase jedoch vorsichtig eingesetzt werden, um Probleme durch das Umschreiben der öffentlichen Historie zu vermeiden. Eine gute Kommunikation im Team darüber, wann Rebase angebracht ist, ist entscheidend. In vielen Fällen ist git merge sicherer und einfacher, insbesondere für gemeinsam genutzte Branches oder wenn eine nicht-lineare Historie akzeptabel ist.
Wichtige Überlegungen Link kopieren
- Umschreiben der Historie
Ein wesentlicher Aspekt von git rebase ist, dass die Commit-Historie neu geschrieben wird. Dabei ändern sich die SHA-1-Hashes der Commits, was in kollaborativen Umgebungen zu Konflikten führen kann, insbesondere wenn ein bereits veröffentlichter Branch erneut rebased wird. Das Rewriting der Historie kann zu Abweichungen zwischen lokalem und Remote-Repository führen.
- Keine öffentlichen Branches rebased
Als Best Practice gilt, öffentliche Branches, die bereits geteilt wurden, nicht zu rebased. Da Rebase die Historie verändert, kann dies zu divergierenden Historien führen und komplizierte Merge-Konflikte verursachen. Rebase eignet sich am besten für lokale Branches oder zur Vorbereitung eines Feature-Branches vor dem finalen Merge. Öffentliche Branches sollten in der Regel gemergt statt gerebased werden.
- Mögliche Konflikte
Während eines Rebase-Vorgangs kann es zu Konflikten kommen, wenn Änderungen in beiden Branches kollidieren. Git hält den Vorgang dann an und fordert Sie auf, die Konflikte manuell zu lösen. Das Vorgehen ähnelt dem bei Merge-Konflikten, ist jedoch oft aufwendiger, da Konflikte für jeden Commit einzeln gelöst werden müssen. Nach der Lösung können Sie mit git rebase --continue fortfahren.
Fazit Link kopieren
Das Zusammenführen zweier Branches durch Rebasing, umgesetzt mit dem Befehl git rebase, unterscheidet sich grundlegend vom klassischen Merge mit git merge.
-
git mergefasst die Commits eines Branches zu einem einzigen Commit in einem anderen Branch zusammen. -
git rebaseverschiebt die Commits eines Branches ans Ende eines anderen Branches und behält die ursprüngliche Reihenfolge bei.
Ein ähnlicher Effekt kann erzielt werden, wenn git pull mit der Option --rebase verwendet wird.
Auf der einen Seite sorgt git rebase für eine sauberere und besser nachvollziehbare Commit-Historie im Hauptbranch und verbessert die Wartbarkeit des Repositories.
Auf der anderen Seite reduziert git rebase die Detailtiefe der Historie und entfernt bestimmte Einträge, was die Nachverfolgung erschweren kann.
Aus diesem Grund ist Rebase ein Werkzeug für erfahrene Benutzer, die das Verhalten von Git genau verstehen. Meist wird git rebase in Kombination mit git merge verwendet, um eine optimale Struktur von Repository und Branches zu erreichen.