Kapitel 4 von 5

Git-Tutorial: Branches, Merge und Konflikte im Team

geprüft am 7 September 2026 · 10 Min.

Schnelle Antwort

Leg mit git switch -c nom einen Branch an, arbeite, und merge ihn dann vom Zielbranch aus mit git merge. Bei einem Konflikt setzt Git Marker in die Datei: schreib den richtigen Inhalt, entferne die Marker, dann git add und git commit. git merge --abort macht jederzeit alles rückgängig.

Ein Branch ist eine parallele Entwicklungslinie. Mit ihm arbeitest du an einem Feature, ohne die stabile Version anzufassen, und dein Kollege macht auf seiner Seite dasselbe. Dieses Kapitel deckt den kompletten Zyklus ab: einen Branch anlegen, ihn mergen, einen Konflikt von Hand lösen und zwischen merge und rebase wählen.

git switch statt git checkout

Historisch war git checkout für alles zuständig: den Branch wechseln, einen neuen anlegen, eine Datei wiederherstellen, auf einen bestimmten Commit springen. Diese Häufung von Rollen ist bei Einsteigern die häufigste Ursache für Verwirrung und bei allen anderen für Unfälle.

Git 2.23 vom August 2019 hat den Befehl in zwei geteilt: git switch für den Wechsel zwischen Branches, git restore zum Verwerfen von Änderungen. Bei ihrem Erscheinen galten beide als experimentell, in der offiziellen Dokumentation tun sie das nicht mehr. Dieses Kapitel benutzt sie und nennt jedes Mal die Entsprechung mit checkout, die dir in Tutorials und auf Stack Overflow noch lange begegnen wird.

Ziel Moderner Befehl Alte Form
Den Branch wechseln git switch nom git checkout nom
Einen Branch anlegen und hineinwechseln git switch -c nom git checkout -b nom
Zurück zum vorigen Branch git switch - git checkout -
Die Änderung an einer Datei verwerfen git restore fichier git checkout -- fichier
Eine Datei aus dem Index nehmen git restore --staged fichier git reset HEAD fichier

Einen Branch anlegen und darin arbeiten

bash
git switch -c feature/panier
Sortie réelle · git switch -c
Switched to a new branch 'feature/panier'

Der Branch startet an dem Commit, auf dem du gerade standest. Du kannst jetzt normal ändern, hinzufügen und committen: nichts davon taucht auf main auf, solange du es nicht gemergt hast.

Für Branch-Namen schreibt Git keine Regel vor, aber die Präfixe feature/, fix/ und hotfix/ sind eine verbreitete Konvention, und die Oberflächen der Hoster gruppieren sie sichtbar.

Um zu sehen, wo du stehst:

bash
git branch              # die lokalen Branches
git branch -vv          # mit dem letzten Commit und dem verfolgten Remote-Branch
git branch -a           # lokale und entfernte
git switch -            # zurück zum vorigen Branch

Um den Branch zu veröffentlichen und ihn dem Team sichtbar zu machen:

bash
git push -u origin feature/panier

Den Branch eines Kollegen holen

In der Gegenrichtung bringt git fetch deinen Kenntnisstand über den Server auf den neuesten Stand, ohne an deinen Branches etwas zu ändern:

bash
git fetch origin feature/collegue   # einen bestimmten Branch
git fetch --all                     # alle Remote-Repositories
git branch -r                       # was du vom Server weißt
Sortie réelle · git branch -r après un fetch
  origin/HEAD -> origin/main
  origin/feature/collegue
  origin/main

Jetzt musst du nur noch hineinwechseln. Git legt den lokalen Branch automatisch an und verknüpft ihn mit dem des Servers:

bash
git switch feature/collegue
Sortie réelle · git switch sur une branche distante
branch 'feature/collegue' set up to track 'origin/feature/collegue'.
Switched to a new branch 'feature/collegue'

Wenn Git den Branch-Wechsel verweigert

Das ist einer der ersten Fehler, die dir begegnen werden:

Sortie réelle · git switch avec des modifications non committées
error: Your local changes to the following files would be overwritten by checkout:
	index.html
Please commit your changes or stash them before you switch branches.
Aborting

Git schützt deine Arbeit: die Datei, die du geändert hast, hat auf dem anderen Branch einen anderen Inhalt, und der Wechsel würde sie überschreiben. Drei Lösungen, nach Vorzug geordnet.

Committen, wenn die Arbeit in sich stimmig ist. Das ist fast immer die richtige Antwort, ein unfertiger Commit auf einem Arbeitsbranch kostet nichts und lässt sich später mit den Befehlen zum Rückgängigmachen aus dem vorigen Kapitel korrigieren.

Beiseitelegen, wenn die Arbeit halb fertig ist:

bash
git stash          # legt die Änderungen beiseite
git switch main    # …du erledigst, was zu erledigen war…
git switch -
git stash pop      # holt die Änderungen zurück
Sortie réelle · git stash
Saved working directory and index state WIP on main: 6d495d9 Page d accueil

