Merge vs. Rebase – Der fundamentale Unterschied Der Unterschied zwischen git merge und git rebase ist eines der wichtigsten Konzepte, das du als fortgeschrittener Git-Nutzer wirklich verstanden haben solltest. Beide Befehle dienen demselben Zweck – Änderungen aus einem Branch in einen anderen zu integrieren – aber sie tun dies auf völlig unterschiedliche Weise, mit unterschiedlichen Auswirkungen auf deine Commit-Historie. Die Ausgangssituation Stellen wir uns folgendes Szenario vor: Du arbeitest an einem Feature-Branch, während dein Team weiterhin Commits auf main macht. Nach einiger Zeit sieht deine Repository-Struktur so aus: gitGraph commit id: "A" commit id: "B" branch feature commit id: "X" commit id: "Y" checkout main commit id: "C" commit id: "D" Du hast auf deinem feature-Branch die Commits X und Y erstellt, während auf main in der Zwischenzeit C und D hinzugekommen sind. Jetzt möchtest du die Änderungen von main in deinen Feature-Branch integrieren (oder umgekehrt deinen Feature-Branch in main einbringen). Hier kommen Merge und Rebase ins Spiel. Was passiert bei einem Merge? Ein Merge erstellt einen neuen Merge-Commit, der die beiden Entwicklungslinien zusammenführt. Dieser Merge-Commit hat zwei Eltern-Commits – er verbindet buchstäblich die beiden Branches miteinander. Der Merge-Befehl # Du bist auf feature und möchtest main integrieren git checkout feature git merge main In PhpStorm: Git → Merge... → main auswählen Das Ergebnis nach dem Merge gitGraph commit id: "A" commit id: "B" branch feature commit id: "X" commit id: "Y" checkout main commit id: "C" commit id: "D" checkout feature merge main id: "M" tag: "Merge-Commit" Der neue Commit M ist der Merge-Commit. Er enthält keine eigenen Code-Änderungen (außer eventuell Konfliktlösungen), sondern dient als „Knotenpunkt", der die beiden Historien verbindet. Eigenschaften eines Merge Aspekt Beschreibung Commit-Historie Bleibt vollständig erhalten, zeigt aber eine verzweigte Struktur Originalcommits X und Y behalten ihre ursprünglichen SHA-Hashes Neuer Commit Ein Merge-Commit mit zwei Eltern wird erstellt Nicht-destruktiv Die bestehende Historie wird niemals verändert Was passiert bei einem Rebase? Ein Rebase nimmt deine Commits und „verpflanzt" sie auf eine neue Basis. Statt eines Merge-Commits werden deine Commits neu erstellt – sie werden auf den aktuellen Stand des Ziel-Branches aufgebaut, als hättest du erst jetzt mit der Arbeit begonnen. Der Rebase-Befehl # Du bist auf feature und möchtest auf main "umbasieren" git checkout feature git rebase main In PhpStorm: Git → Rebase... → main auswählen Was genau passiert beim Rebase? Der Rebase-Prozess läuft in mehreren Schritten ab: Git identifiziert die Commits, die nur auf feature existieren (X und Y) Git speichert diese Commits temporär (als Patches) Git setzt den feature-Branch auf die Spitze von main (Commit D) Git wendet die gespeicherten Commits nacheinander wieder an Das Ergebnis sind neue Commits X' und Y', die denselben Inhalt haben wie die Originale, aber: einen anderen Eltern-Commit (sie bauen jetzt auf D auf, nicht auf B) einen anderen SHA-Hash (weil sich der Eltern-Commit geändert hat) einen anderen Zeitstempel (optional, je nach Konfiguration) Das Ergebnis nach dem Rebase gitGraph commit id: "A" commit id: "B" commit id: "C" commit id: "D" commit id: "X'" tag: "neu erstellt" commit id: "Y'" tag: "neu erstellt" Beachte: Die ursprünglichen Commits X und Y existieren technisch noch im Repository (erreichbar über git reflog), aber kein Branch zeigt mehr auf sie. Sie werden bei der nächsten Garbage Collection entfernt. Visueller Vergleich: Merge vs. Rebase Um den Unterschied noch deutlicher zu machen, hier beide Ergebnisse im direkten Vergleich: flowchart TB subgraph vorher["Ausgangssituation"] direction LR A1["A"] --> B1["B"] B1 --> C1["C"] --> D1["D"] B1 --> X1["X"] --> Y1["Y"] end subgraph merge["Nach git merge main"] direction LR A2["A"] --> B2["B"] B2 --> C2["C"] --> D2["D"] B2 --> X2["X"] --> Y2["Y"] D2 --> M["M"] Y2 --> M end subgraph rebase["Nach git rebase main"] direction LR A3["A"] --> B3["B"] --> C3["C"] --> D3["D"] D3 --> X3["X'"] --> Y3["Y'"] end vorher --> merge vorher --> rebase style M fill:#90EE90,color:#000000 style X3 fill:#FFD700,color:#000000 style Y3 fill:#FFD700,color:#000000 Die tiefgreifenden Unterschiede im Detail 1. Integrität der Historie vs. Sauberkeit Merge bewahrt die exakte historische Wahrheit: Es zeigt, dass parallel entwickelt wurde und wann die Zusammenführung stattfand. Das kann wertvoll sein, wenn du später nachvollziehen möchtest, wie die Entwicklung tatsächlich ablief. Rebase erzeugt eine saubere, lineare Historie, als hätte es nie parallele Entwicklung gegeben. Das macht die Historie leichter lesbar, „lügt" aber technisch gesehen über den tatsächlichen Entwicklungsverlauf. 2. Commit-Identität Dieser Punkt ist entscheidend für das Verständnis: # Vor dem Rebase git log --oneline feature # abc1234 Y - Feature fertiggestellt # def5678 X - Feature begonnen # Nach dem Rebase git log --oneline feature # 111aaaa Y' - Feature fertiggestellt ← NEUER HASH! # 222bbbb X' - Feature begonnen ← NEUER HASH! Die Commits nach dem Rebase sind komplett neue Git-Objekte. Sie haben: denselben Autor dieselbe Commit-Message dieselben Code-Änderungen (Diffs) aber einen anderen SHA-Hash (weil der Parent-Commit anders ist) 3. Konfliktbehandlung Bei einem Merge musst du Konflikte einmal lösen – im Merge-Commit. Die Konfliktlösung wird Teil dieses einen Commits. Bei einem Rebase musst du Konflikte für jeden Commit einzeln lösen, während Git die Commits nacheinander auf die neue Basis anwendet. Das kann aufwändiger sein, führt aber dazu, dass jeder Commit für sich genommen „funktioniert". # Rebase mit Konflikten git rebase main # CONFLICT in datei.php # Konflikt lösen, dann: git add datei.php git rebase --continue # Möglicherweise nächster Konflikt im nächsten Commit... 4. Auswirkungen auf andere Entwickler Hier liegt der kritischste Unterschied: Szenario Merge Rebase Commits noch nicht gepusht ✅ Sicher ✅ Sicher Commits bereits gepusht ✅ Sicher ⚠️ Gefährlich! Andere arbeiten auf dem Branch ✅ Sicher ❌ Sehr problematisch! Wenn du Commits rebasst, die bereits gepusht wurden, änderst du deren SHA-Hashes. Wenn ein Kollege diese Commits bereits hat, entstehen Duplikate in der Historie, weil Git die alten und neuen Commits als unterschiedlich betrachtet. Wann sollte ich Merge verwenden? Merge ist die richtige Wahl, wenn: Du öffentliche Historie integrierst – Wenn du Änderungen aus main in deinen Feature-Branch holst und dieser Branch bereits gepusht wurde, ist Merge sicherer. Mehrere Entwickler am gleichen Branch arbeiten – Ein Merge verändert keine bestehenden Commits, sodass niemand Probleme bekommt. Du die komplette Entwicklungshistorie bewahren möchtest – Für Auditing oder Nachvollziehbarkeit kann die „echte" Historie wichtig sein. Du größere Feature-Branches in main integrierst – Viele Teams bevorzugen hier einen Merge-Commit als „Markierung", dass ein Feature abgeschlossen wurde. Du unsicher bist – Merge ist die sicherere Option. Im Zweifel: Merge verwenden. Beispiel: Feature in main mergen git checkout main git merge feature --no-ff # --no-ff erzwingt einen Merge-Commit Das --no-ff (no fast-forward) Flag ist wichtig, wenn du explizit einen Merge-Commit möchtest, auch wenn ein Fast-Forward möglich wäre. Wann sollte ich Rebase verwenden? Rebase ist die richtige Wahl, wenn: Du deine lokale Arbeit aufräumen möchtest, bevor du sie teilst – Vor dem ersten Push ist Rebase völlig sicher und macht deine Commits präsentabler. Du deinen Feature-Branch auf den neuesten Stand von main bringen möchtest (und der Branch noch nicht gepusht wurde oder nur du daran arbeitest). Du eine lineare, saubere Historie bevorzugst – Manche Teams haben die Konvention, dass Feature-Branches vor dem Merge rebased werden müssen. Du mit Interactive Rebase Commits zusammenfassen oder aufteilen möchtest – Das ist nur mit Rebase möglich. Beispiel: Feature-Branch aktualisieren git checkout feature git fetch origin git rebase origin/main # Jetzt ist dein Feature-Branch auf dem neuesten Stand In PhpStorm kannst du das über Git → Rebase... machen oder über das Git-Log-Fenster (Rechtsklick auf origin/main → „Rebase Current onto Selected"). Der kombinierte Workflow: Das Beste aus beiden Welten Viele professionelle Teams nutzen einen kombinierten Workflow, der die Vorteile beider Ansätze vereint: flowchart TD A["Feature-Branch erstellen"] --> B["Lokal entwickeln\nmit kleinen Commits"] B --> C{"Bereit zum Teilen?"} C -->|Nein| B C -->|Ja| D["Interactive Rebase:\nCommits aufräumen"] D --> E["Rebase auf aktuellen main"] E --> F["Push Feature-Branch"] F --> G["Pull Request erstellen"] G --> H["Code Review"] H --> I{"Änderungen nötig?"} I -->|Ja| J["Änderungen committen"] J --> H I -->|Nein| K["Merge oder Squash-Merge\nin main"] style D fill:#FFD700,color:#000000 style E fill:#FFD700,color:#000000 style K fill:#90EE90,color:#000000 Die Schritte im Detail Während der Entwicklung: Mache so viele kleine Commits wie nötig, ohne dir über die „Schönheit" der Historie Gedanken zu machen. Vor dem Push: Nutze Interactive Rebase ( git rebase -i), um deine Commits aufzuräumen – Work-in-Progress-Commits zusammenfassen, Commit-Messages verbessern. Vor dem Pull Request: Rebase auf den aktuellen main, um sicherzustellen, dass dein Branch sauber auf dem neuesten Stand aufbaut. Beim Mergen: Der Pull Request wird entweder mit einem Merge-Commit oder einem Squash-Merge in main integriert. Die „goldene Regel" des Rebasings 🚨 Rebase niemals Commits, die bereits gepusht wurden und an denen andere arbeiten könnten! Diese Regel ist so wichtig, dass sie einen eigenen Abschnitt verdient. Hier ist, was passiert, wenn du sie brichst: Das Katastrophen-Szenario sequenceDiagram participant Du participant GitHub participant Kollege Du->>GitHub: Push commits X, Y GitHub->>Kollege: Pull commits X, Y Note over Kollege: Kollege arbeitet
basierend auf Y Du->>Du: Rebase X, Y → X', Y' Du->>GitHub: Force Push X', Y' Note over GitHub: X, Y ersetzt durch X', Y' Kollege->>GitHub: Push neuer Commit Z Note over GitHub: KONFLIKT!
Z basiert auf Y,
aber Y existiert nicht mehr GitHub-->>Kollege: Rejected! Note over Kollege: Muss jetzt manuell
reparieren 😱 Dein Kollege hat jetzt ein ernsthaftes Problem: Seine Arbeit basiert auf Commits, die in der offiziellen Historie nicht mehr existieren. Was tun, wenn es doch passiert ist? Falls du versehentlich gepushte Commits rebased hast: Kommuniziere sofort mit deinem Team – Informiere alle, die betroffen sein könnten. Koordiniere die Reparatur – Alle müssen ihre lokalen Branches aktualisieren: git fetch origin git reset --hard origin/feature # ACHTUNG: Lokale Änderungen gehen verloren! Lerne daraus – Richte Protected Branches ein, die Force-Push verbieten. Merge und Rebase in PhpStorm Merge durchführen Stelle sicher, dass du auf dem Ziel-Branch bist (z.B. feature) Gehe zu Git → Merge... Wähle den Branch, den du einmergen möchtest (z.B. main) Klicke auf Merge Bei Konflikten öffnet sich der Merge-Dialog Rebase durchführen Stelle sicher, dass du auf dem Branch bist, den du rebasen möchtest (z.B. feature) Gehe zu Git → Rebase... Wähle den Branch, auf den du rebasen möchtest (z.B. main) Klicke auf Rebase Bei Konflikten: Löse jeden Konflikt im Editor Klicke auf Continue Rebase in der Notification Tipp: Rebase über das Git-Log-Fenster Eine besonders intuitive Methode in PhpStorm: Öffne das Git-Tool-Window (Alt+9 / Cmd+9) Sieh dir das Commit-Log an Rechtsklicke auf den Commit, auf den du rebasen möchtest Wähle Rebase Current onto Selected Praktisches Beispiel: Ein Tag im Leben eines Entwicklers Lass mich einen typischen Workflow durchspielen: Morgens: Feature-Branch erstellen git checkout main git pull git checkout -b feature/user-profile Während des Tages: Entwickeln mit vielen kleinen Commits git commit -m "WIP: Grundstruktur angelegt" git commit -m "WIP: Formular hinzugefügt" git commit -m "Fix Typo" git commit -m "WIP: Validierung" git commit -m "Fertig mit Validierung" Vor dem Feierabend: Aufräumen mit Interactive Rebase git rebase -i HEAD~5 # Im Editor: squash die WIP-Commits zusammen # Ergebnis: 2 saubere Commits statt 5 chaotische Nächster Morgen: Auf aktuellen main rebasen git fetch origin git rebase origin/main # Konflikte lösen, falls nötig Push und Pull Request git push -u origin feature/user-profile # Pull Request auf GitHub erstellen Nach dem Review: Merge in main Auf GitHub: Squash and Merge oder Merge Commit – je nach Team-Konvention. Zusammenfassung: Merge vs. Rebase auf einen Blick Kriterium Merge Rebase Historie Verzweigt, zeigt parallele Entwicklung Linear, als wäre sequentiell entwickelt worden Neue Commits Ein Merge-Commit Keine neuen Commits (außer neu erstellten) Original-Commits Bleiben unverändert Werden neu erstellt (neue SHA-Hashes) Sicherheit Immer sicher Nur sicher für nicht-gepushte Commits Konfliktlösung Einmal im Merge-Commit Für jeden Commit einzeln Lesbarkeit Kann unübersichtlich werden Sehr übersichtlich Empfohlen für Öffentliche Branches, Team-Arbeit Lokale Arbeit, Branch-Aktualisierung Meine Empfehlung: Starte mit Merge als Standard – es ist sicherer und verzeihender. Nutze Rebase gezielt für lokale Aufräumarbeiten und Branch-Aktualisierungen, bevor du pushst. Mit der Zeit wirst du ein Gefühl dafür entwickeln, wann welcher Ansatz am besten passt. 🎯