Sessie 12: Git Branches: Parallelle universums voor je code

Vorige sessie leerde je commits maken: foto’s van je code op één tijdlijn. Alles netjes achter elkaar.

Maar wat als je een nieuw idee wil uitproberen? Een lasergun toevoegen aan je game, bijvoorbeeld. Je weet niet of het gaat werken. Je wil je werkende code niet kapot maken.

Daar zijn branches voor.

Een branch is een kopie van je code waar je vrij kunt experimenteren. Je hoofdcode (de master-branch) blijft veilig. Als je experiment werkt, plak je het terug in master. Werkt het niet? Je gooit de branch weg. Je master-branch heeft er nooit iets van gemerkt.

Noot: Op GitHub en in veel nieuwe projecten heet de hoofdbranch main in plaats van master. Dat is exact hetzelfde, alleen de naam is anders. In deze cursus gebruiken we master, maar als je online main tegenkomt, weet je dat het hetzelfde betekent.

Wat je vandaag leert

  • Wat een branch is en hoe Git branches intern opslaat
  • Branches aanmaken, wisselen en samenvoegen
  • Wat een merge conflict is en hoe je het oplost
  • Wanneer je wél en níet een branch moet gebruiken

Stap 0: Herhaling: waar sta je nu?

Open je terminal in het project van vorige sessie. Check waar je bent:

git status
git log --oneline

Je hebt een paar commits op master. Dit is je stabiele basis: hier ga je straks vanaf splitsen.

Stap 1: Je eerste branch

Je gaat een nieuwe feature toevoegen: een highscore.txt-bestand dat de hoogste score bijhoudt. Maar eerst maak je een branch:

git branch highscore-feature

Git heeft nu een nieuwe branch aangemaakt. Maar je staat nog steeds op master. Check welke branches er zijn:

git branch

Je ziet:

  highscore-feature
* master

Het sterretje bij master betekent: “hier sta je nu.” Wissel naar je nieuwe branch:

git switch highscore-feature

(Oudere Git-versies gebruiken git checkout highscore-feature. Beide werken.)

Nog een keer git branch: het sterretje staat nu bij highscore-feature. Alles wat je nu commit, gebeurt op deze branch. master blijft onaangeroerd.

Tip: Je kunt een branch aanmaken en er meteen naartoe switchen in één commando:

git switch -c mijn-nieuwe-branch

-c staat voor “create”. Dit is sneller en je vergeet nooit te switchen.

Stap 2: Werk doen op een branch

Maak een nieuw bestand aan:

echo "HIGHSCORE: 0" > highscore.txt

Commit je werk:

git add highscore.txt
git commit -m "Add highscore.txt met beginwaarde 0"

Voeg nog een bestand toe dat de highscore leest:

echo 'def lees_highscore():' > highscore_manager.py
echo '    with open("highscore.txt") as f:' >> highscore_manager.py
echo '        return int(f.read().split(": ")[1])' >> highscore_manager.py

Commit opnieuw:

git add highscore_manager.py
git commit -m "Add highscore_manager: functie om highscore te lezen"

Kijk nu naar je log:

git log --oneline

Je ziet al je commits van master, plus de twee nieuwe. Git onthoudt de hele keten.

Stap 3: Twee werelden tegelijk

Switch terug naar master:

git switch master

Kijk wat er hier is:

ls

highscore.txt en highscore_manager.py zijn… weg. Ze bestaan alleen op de highscore-feature-branch. Op master is alles nog precies zoals je het achterliet.

Dit is de magie van branches: twee (of meer) versies van je project, tegelijk op je computer, zonder dat ze elkaar in de weg zitten.

Switch nog eens heen en weer om het te voelen:

git switch highscore-feature   # bestanden zijn terug
git switch master                # bestanden zijn weer weg

Stap 4: Samenvoegen met git merge

Je highscore-feature werkt. Tijd om hem terug in master te zetten. Dit heet mergen.

Zorg dat je op master staat:

git switch master

Voeg de branch samen:

git merge highscore-feature

Git toont iets als Updating a1b2c3d..e4f5g6h en Fast-forward. Je highscore-feature-commits zijn nu onderdeel van master. Controleer:

ls
git log --oneline

highscore.txt en highscore_manager.py staan nu op master. Alle commits van de feature-branch zijn opgenomen in de geschiedenis.

Stap 5: Wat zijn merge conflicts?

Stel: je hebt op master iets veranderd in highscore.txt, bijvoorbeeld “HIGHSCORE: 100” in plaats van “HIGHSCORE: 0”. En tegelijkertijd heb je op een andere branch highscore.txt ook veranderd, naar “HIGHSCORE: 500”.

