Close

git rebase

In diesem Artikel befassen wir uns intensiver mit der Frage "Was ist git rebase?" Der Git-Workflow "rebase" wurde auch in Einrichten eines Repositorys und Umarbeiten von Verläufen angesprochen. Auf dieser Seite sehen wir uns die Konfiguration und Ausführung von git rebase genauer an. Darüber hinaus stellen wir häufige Anwendungsfälle vor und weisen auf Fallstricke hin.

Also, was ist "git rebase" genau? Rebase ist eines der beiden Git-Dienstprogramme für die Integration von Änderungen von einem Branch in einen anderen. Bei dem anderen Dienstprogramm zur Integration von Änderungen handelt es sich um git merge. Merge ist immer ein nach vorne ausgerichteter Änderungsansatz. Rebase dagegen kann die Geschichte (bzw. den Verlauf) umschreiben. Eine detaillierte Gegenüberstellung von Merge und Rebase findest du in Merging vs. Rebasing. "git rebase" verfügt über zwei Hauptmodi: manuell und interaktiv. Darauf werden wir unten noch tiefer eingehen.


Was ist "git rebase"?


Der Git-Workflow "rebase" ist das Verschieben oder Zusammenführen einer Abfolge von Commits in einem neuen Basis-Commit. Dies ist äußerst nützlich und kann vor dem Hintergrund eines Feature Branch Workflows leicht visualisiert werden. Der allgemeine Prozess kann wie folgt dargestellt werden:

git rebase

Aus inhaltlicher Sicht ändert "git rebase" die Basis deines Branch von einem Commit zu einem anderen, sodass es so aussieht, als ob du deinen Branch von einem anderen Commit erstellt hättest. Intern bewerkstelligt Git dies, indem neue Commits erstellt werden, die dann auf die angegebene Basis angewendet werden. Es ist enorm wichtig zu verstehen, dass die Branches zwar gleich aussehen, aber aus völlig neuen Commits bestehen.

Git-Logo
Zugehöriges Material

Git-Merkzettel

Bitbucket-Logo
Lösung anzeigen

Git kennenlernen mit Bitbucket Cloud

Anwendung von "git rebase"


Der Hauptgrund für die Verwendung von "git rebase" ist die Wahrung eines linearen Projektverlaufs. Stell dir z. B. vor, der Haupt-Branch hat sich seit Beginn deiner Arbeit an einem Feature-Branch weiterentwickelt. Du möchtest in deinem Feature-Branch die neuesten Updates des Haupt-Branch haben, aber der Verlauf deines Branch soll sauber bleiben, damit es so aussieht, als ob du am neuesten Haupt-Branch arbeitest. Dies hat den Vorteil, dass du deinen Feature-Branch sauber zurück in den Haupt-Branch mergen kannst. Warum wollen wir einen sauberen Verlauf? Die Vorteile eines sauberen Verlaufs sind bei der Untersuchung von Git auf den Anfangspunkt einer Regression deutlich spürbar. Ein realitätsnäheres Szenario wäre Folgendes:

Zentrales git-Repository auf lokales git-Repository

1. Im Haupt-Branch wurde ein Fehler entdeckt. Ein Feature, das bisher gut funktioniert hat, läuft nun nicht mehr.

2. A developer examines the history of the main branch using git log because of the "clean history" the developer is quickly able to reason about the history of the project.

3. The developer can not identify when the bug was introduced using git log so the developer executes a git bisect.

4. Because the git history is clean, git bisect has a refined set of commits to compare when looking for the regression. The developer quickly finds the commit that introduced the bug and is able to act accordingly.

Erfahre mehr zu git log und git bisect auf den jeweiligen Seiten zu ihrer Verwendung.

Zur Integration deines Features in den Haupt-Branch hast du zwei Optionen: einen direkten Merge oder erst ein Rebasing mit anschließendem Merge. Die erste Option führt zu einem 3-Wege-Merge und einem Merge-Commit, die zweite Option dagegen führt zu einem Fast-Forward-Merge und einem exakt linearen Verlauf. Im folgenden Diagramm ist dargestellt, wie Rebasing in den Haupt-Branch einen Fast-Forward-Merge erleichtert.