Wegwerfen, mit git restore ., wenn die Änderungen nichts taugten. Ohne Rückweg.

Einen Branch mergen

Ist das Feature fertig, wechsel auf den Zielbranch und merge:

bash
git switch main
git merge feature/panier

Haben die beiden Branches unterschiedliche Dateien geändert, erledigt Git die Zusammenführung allein und muss dich nichts fragen. Interessant ist der andere Fall.

Einen Konflikt lösen

Hier die Situation, die für dieses Kapitel nachgestellt wurde. Auf feature/panier wurde die zweite Zeile von index.html durch eine Meldung über den leeren Warenkorb ersetzt. Auf main wurde die erste Zeile geändert, um den Markennamen zu ergänzen. Beide Branches haben dieselbe Datei angefasst.

Sortie réelle · git merge feature/panier
Auto-merging index.html
CONFLICT (content): Merge conflict in index.html
Automatic merge failed; fix conflicts and then commit the result.

Nichts ist kaputt. Git hat zusammengeführt, was ging, und überlässt dir den Rest. Als Erstes fragst du, wo du stehst:

bash
git status
Sortie réelle · git status pendant un conflit
On branch main
Your branch is ahead of 'origin/main' by 1 commit.
  (use "git push" to publish your local commits)

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:   index.html

no changes added to commit (use "git add" and/or "git commit -a")

Nur die Liste der zu bearbeitenden Dateien:

bash
git diff --name-only --diff-filter=U

Öffne die Datei. Git hat dort Marker eingefügt:

index.html pendant le conflit
<<<<<<< HEAD
<h1>Boutique Gekkode</h1>
<p>Bienvenue sur la boutique.</p>
=======
<h1>Boutique</h1>
<p>Votre panier est vide.</p>
>>>>>>> feature/panier

Das liest sich mechanisch. Zwischen <<<<<<< HEAD und ======= steht die Version des Branches, auf dem du bist, hier main. Zwischen ======= und >>>>>>> steht die Version des Branches, den du mergst.

Das richtige Ergebnis schreibst du selbst. Es ist nicht zwingend die eine oder die andere Fassung: hier sind beide Änderungen gut und müssen nebeneinander bestehen bleiben.

index.html après résolution
<h1>Boutique Gekkode</h1>
<p>Votre panier est vide.</p>

Lösch die drei Marker, sie dürfen nicht in der Datei bleiben. Sag Git dann, dass die Sache erledigt ist, und schließ den Merge ab:

bash
git add index.html
git commit -m "Fusionne feature/panier dans main"
Sortie réelle · git log --oneline --graph après la fusion
*   0899b0c Fusionne feature/panier dans main
|  
| * aacf4c0 Panier : message quand le panier est vide
* | 11ff16b Ajoute le nom de la marque au titre
|/  
* 6d495d9 Page d accueil

Der Merge-Commit hat zwei Elternteile, und der Graph macht das sichtbar.

Alles abbrechen und neu ansetzen

Wächst dir der Konflikt über den Kopf, bist du zu nichts verpflichtet:

bash
git merge --abort

Das Repository steht wieder genau so da wie vor dem Befehl merge. Nichts ist verloren, du kannst später neu anfangen oder die Sache mit dem Autor des anderen Branches besprechen.

merge oder rebase

Beide binden die Arbeit eines Branches in einen anderen ein, aber nicht auf dieselbe Weise.

git merge legt einen Merge-Commit an, der die beiden Historien verbindet. Die Historie behält die genaue Spur dessen, was passiert ist, einschließlich der Tatsache, dass zwei Branches parallel existiert haben. Der Graph ist getreu, aber er verzweigt sich.

git rebase spielt deine Commits über dem Zielbranch neu ein, als hättest du von dessen letzter Version aus gearbeitet. Die Historie bleibt eine gerade Linie und ist leichter zu lesen, aber sie wird umgeschrieben: deine Commits bekommen neue IDs.

bash
git switch feature/panier
git rebase main

Ein Rebase kann auf dieselben Konflikte stoßen wie ein Merge, Commit für Commit. Die Lösung ist identisch, nur der Befehl zum Weitermachen unterscheidet sich:

Sortie réelle · conflit pendant un rebase
Auto-merging index.html
CONFLICT (content): Merge conflict in index.html
error: could not apply 4937109... Promo
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".
hint: Disable this message with "git config set advice.mergeConflict false"
Could not apply 4937109... Promo
bash
git add index.html
git rebase --continue
# oder, um alles abzubrechen
git rebase --abort

Die goldene Regel passt in einen Satz: rebase nie einen Branch, den andere schon geholt haben. Eine geteilte Historie umzuschreiben zwingt deine Kollegen dazu, ihre eigene von Hand zu reparieren. Auf deinem eigenen Arbeitsbranch dagegen, bevor du ihn anbietest, ist ein Rebase völlig legitim und liefert eine deutlich lesbarere Historie.

Der Alltagsfall: jemand hat vor dir gepusht

Du willst pushen, und Git verweigert es:

Sortie réelle · git push refusé
To /root/o.git
 ! [rejected]        main -> main (fetch first)
error: failed to push some refs to '/root/o.git'
hint: Updates were rejected because the remote contains work that you do not

Der Server hat Commits, die du nicht hast. Du musst sie zuerst einbinden. Und an dieser Stelle stellt dir Git auf einem frischen Repository eine Frage, statt zu handeln:

Sortie réelle · git pull sans stratégie configurée
hint: You have divergent branches and need to specify how to reconcile them.
hint: You can do so by running one of the following commands sometime before
hint: your next pull:
hint:
hint:   git config pull.rebase false  # merge
hint:   git config pull.rebase true   # rebase
hint:   git config pull.ff only       # fast-forward only
hint:

Seit Version 2.27 weigert sich Git, an deiner Stelle zu wählen. Beantworte die Frage ein für alle Mal, wie im Installationskapitel vorgeschlagen:

bash
git config --global pull.rebase true

Der Ablauf sieht dann so aus:

bash
git pull --rebase
git push
Sortie réelle · git pull --rebase puis git log
From /root/o
   622a60b..38b7dc5  main       -> origin/main
Rebasing (1/1)Successfully rebased and updated refs/heads/main.

* 5b45117 Ajoute app.js
* 38b7dc5 Ajoute la doc
* 622a60b Depart

Dein Commit wurde über den des Kollegen gesetzt, und die Historie ist linear geblieben, ohne störenden Merge-Commit. Das ist die Einstellung, die sich für ein Team am Anfang empfiehlt.

Zum Schluss eine Warnung: versuch nie, einen abgelehnten push mit git push --force durchzudrücken. Dieser Befehl überschreibt die Arbeit, die auf dem Server liegt. Musst du wirklich forcieren, nach einem Rebase deines eigenen Branches, dann nimm git push --force-with-lease: es weigert sich, Commits zu überschreiben, die du noch nicht gesehen hattest.

Aufräumen

Ein zusammengeführter Branch hat keinen Grund mehr zu existieren. Wurde er mit -u veröffentlicht, pushen Sie zuerst seine letzten Commits: Git weigert sich, einen lokalen Branch zu löschen, der seinem Remote-Branch voraus ist, selbst wenn er in main gemergt ist.

bash
git push origin feature/panier
git branch -d feature/panier
Sortie réelle · suppression d'une branche fusionnée
Deleted branch feature/panier (was bc2203a).

Ohne diesen vorherigen push ist die Meldung eindeutig:

Sortie réelle · branche locale en avance sur origin
warning: not deleting branch 'feature/panier' that is not yet merged to
         'refs/remotes/origin/feature/panier', even though it is merged to HEAD
error: the branch 'feature/panier' is not fully merged
hint: If you are sure you want to delete it, run 'git branch -D feature/panier'
hint: Disable this message with "git config set advice.forceDeleteBranch false"

Wurde der Branch nicht gemergt, stoppt Git dich, was ein nützliches Sicherheitsnetz ist:

Sortie réelle · suppression d'une branche non fusionnée
error: the branch 'feature/promo' is not fully merged
hint: If you are sure you want to delete it, run 'git branch -D feature/promo'
hint: Disable this message with "git config set advice.forceDeleteBranch false"

Um den Branch auch auf dem Server zu löschen und die lokal überflüssig gewordenen Referenzen aufzuräumen:

bash
git push origin --delete feature/panier
git fetch --prune

git fetch holt den Stand des Servers, ohne etwas in deine Branches zu mergen, anders als git pull. Die Option --prune entfernt dabei die Remote-Branches, die es nicht mehr gibt, also die, die deine Kollegen gemergt und gelöscht haben.

Du kannst jetzt zusammenarbeiten. Das letzte Kapitel behandelt die Organisation: welches Branch-Modell zu deinem Team passt.

Häufige Fehler

Your local changes would be overwritten by checkout Committe deine Änderungen oder leg sie mit git stash beiseite, bevor du den Branch wechselst.
You have divergent branches Seit Git 2.27 weigert sich git pull, allein zwischen Merge und Rebase zu wählen. Klär die Frage mit git config --global pull.rebase true.
! [rejected] non-fast-forward Der Server hat Commits, die du nicht hast. Bind sie mit git pull --rebase ein. Nimm nie git push --force, um dich darüber hinwegzusetzen: es überschreibt die Arbeit der anderen.
Vergessene Konfliktmarker Die Zeilen, die mit <<<<<<<, ======= und >>>>>>> beginnen, müssen vor dem git add aus der Datei verschwinden.
Rebase eines geteilten Branches Eine Historie umzuschreiben, die andere schon geholt haben, zwingt sie dazu, ihre eigene zu reparieren. Rebase nur deine eigenen, noch nicht veröffentlichten Branches.
Newsletter

Neue Tests, Tutorials und Projekte, per E-Mail.

Reproduzierbare Tests, versionierter Code, datierte Ergebnisse. Niemals Spam.