Als je nu probeert te mergen, weet Git niet welke versie de juiste is. Dat is een merge conflict. Git vraagt jóu om te beslissen.

Laten we het expres uitlokken.

Op master:

echo "HIGHSCORE: 100" > highscore.txt
git add highscore.txt
git commit -m "Update highscore naar 100 op master"

Maak een nieuwe branch en verander daar hetzelfde bestand:

git switch -c andere-highscore
echo "HIGHSCORE: 500" > highscore.txt
git add highscore.txt
git commit -m "Update highscore naar 500"

Switch terug naar master en probeer te mergen:

git switch master
git merge andere-highscore

Git zegt: CONFLICT (content): Merge conflict in highscore.txt. Open highscore.txt in je editor. Je ziet:

<<<<<<< HEAD
HIGHSCORE: 100
=======
HIGHSCORE: 500
>>>>>>> andere-highscore

Dit zijn de twee versies. HEAD is jouw master-versie. Daaronder staat de versie van andere-highscore. Jij kiest welke je houdt, of je combineert ze.

Verwijder de markers en kies één versie:

HIGHSCORE: 500

Sla het bestand op. Vertel Git dat het conflict is opgelost:

git add highscore.txt
git commit -m "Merge: highscore van andere-highscore gekozen"

Conflict opgelost. Git kan weer verder.

Stap 6: Branches opruimen

Je feature is gemerged. De branch heb je niet meer nodig:

git branch -d highscore-feature
git branch -d andere-highscore

-d staat voor “delete”. Git weigert een branch te verwijderen die nog niet gemerged is: dat is een veiligheidsklep. Als je écht weg wil gooien zonder mergen, gebruik je -D (hoofdletter). Maar wees daar voorzichtig mee.

Wanneer wél een branch, wanneer niet?

Wél een branchGéén branch
Nieuwe feature die tijd kostTypo in een comment fixen
Experiment waarvan je niet weet of het werktKleine bugfix van één regel
Iets dat je werkende code kan brekenJe werkt alleen en je wijziging is duidelijk
Je werkt samen met anderen(bij solo-werk is master vaak genoeg)

Vuistregel: Als je twijfelt, maak een branch. Een branch kost niks. Code kwijtraken wel.

Tips om vlot te werken met branches

  1. Houd branches kort. Een branch van 3 uur is prima. Een branch van 3 weken wordt een merge-nachtmerrie: hoe langer je wacht met mergen, hoe meer er intussen op master verandert, en hoe groter de kans op conflicts.
  2. Eén ding per branch. “Highscore toevoegen” is een goede branch. “Highscore, menu, en nieuwe levels toevoegen” is te veel: split het op.
  3. Merge vaak. Werk je feature af, merge hem meteen terug naar master. Kleine, frequente merges zijn makkelijker dan één groot monster-merge.
  4. Geef branches duidelijke namen. highscore-feature is goed. test123 of branch2 zijn slecht. Over een week weet je niet meer wat er in test123 zat.
  5. Check waar je bent voor je begint. git branch of git status vertelt je op welke branch je staat. Maak hier een gewoonte van, zodat je voorkomt dat je per ongeluk op master code schrijft die eigenlijk op een feature-branch hoort.

Showcase

Laat aan een coach en een buddy zien:

  1. git branch met minstens twee branches (waaronder master).
  2. Op elke branch een ander bestand of andere code.
  3. Switch heen en weer: de bestanden verschijnen en verdwijnen.
  4. Een succesvolle merge van een feature-branch in master.

Tot de volgende keer!

“Tot nu toe leeft al je code alleen op jouw laptop. Volgende keer zetten we hem online. Je maakt een GitHub-account, pusht je repository naar het internet, en je game is overal ter wereld te bekijken. En: je kunt samenwerken met anderen. GitHub: je code de wereld in.”

Neem mee naar huis

  1. Makkelijk: Maak een branch voor een kleine feature in een bestaand project. Commit je werk en merge hem terug.
  2. Middel: Creëer expres een merge conflict (twee branches die hetzelfde bestand wijzigen) en los het op.
  3. Lastig: Werk met drie branches tegelijk op hetzelfde project. Merge ze één voor één terug in master. Check na elke merge of alles nog werkt.
  4. Erg lastig: Maak een branch, commit drie wijzigingen, switch terug naar master, maak daar óók een wijziging in hetzelfde bestand, en merge de branch. Los het conflict zorgvuldig op en check met git log --graph hoe de geschiedenis eruitziet.