Git rebase: Branch onto main

"git rebase" ist eine übliche Methode zur Integration von Upstream-Änderungen in dein lokales Repository. Das Pullen von Upstream-Änderungen mit "git merge" führt jedes Mal, wenn du den Projektfortschritt ansiehst, zu einem überflüssigen Merge-Commit. Rebasing kommt dagegen der Aussage "Ich möchte meine Änderungen auf die bereits erledigten Arbeit der anderen stützen" gleich.

Kein Rebasing von öffentlichen Verläufen

Wie zuvor in Umarbeiten von Verläufen erläutert, solltest du Commit niemals rebasen, nachdem sie in ein öffentliches Repository gepusht wurden. Der Git-Workflow "rebase" würde die alten Commits durch neue ersetzen und es würde so aussehen, als ob dieser Teil deines Projektverlaufs plötzlich verschwunden ist.

Git rebase standard vs git rebase interactive

Der interaktive Modus von "git rebase" wird ausgeführt, indem der Befehl mit dem Argument -- i kombiniert wird. Dieses steht für "interaktiv". Ohne diesen Zusatz wird der Befehl im Standardmodus ausgeführt. Nehmen wir für beide Fälle an, wir haben einen separaten Feature Branch erstellt.

# Create a feature branch based off of main 
git checkout -b feature_branch main
# Edit files 
git commit -a -m "Adds new feature" 

Im Standardmodus wendet "git rebase" Commits in deinem aktuellen Arbeits-Branch automatisch auf den angegebenen Branch-Head an.

git rebase <base>

Dabei wird das Rebasing für den aktuellen Branch automatisch auf die <base> durchgeführt, bei der es sich um jede Art von Commit-Referenz handeln kann (z. B. eine ID, ein Branch-Name, ein Tag oder eine relative Referenz zum HEAD).

Das Ausführen von git rebase mit dem Zusatz -i startet eine interaktive Rebasing-Sitzung. Anstatt alle Commit blind in die neue Basis zu verschieben, hast du beim interaktiven Rebasing die Möglichkeit den Prozess für die einzelnen Commits zu beeinflussen. Du kannst deinen Verlauf bereinigen, indem du den vorhandene Commits entfernst, aufteilst und änderst. Der Modus ist also im Prinzip wie Git commit --amend auf Steroiden.

git rebase --interactive <base>

Dadurch wird der aktuelle Branch auf <base> rebased, es wird dazu jedoch eine interaktive Rebasing-Sitzung verwendet. Dadurch wird ein Editor geöffnet, in dem du die Befehle (siehe unten) fürjeden Commit, der rebased werden soll, eingeben kannst. Diese Befehle bestimmen, wie einzelne Commits auf die neue Basis übertragen werden. Du kannst die Commit-Liste auch neu anordnen, um die Reihenfolge der Commits selbst zu ändern. Sobald du Befehle für jedes Commit im Rebase-Workflow angegeben hast, beginnt Git mit der Wiedergabe von Commits unter Anwendung der Rebase-Befehle. Die Rebase-Bearbeitungsbefehle lauten wie folgt:

pick 2231360 some old commit
pick ee2adc2 Adds new feature


# Rebase 2cf755d..ee2adc2 onto 2cf755d (9 commands)
#
# Commands:
# p, pick = use commit
# r, reword = use commit, but edit the commit message
# e, edit = use commit, but stop for amending
# s, squash = use commit, but meld into previous commit
# f, fixup = like "squash", but discard this commit's log message
# x, exec = run command (the rest of the line) using shell
# d, drop = remove commit

Weitere Befehle für den Git-Workflow "rebase"

