Hoofdstuk 8 · oefening
Lokaal samenwerken
Een branch bijwerken
Twee mensen kunnen bij dezelfde commit beginnen en daarna verschillende commits maken. Git noemt het resultaat divergentie: geen van beide branches bevat alles van de andere branch. Er is niet automatisch werk fout of verloren. De geschiedenissen moeten alleen worden samengebracht voordat de gedeelde branch vooruit kan.
Maak kennis met de drie repositories
Dit hoofdstuk blijft helemaal binnen één oefenwerkruimte:
/workspace/
├── shop/ your working repository
├── origin.git/ the bare repository used to exchange history
└── colleague/ an observation clone that must remain unchanged
De klaargezette repository shop staat al op main en zijn werkboom is schoon. Zijn lokale main heeft twee commits voor ontvangstbewijzen. Zijn remote-tracking ref origin/main registreert twee commits voor hoeveelheden die via colleague zijn binnengekomen. Beide lijnen beginnen bij dezelfde eerdere commit.
Begin met opdrachten die je al kent:
pwd
git status
Het statusrapport zegt dat main en origin/main uiteen zijn gelopen en geeft een ahead/behind-telling. “Ahead by 2”, twee voor, betekent dat de lokale main twee commits bereikt die origin/main niet bereikt. “Behind by 2”, twee achter, betekent dat origin/main twee commits bereikt die de lokale main niet bereikt. Die aantallen beschrijven bereikbaarheid tussen commitgeschiedenissen, geen score en geen aantal gewijzigde bestanden.
Vernieuw wat deze repository weet
De opdracht git fetch benadert de opgeslagen repository origin, haalt commits en refs op die hier ontbreken en werkt remote-tracking refs zoals origin/main bij. Die verplaatst de lokale main niet en verandert de werkboom niet. Voer haar uit voordat je een samenwerkingsbeslissing neemt, zodat je redeneert vanuit de nieuwste informatie die deze repository kan krijgen:
git fetch
git status
In deze deterministische werkruimte was origin/main al actueel, dus de telling blijft twee voor en twee achter. Ook dat ongewijzigde resultaat is nuttig bewijs: je hebt gecontroleerd in plaats van gegokt.
Vergelijk beide kanten van de splitsing
Met een geschiedenisbereik laat git log commits zien die bereikbaar zijn vanaf de ene naam maar niet vanaf de andere. In A..B is de naam rechts de kant die Git toont; commits die ook vanaf de naam links bereikbaar zijn worden uitgesloten. De optie --oneline toont elke passende commit als een verkort ID met onderwerp, zodat de twee korte lijsten gemakkelijker te vergelijken zijn. De eerste opdracht hieronder toont dus de commits van de collega die in de lokale main ontbreken; de tweede draait het bereik om en toont de lokale commits die in origin/main ontbreken:
git log --oneline main..origin/main
git log --oneline origin/main..main
Lees de onderwerpen voordat je integreert. De kant van de collega voegt het verwerken van hoeveelheden toe en documenteert dat. Jouw kant voegt ontvangstbewijsgedrag en een test toe. De wijzigingen zijn verschillend maar passen bij elkaar, dus beide horen in het resultaat.
Waarom de eerste push moet stoppen
git push vraagt de bare origin om zijn branch main naar jouw lokale main te verplaatsen. Op dit moment zou die stap de twee commits van de collega weggooien die alleen origin bereikt. Git wijst deze non-fast-forward-push af, omdat de gevraagde nieuwe tip de huidige remotetip niet bevat. Voer de gewone opdracht uit en lees de afwijzing:
git push
De afwijzing is bescherming, geen verzoek om de push te forceren. Herstel heeft drie stappen: kennis van de remote vernieuwen, de remote-tracking ref in de lokale branch integreren en vervolgens het geïntegreerde resultaat pushen. Je hebt al gefetcht en beide kanten bekeken, dus nu volgt integreren.
Integreer zonder een van beide kanten te verliezen
Je maakte in hoofdstuk 6 kennis met git merge. Hier betekent git merge origin/main: “breng de commitgeschiedenis die mijn remote-tracking ref benoemt in de branch waarop ik sta”. Omdat beide kanten unieke commits hebben, maakt Git een mergecommit met twee ouders. De optie -m geeft de melding rechtstreeks mee zodat er geen editor hoeft te openen. De beginsituatie is zo gemaakt dat deze merge zonder conflict eindigt:
git merge origin/main -m "Merge origin main"
git status
Na de merge meldt git status een schone werkboom en zegt dat de lokale main voorloopt op origin/main. Dat klopt: de geïntegreerde commit bestaat alleen in shop totdat de volgende les die pusht.
Een eerlijk woord over rebase
Je zult horen dat git rebase de andere manier is om te doen wat je net deed, en dat klopt. Een merge behoudt beide lijnen precies zoals ze ontstonden en voegt een commit toe die vastlegt waar ze samenkwamen. Een rebase kopieert jouw commits in plaats daarvan naar het einde van de andere lijn, met een rechter verloop en nieuwe identiteiten voor jouw commits.
Geen van beide is het enige juiste antwoord. Teams kiezen een gewoonte, vooral op basis van de vraag of het herschrijven van hun eigen commits veilig is en wat ze onderling hebben afgesproken. Deze cursus oefent merge, omdat die nooit een commit herschrijft die een collega al kan hebben en omdat het samenkomen daarna zichtbaar blijft. Kom je in een team dat rebase gebruikt, dan is alles vóór de integratiestap — fetchen en beide kanten lezen — hetzelfde.
Je eerste git push werd afgewezen. Wat beschermde Git?
git status zei dat main twee commits voor en twee achter liep. Wat beschrijft dat?
Beide werklijnen zitten nu in één geschiedenis en de mergecommit legt vast waar ze samenkwamen. Niemands werk is verkozen boven dat van een ander. Dat is de uitkomst die je wilt wanneer de andere lijn van iemand anders is.
Je repository loopt nu voor op de gedeelde repository. Dat verschil sluiten is de volgende les, en deze keer wordt de push geaccepteerd.