Hoofdstuk 4 van 5

Git-tutorial: samenwerken met branches, merge en rebase

geverifieerd op 7 september 2026 · 10 min

Kort antwoord

Maak een branch met git switch -c nom, werk eraan en merge hem daarna met git merge vanaf de doelbranch. Bij een conflict zet Git markeringen in het bestand: schrijf de juiste inhoud, verwijder de markeringen en doe dan git add en git commit. git merge --abort maakt op elk moment alles ongedaan.

Een branch is een parallelle ontwikkellijn. Daarmee werk je aan een feature zonder de stabiele versie aan te raken, terwijl je collega aan zijn kant hetzelfde doet. Dit hoofdstuk behandelt de volledige cyclus: een branch aanmaken, hem mergen, een conflict met de hand oplossen en kiezen tussen merge en rebase.

git switch in plaats van git checkout

Historisch deed git checkout alles: van branch wisselen, er een aanmaken, een bestand terugzetten, naar een specifieke commit springen. Die opeenstapeling van rollen is de eerste bron van verwarring bij beginners, en een bron van ongelukken bij de rest.

Git 2.23, uitgebracht in augustus 2019, splitste het commando in tweeën: git switch om tussen branches te wisselen, git restore om wijzigingen ongedaan te maken. Bij hun release stonden ze als experimenteel te boek, in de officiële documentatie is dat niet langer zo. Dit hoofdstuk gebruikt ze, en geeft telkens het equivalent in checkout, dat je nog lang in tutorials en op Stack Overflow zult tegenkomen.

Bedoeling Modern commando Oude vorm
Van branch wisselen git switch nom git checkout nom
Een branch aanmaken en erheen gaan git switch -c nom git checkout -b nom
Terug naar de vorige branch git switch - git checkout -
De wijziging van een bestand ongedaan maken git restore fichier git checkout -- fichier
Een bestand uit de index halen git restore --staged fichier git reset HEAD fichier

Een branch aanmaken en eraan werken

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

De branch vertrekt vanaf de commit waarop je stond. Je kunt nu gewoon wijzigen, toevoegen en committen: niets daarvan verschijnt op main zolang je het niet hebt gemerged.

Voor branchnamen legt Git geen enkele regel op, maar de prefixen feature/, fix/ en hotfix/ zijn een wijdverbreide conventie, en de interfaces van de hosters groeperen ze visueel.

Om te zien waar je staat:

bash
git branch              # de lokale branches
git branch -vv          # met de laatste commit en de gevolgde remote branch
git branch -a           # lokale en remote
git switch -            # terug naar de vorige branch

Om de branch te publiceren en zichtbaar te maken voor het team:

bash
git push -u origin feature/panier

De branch van een collega ophalen

Andersom brengt git fetch je beeld van de server bij zonder iets in je branches te wijzigen:

bash
git fetch origin feature/collegue   # een specifieke branch
git fetch --all                     # alle remote repositories
git branch -r                       # wat je van de server weet
Sortie réelle · git branch -r après un fetch
  origin/HEAD -> origin/main
  origin/feature/collegue
  origin/main

Daarna hoef je er alleen nog naartoe te schakelen. Git maakt de lokale branch automatisch aan en koppelt hem aan die van de server:

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'

Als Git weigert van branch te wisselen

Dit is een van de eerste fouten die je tegenkomt:

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 beschermt je werk: het bestand dat je hebt gewijzigd heeft op de andere branch niet dezelfde inhoud, en wisselen zou het overschrijven. Drie oplossingen, in volgorde van voorkeur.

Committen, als het werk samenhangend is. Dat is bijna altijd het juiste antwoord, een onvolmaakte commit op een werkbranch kost niets en corrigeer je later met de commando’s om terug te komen op je stappen uit het vorige hoofdstuk.

Opzijzetten, als het werk half af is:

bash
git stash          # zet de wijzigingen opzij
git switch main    # …je doet wat je te doen had…
git switch -
git stash pop      # haalt de wijzigingen terug
Sortie réelle · git stash
Saved working directory and index state WIP on main: 6d495d9 Page d accueil

Weggooien, met git restore ., als de wijzigingen niets waard waren. Zonder weg terug.

Een branch mergen

Is de feature klaar, ga dan naar de doelbranch en merge:

bash
git switch main
git merge feature/panier

Hebben de twee branches verschillende bestanden gewijzigd, dan merget Git helemaal zelf en hoeft het je niets te vragen. Interessant wordt het in het andere geval.

Een conflict oplossen

Dit is de situatie die voor dit hoofdstuk is nagebouwd. Op feature/panier is de tweede regel van index.html vervangen door een bericht dat de winkelwagen leeg is. Op main is de eerste regel aangepast om de merknaam toe te voegen. Beide branches hebben hetzelfde bestand aangeraakt.

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.

Er is niets stuk. Git heeft gemerged wat het kon en laat de rest aan jou. Vraag eerst waar je staat:

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")

Wil je alleen de lijst met te behandelen bestanden:

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

Open het bestand. Git heeft er markeringen in gezet:

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