Wie auf der Seite Umarbeiten von Verläufen beschrieben, können ältere und auch mehrere Commits sowie committete Dateien und mehrere Nachrichten mithilfe von "git rebase" geändert werden. Dies sind die gebräuchlichsten Anwendungen von git rebase. Es gibt jedoch noch weitere Optionen, die in komplexeren Anwendungsfällen von Nutzen sind.

  • git rebase -- d bedeutet, dass der Commit während des Abspielens vom finalen Commit-Block entfernt wird.
  • git rebase -- p verändert den Commit nicht. Die Commit-Nachricht oder der Inhalt ändert sich nicht und der Commit bleibt weiterhin als individueller Commit im Branch-Verlauf erhalten.
  • git rebase -- x führt während des Abspielens für jeden markierten Commit ein Shell-Skript aus. Ein nützlicher Use Case wäre z. B. das Ausführen der Test-Suite deiner Codebasis für bestimmte Commits zur Identifizierung von Regressionen während eines Rebasings.

Zusammenfassung

Mit dem interaktiven Git-Workflow "rebase" hast du die volle Kontrolle über das Aussehen deines Projektverlaufs. Das gewährt Entwicklern die Freiheit, "chaotische" Verläufe zu generieren, während sie sich auf die Codeerstellung konzentrieren, und die Verläufe anschließend zu säubern.

Die meisten Entwickler verwenden gerne für den letzten Schliff an einem Feature Branch interaktives Rebasing, bevor sie ihn in die Haupt-Codebasis mergen. Auf diese Weise können sie unwichtige und überflüssige Commits entfernen bzw. squashen und sicherstellen, dass alles in Ordnung ist, bevor ein Commit in den "offiziellen" Projektverlauf durchgeführt wird. Für Außenstehende wird es so aussehen, als ob das gesamte Feature in einer einzigen Reihe gut geplanter Commits entwickelt wurde.

Die wahre Stärke des interaktiven Git-Workflows "rebase" zeigt sich im Verlauf des resultierenden Haupt-Branch. Für Außenstehende sieht es so aus, als seist du ein brillanter Entwickler, der das neue Feature auf Anhieb mit der perfekten Anzahl von Commits implementiert hat. So kann interaktives Rebasing einen Projektverlauf sauber und aussagekräftig halten.

Konfigurationsoptionen

Mit git config können einige Rebase-Eigenschaften eingerichtet werden. Diese Optionen ändern das Erscheinungsbild der git rebase-Ausgabe.

  • rebase.stat: Eine Boolesche Variable, die standardmäßig auf "Falsch" gesetzt ist. Mit der Option wechselst du zur Anzeige von Diffstat-Inhalten, die darstellen, was sich seit dem letzten Rebasing geändert hat.
  • rebase.autoSquash: Ein Boolescher Wert, der das --autosquash-Verhalten umschaltet.
  • rebase.missingCommitsCheck: Kann auf verschiedene Werte gesetzt werden, die jeweils das Verhalten bezüglich fehlender Commits ändern.

warn

Zeigt im interaktiven Modus eine Warnmeldung an, die vor entfernten Commits warnt

error

Stoppt das Rebasing und zeigt eine Warnmeldung zu entfernten Commits an

ignore

In den Standardeinstellungen werden Warnungen zu fehlenden Commits ignoriert.

  • rebase.instructionFormat: Ein git log-Format-String zur Formatierung der interaktiven Rebase-Anzeige

Erweiterte Anwendung von "git rebase"

Das Befehlszeilenargument --onto kann an git rebase angefügt werden. Im git rebase --onto-Modus sieht der Befehl folgendermaßen aus:

git rebase --onto <newbase> <oldbase>

The --onto command enables a more powerful form or rebase that allows passing specific refs to be the tips of a rebase. Let’s say we have an example repo with branches like:

   o---o---o---o---o  main
        \
         o---o---o---o---o  featureA
              \
               o---o---o  featureB

featureB basiert auf featureA, trotzdem ist featureB nicht von Änderungen an featureA abhängig und könnte auch auf Basis des Haupt-Branch erstellt worden sein.

git rebase --onto main featureA featureB

featureA ist die <oldbase>. main wird zu <newbase> und featureB zeigt, auf was der HEAD der <newbase> verweist. Das Ergebnis sieht dann folgendermaßen aus:

                      o---o---o  featureB
                     /
    o---o---o---o---o  main
     \
      o---o---o---o---o  featureA
                           

