git merge: Branches zusammenführen und Konflikte lösen
git merge führt die Historie eines anderen Branches mit dem aktuellen zusammen: Ist der aktuelle Branch nicht vorangeschritten, verschiebt Git einfach den Zeiger (Fast-Forward), andernfalls entsteht ein Merge-Commit mit zwei Eltern. Wechseln Sie in den Ziel-Branch und führen Sie git merge branch-name aus; bei einem Konflikt korrigieren Sie die Dateien, dann git add und git commit – oder brechen alles mit git merge --abort ab.
Was macht git merge?
Der Befehl git merge nimmt die Änderungen aus dem angegebenen Branch und integriert sie in den Branch, in dem Sie sich gerade befinden. Merken Sie sich die Richtung: Man merged „in sich hinein“. Um feature/login in main zu übernehmen, wechselt man zuerst zu main und ruft dann den Merge auf.
git switch main
git pull # aktuellen main vom Server holen
git merge feature/login
Git kopiert nichts zeilenweise „von Hand“. Es sucht den gemeinsamen Vorfahren der beiden Branches (Merge-Base), vergleicht beide Versionen damit und kombiniert die Änderungen. Haben beide Seiten verschiedene Stellen bearbeitet, entsteht das Ergebnis automatisch. Ist es dieselbe Stelle, gibt es einen Konflikt, und die Entscheidung treffen Sie.
Zwei Modi: Fast-Forward und Three-Way-Merge
Fast-Forward – wenn kein Merge-Commit nötig ist
Angenommen, Sie haben feature von main abgezweigt, drei Commits gemacht, und in main ist inzwischen nichts hinzugekommen. Dann ist die Historie von main einfach der Anfang der Historie von feature. Git verschiebt den Zeiger main nach vorn auf den letzten Commit von feature, ein neuer Commit entsteht nicht.
$ git merge feature
Updating 3f2a1c4..9b7e0d2
Fast-forward
src/auth.js | 42 ++++++++++++++++++++++++++++++++++++++++++
1 file changed, 42 insertions(+)
Die Historie bleibt linear, aber die Information „hier gab es einen Branch feature“ geht verloren. Manchmal ist das gut, manchmal nicht – dazu mehr unten im Abschnitt über --no-ff.
Three-Way-Merge und Merge-Commit
Sind beide Branches seit dem gemeinsamen Vorfahren vorangeschritten, lässt sich der Zeiger nicht mehr einfach verschieben. Git führt einen Three-Way-Merge durch: Basis, „unsere“ Seite (aktueller Branch) und „ihre“ Seite (der zu mergende Branch). Das Ergebnis wird in einem eigenen Merge-Commit mit zwei Eltern festgehalten.
$ git merge feature
Merge made by the 'ort' strategy.
src/auth.js | 42 ++++++++++++++++++++
src/router.js | 3 +-
2 files changed, 44 insertions(+), 1 deletion(-)
Git öffnet einen Editor mit einer Nachricht wie Merge branch 'feature'. Sie können sie lassen oder ergänzen, warum gemerged wurde. Die entstandene „Gabelung“ sehen Sie bequem so:
git log --oneline --graph --all
Die Strategie ort ist seit Git 2.34 Standard; davor war es recursive. Für die tägliche Arbeit müssen Sie die Strategie nicht ändern.
Nützliche Flags für git merge
| Flag | Was es tut | Wann es nützlich ist |
|---|---|---|
--no-ff | Erzeugt immer einen Merge-Commit, auch wenn Fast-Forward möglich wäre | Sie möchten in der Historie sehen, welche Commits aus einem Feature stammen |
--ff-only | Merged nur per Vorspulen, sonst Abbruch mit Fehler | Lokalen Branch aktualisieren ohne versehentliche Merge-Commits |
--squash | Legt alle Änderungen des Branches in den Index, committet aber nicht und erzeugt keine Verbindung zum Branch | Ein Feature soll ein einziger sauberer Commit werden |
--no-commit | Führt den Merge durch, hält aber vor dem Commit an | Sie möchten das Ergebnis prüfen oder Tests vor dem Festschreiben laufen lassen |
-m "text" | Legt die Nachricht des Merge-Commits fest | Merges in Skripten und ohne Editor |
--abort | Bricht einen begonnenen Merge ab und stellt den vorherigen Zustand wieder her | Zu viele Konflikte, Sie wollen neu beginnen |
--continue | Schließt den Merge nach dem Lösen der Konflikte ab | Alternative zu git commit im letzten Schritt |
-X ours / -X theirs | Übernimmt bei konfliktbehafteten Abschnitten automatisch unsere oder ihre Version | Sie wissen sicher, wessen Version richtig ist (Vorsicht!) |
--no-ff: Feature-Grenzen erhalten
Viele Teams mergen Features nur mit --no-ff. Dann erscheint jede Aufgabe im Graphen als „Blase“ und lässt sich mit einem einzigen git revert -m 1 <merge-commit> zurücknehmen. Bei Fast-Forward gibt es diesen Punkt nicht, und Sie müssten jeden Commit einzeln rückgängig machen.
--squash: ein Commit statt zehn
git switch main
git merge --squash feature/login
git commit -m "Login per E-Mail und Passwort"
Nach --squash betrachtet Git den Branch nicht als gemerged: git branch -d feature/login verweigert das Löschen mit der Warnung „not fully merged“. Löschen Sie mit git branch -D, sobald Sie sicher sind, dass alles angekommen ist. Und arbeiten Sie nach einem Squash nicht im selben Branch weiter – der nächste Merge bringt die bereits übernommenen Änderungen erneut und führt fast sicher zu Konflikten.
Merge-Konflikt: so lösen Sie ihn
Ein Konflikt ist eine normale Arbeitssituation, kein Unfall. Er bedeutet nur: Zwei Branches haben dieselben Zeilen geändert (oder einer hat eine Datei gelöscht, die der andere bearbeitet hat), und Git rät nicht, welche Version richtig ist.
$ git merge feature/login
Auto-merging src/config.js
CONFLICT (content): Merge conflict in src/config.js
Automatic merge failed; fix conflicts and then commit the result.
Schritt 1. Sehen, was in Konflikt steht
$ git status
On branch main
You have unmerged paths.
(fix conflicts and run "git commit")
(use "git merge --abort" to abort the merge)
Unmerged paths:
(use "git add <file>..." to mark resolution)
both modified: src/config.js
Schritt 2. Die Datei bearbeiten
In der Konfliktdatei setzt Git Markierungen:
<<<<<<< HEAD
const TIMEOUT = 5000;
=======
const TIMEOUT = 10000;
>>>>>>> feature/login
Der obere Teil ist Ihr aktueller Branch (HEAD), der untere der zu mergende. Behalten Sie die richtige Variante (oder kombinieren Sie beide), entfernen Sie alle drei Markierungszeilen und speichern Sie die Datei. Ein häufiger Fehler ist eine vergessene Markierung irgendwo mitten in der Datei; suchen Sie vor dem Commit danach: git diff --check hebt verbliebene Markierungen hervor.
Schritt 3. Lösung markieren und Merge abschließen
git add src/config.js
git commit # oder git merge --continue
Wenn sich der Konflikt komplett durch die Wahl einer Seite lösen lässt, müssen Sie die Datei nicht von Hand bearbeiten:
git checkout --ours src/config.js # Version des aktuellen Branches behalten
git checkout --theirs src/config.js # Version des zu mergenden Branches übernehmen
git add src/config.js
Bequemer im Editor
VS Code, JetBrains-IDEs und andere Editoren zeigen den Konflikt in drei Spalten und bieten Schaltflächen wie „Accept Current / Incoming / Both“. Ein externes Tool binden Sie über git mergetool ein. Eine nützliche Einstellung ist git config --global merge.conflictStyle zdiff3: In den Markierungen erscheint zusätzlich die ursprüngliche Version des gemeinsamen Vorfahren, und es wird klar, wer was geändert hat.
Meinung geändert – Merge abbrechen
git merge --abort
Der Befehl setzt Arbeitsverzeichnis und Index auf den Zustand vor git merge zurück. Deshalb ist es besser, vor dem Merge einen sauberen Arbeitsbaum zu haben: Committen Sie unfertige Änderungen oder legen Sie sie mit git stash beiseite, sonst lassen sie sich schwer vom Merge-Ergebnis trennen.
Einen bereits durchgeführten Merge rückgängig machen
Wurde der Merge-Commit noch nicht auf den Server gepusht, setzen Sie den Branch am einfachsten zurück:
git reset --hard ORIG_HEAD
ORIG_HEAD schreibt Git vor riskanten Operationen, auch vor einem Merge – das ist die Position des Branches vor dem Merge. --hard verwirft nicht committete Änderungen, prüfen Sie also vorher git status.
Ist der Merge bereits im gemeinsamen Repository, schreibt man die Historie nicht um. Stattdessen erzeugt man einen Gegen-Commit:
git revert -m 1 a1b2c3d
Das Flag -m 1 besagt, dass der erste Elternteil (der Branch, in den gemerged wurde) als „Hauptlinie“ gilt. Beachten Sie den Haken: Nach so einem revert betrachtet Git die Commits des Features als bereits übernommen. Wollen Sie das korrigierte Feature später erneut mergen, müssen Sie zuerst den revert-Commit selbst reverten.
Merge in der Teamarbeit
git pull ist fetch plus merge
Ein normales git pull lädt die Änderungen herunter und merged den Remote-Branch in den lokalen. Haben Sie und eine Kollegin parallel committet, entsteht ein Commit „Merge branch 'main' of ...“. Um solche technischen Merges zu vermeiden, setzen Sie git config --global pull.ff only (pull schlägt fehl, wenn kein Vorspulen möglich ist, und Sie entscheiden selbst) oder nutzen git pull --rebase.
Pull Request und der Merge-Button
Auf GitHub und GitLab erfolgt der Merge meist über einen Pull- bzw. Merge-Request. Der Button „Create a merge commit“ entspricht git merge --no-ff, „Squash and merge“ einem Merge mit Squash, „Rebase and merge“ einem Rebase. Welcher Modus gilt, ist eine Teamvereinbarung – der Mechanismus ist derselbe wie in der Konsole.
main in den eigenen Branch mergen
Ein langlebiger Branch entfernt sich von main, und Konflikte sammeln sich an. Holen Sie den Hauptbranch regelmäßig zu sich:
git switch feature/login
git fetch origin
git merge origin/main
So lösen Sie Konflikte in kleinen Portionen, sobald sie auftreten, und der finale Merge in main verläuft reibungslos.
Typische Fehler
- In die falsche Richtung gemerged.
git merge mainausgeführt, während man inmainist, oder ein Feature in ein anderes Feature gemerged. Prüfen Sie vor dem Merge den aktuellen Branch mitgit branch --show-current. - Merge mit veraltetem Branch. Einen lokalen
maingemerged, der eine Woche nicht aktualisiert wurde. Erstgit pull, dann merge. - „Your local changes would be overwritten by merge“. Im Arbeitsverzeichnis gibt es nicht committete Änderungen in denselben Dateien. Committen Sie sie oder legen Sie sie in den stash.
- „refusing to merge unrelated histories“. Die Branches haben keinen gemeinsamen Vorfahren – etwa wenn das lokale Repository mit
git initerstellt wurde und das Remote bereits eine README enthält. Wenn die Zusammenführung wirklich gewollt ist, ergänzen Sie--allow-unrelated-histories. - Konfliktmarkierungen committet. Der Build scheitert an
<<<<<<<. Prüfen Sie mitgit diff --checkund lassen Sie die Tests vor dem Commit laufen.
Fazit
git merge ist eine sichere Methode, Branches zusammenzuführen: Bestehende Commits werden nicht umgeschrieben, es kommt nur ein neuer hinzu (oder der Zeiger wird vorgespult). Mergen Sie in den aktuellen Branch, halten Sie den Arbeitsbaum sauber, nutzen Sie --no-ff, wenn Feature-Grenzen wichtig sind, und --squash, wenn ein einziger Commit gewünscht ist. Konflikte lösen Sie in drei Schritten: Datei bearbeiten, git add, git commit – und git merge --abort bringt Sie jederzeit zum Ausgangspunkt zurück. Das Zusammenführen von Branches und das Lösen von Konflikten üben wir ausführlich in der Praxis in unserem Git-Kurs.
Häufige Fragen
Was ist der Unterschied zwischen git merge und git pull?
git pull lädt zuerst die Änderungen vom Server (git fetch) und merged dann den Remote-Branch per git merge oder, je nach Einstellung, per rebase in den aktuellen. git merge arbeitet nur mit dem, was lokal bereits vorhanden ist.
Kann ich mehrere Branches gleichzeitig mergen?
Ja, git merge feature-a feature-b führt einen Octopus-Merge mit mehreren Eltern durch, aber nur, wenn es keine Konflikte gibt. In der Praxis merged man Branches meist einzeln.
Wie sehe ich, welche Branches bereits in den aktuellen gemerged sind?
git branch --merged zeigt die Branches, die vollständig im aktuellen enthalten sind, git branch --no-merged die noch nicht gemergten. Gemergte Branches können Sie bedenkenlos mit git branch -d löschen.
Wie sehe ich vorab, was ein Merge mitbringt?
Führen Sie git log main..feature aus, um die Commits zu sehen, die nicht in main sind, und git diff main...feature, um die Änderungen des Branches gegenüber dem gemeinsamen Vorfahren zu sehen.
Was ist ORIG_HEAD nach einem Merge?
Das ist eine Referenz, die Git vor dem Merge speichert: Sie zeigt auf die Position des Branches vor dem Merge. Mit git reset --hard ORIG_HEAD können Sie einen lokalen Merge zurücknehmen, solange er nicht auf den Server gepusht wurde.
Dieses Thema wird im Kurs „Git vom Anfänger zum versierten Entwickler“ ausführlich mit Praxis behandelt.
Zum Kurs