Het lezen gaat mechanisch. Tussen <<<<<<< HEAD en ======= staat de versie van de branch waarop je staat, hier main. Tussen ======= en >>>>>>> staat de versie van de branch die je merget.

Aan jou om het juiste resultaat te schrijven. Dat is niet per se de ene of de andere: hier zijn beide wijzigingen goed en moeten ze naast elkaar bestaan.

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

Verwijder de drie markeringen, die mogen niet in het bestand blijven staan. Meld daarna aan Git dat het geregeld is en rond de merge af:

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

De merge-commit heeft twee ouders, en de graaf maakt dat zichtbaar.

Alles annuleren en opnieuw beginnen

Gaat het conflict je boven de pet, dan zit je nergens aan vast:

bash
git merge --abort

De repository keert precies terug naar de toestand van voor het merge-commando. Er gaat niets verloren, je kunt later opnieuw beginnen of erover overleggen met de auteur van de andere branch.

merge of rebase

Beide brengen het werk van de ene branch in de andere onder, maar niet op dezelfde manier.

git merge maakt een merge-commit die de twee geschiedenissen verbindt. De geschiedenis houdt exact bij wat er is gebeurd, inclusief het feit dat er twee branches naast elkaar hebben bestaan. De graaf is getrouw, maar hij vertakt.

git rebase speelt je commits opnieuw af boven op de doelbranch, alsof je vanaf de laatste versie ervan had gewerkt. De geschiedenis blijft een rechte lijn, makkelijker te lezen, maar ze wordt herschreven: je commits krijgen een andere hash.

bash
git switch feature/panier
git rebase main

Een rebase kan dezelfde conflicten tegenkomen als een merge, commit voor commit. Het oplossen gaat identiek, alleen het commando om verder te gaan verschilt:

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
# of, om alles te annuleren
git rebase --abort

De gouden regel past in één zin: rebase nooit een branch die anderen al hebben opgehaald. Een gedeelde geschiedenis herschrijven dwingt je collega’s om die van hen met de hand te repareren. Op je eigen werkbranch, voordat je hem aanbiedt, is een rebase daarentegen volkomen legitiem en levert hij een veel leesbaardere geschiedenis op.

Het alledaagse geval: iemand was je voor met pushen

Je wilt pushen, en Git weigert:

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

De server heeft commits die jij niet hebt. Die moet je eerst binnenhalen. En op een verse repository stelt Git je dan een vraag in plaats van te handelen:

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:

Sinds versie 2.27 weigert Git in jouw plaats te kiezen. Beantwoord de vraag voor eens en altijd, zoals voorgesteld in het installatiehoofdstuk:

bash
git config --global pull.rebase true

Het verloop wordt dan dit:

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

Je commit is boven op die van je collega geplaatst en de geschiedenis is lineair gebleven, zonder overbodige merge-commit. Dit is de instelling die je een beginnend team moet aanraden.

Tot slot een waarschuwing: probeer een geweigerde push nooit vlot te trekken met git push --force. Dat commando overschrijft het werk dat op de server staat. Moet je echt forceren, na een rebase van je eigen branch, gebruik dan git push --force-with-lease, dat weigert commits te overschrijven die jij niet had gezien.

Opruimen

Een samengevoegde branch heeft geen reden meer om te bestaan. Is hij met -u gepubliceerd, push dan eerst zijn laatste commits: Git weigert een lokale branch te verwijderen die voorloopt op zijn remote branch, ook al is hij in main samengevoegd.

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).

Zonder die voorafgaande push is de melding duidelijk:

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"

Is de branch niet gemerged, dan houdt Git je tegen, wat een nuttig vangnet is:

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"

Om de branch ook op de server te verwijderen en de lokale referenties op te ruimen die overbodig zijn geworden:

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

git fetch haalt de toestand van de server op zonder iets in je branches te mergen, anders dan git pull. De optie --prune verwijdert meteen de remote branches die niet meer bestaan, die je collega’s hebben gemerged en gewist.

Je kunt nu samenwerken. Het laatste hoofdstuk gaat over organisatie: welk branchmodel je kiest, afhankelijk van je team.

Veelgemaakte fouten

Your local changes would be overwritten by checkout Commit je wijzigingen, of zet ze opzij met git stash, voordat je van branch wisselt.
You have divergent branches Sinds Git 2.27 weigert git pull zelf te kiezen tussen merge en rebase. Regel dat met git config --global pull.rebase true.
! [rejected] non-fast-forward De server heeft commits die jij niet hebt. Haal ze binnen met git pull --rebase. Gebruik nooit git push --force om eroverheen te walsen: dat overschrijft het werk van anderen.
Vergeten conflictmarkeringen De regels die beginnen met <<<<<<<, ======= en >>>>>>> moeten uit het bestand verdwijnen voor de git add.
Rebase van een gedeelde branch Een geschiedenis herschrijven die anderen al hebben opgehaald, dwingt hen die van hen te repareren. Rebase alleen je eigen, nog niet gepubliceerde branches.
Nieuwsbrief

Nieuwe tests, tutorials en projecten, per e-mail.

Reproduceerbare tests, geversioneerde code, gedateerde resultaten. Nooit spam.