Die Gefahren von "git rebase"


Ein Problem bei der Arbeit mit "git rebase" sind die zunehmenden Merge-Konflikte in einem Rebase-Workflow. Diese treten auf, wenn ein langlebiger Branch sich immer weiter vom Haupt-Branch entfernt. Letzten Endes wirst du auf den Haupt-Branch rebasen wollen und dieser enthält möglicherweise viele neue Commits, mit denen deine Branch-Änderungen in Konflikt geraten könnten. Hier kann leicht Abhilfe geschaffen werden, indem du für deinen Branch regelmäßig Rebasings mit dem Haupt-Branch und häufigere Commits durchführst. Die Befehlszeilenargumente --continue und --abort können an git rebase angefügt werden, um im Rahmen der Lösung von Konflikten das Rebasing fortzuführen oder zurückzusetzen.

Eine größere Gefahr beim Rebasing sind verlorene Commits beim interaktiven Umarbeiten des Verlaufs. Das Ausführen von "git rebase" im interaktiven Modus zusammen mit Unterbefehlen wie "squash" oder "drop" entfernt Commits vom unmittelbaren Branch-Protokoll. Auf den ersten Blick wirkt dies, als ob die Commits für immer verschwunden sind. Doch mit git reflog können diese Commits wiederhergestellt und das komplette Rebasing rückgängig gemacht werden. Für weitere Informationen, wie du mit git reflog verlorene Commits wiederfindest, siehe die Seite zur "Git reflog"-Dokumentation.

"git rebase" ist an sich nicht wirklich gefährlich. Die wahren Gefahren lauern beim Ausführen von interaktiven Rebases zum Umarbeiten von Verläufen und anschließendem erzwungenen Pushen der Ergebnisse in einen Remote Branch, der gemeinsam mit anderen Benutzern verwendet wird. Dieses Muster sollte vermieden werden, da dabei die Arbeit anderer Remote-Benutzer überschrieben werden kann, wenn diese einen Pull durchführen.

Wiederherstellen nach einem Upstream-Rebasing


Wenn ein anderer Benutzer "git rebase" durchgeführt und dann einen Push zu dem Branch erzwungen hat, zu dem auch du committest, wird der Befehl git pull alle Commits überschreiben, die du auf Basis dieses vorigen Branch, dessen Spitze zwangsgepusht wurde, erstellt hast. Zum Glück erhältst du mit dem Befehl git reflog den Reflog des Remote Branch. Im Reflog des Remote Branch findest du eine Ref mit dem Status vor dem Rebasing. Anschließend kannst du für deinen Branch mit der Option --onto ein Rebasing auf diese Remote-Ref durchführen wie im Abschnitt zur erweiterten Rebasing-Anwendung beschrieben.

Zusammenfassung


In diesem Artikel haben wir die Nutzung von git rebase behandelt. Wir haben grundlegende und erweiterte Anwendungsfälle sowie Beispiele für Fortgeschrittene besprochen. Wichtige Punkte dabei waren:

  • Standard- und interaktiver Modus von "git rebase" im Vergleich
  • Konfigurationsoptionen für "git rebase"
  • git rebase --onto
  • "git rebase" und verlorene Commits

We looked at git rebase usage with other tools like git reflog, git fetch, and git push. Visit their corresponding pages for further information.


Diesen Artikel teilen
Nächstes Thema

Lesenswert

Füge diese Ressourcen deinen Lesezeichen hinzu, um mehr über DevOps-Teams und fortlaufende Updates zu DevOps bei Atlassian zu erfahren.

Mitarbeiter arbeiten mit unzähligen Tools zusammen

Bitbucket-Blog

Abbildung: DevOps

DevOps-Lernpfad

Demo Den: Feature-Demos mit Atlassian-Experten

So funktioniert Bitbucket Cloud mit Atlassian Open DevOps

Melde dich für unseren DevOps-Newsletter an

Thank you for signing up