Als ik kijk naar de adoptie van Git in de Microsoft Stack dan kan het niet anders dan concluderen dat de meeste bedrijven die ik bezoek inmiddels de overstap hebben gemaakt van TFS flow naar Git-based source control. In die overstap zijn er een hoop basisprincipes van Git die lastig zijn als je vanuit de TFS wereld naar Git kijkt. Ik wilde er graag eentje uitpikken waarvan ik merk dat men er mee worstelt en dat is de functionaliteit van merge versus die van rebase. Ik moet eerlijk zeggen dat er overigens bij teams verschillende strategieën leven ten opzichte van het gebruik van rebase, dus het is onvermijdelijk dat ik hier mijn voorkeur promoot.
Wat is rebase in vergelijking met een merge
Voordat ik verder in de details duik is het belangrijk om goed te begrijpen wat een rebase en een merge nu eigenlijk zijn. Hiervoor is het van belang om te begrijpen dat elke commit in git een setje aan veranderingen vertegenwoordigt ten opzichte van de commit ervoor:
In het voorbeeld hierboven is er een feature aangemaakt waarop een aantal commits zijn uitgevoerd. Bij het aanmaken van een feature branch, onthoudt git op basis van welke commit de feature gemaakt is en vervolgens wordt elke nieuwe commit daar aan vastgeknoopt.
Maar wat gebeurt er als in de tussentijd er ook wijzigingen zijn geweest op de master branch. Voordat de feature branch terug kan worden gebracht in de master branch (meestal met een pull request), wil je deze wijzigingen lokaal testen om te valideren dat er geen impact is op de wijzigingen die je zelf aan het maken bent.
Optie 1 voer een merge uit van de master naar je feature branch
Een veel gebruikte manier om deze wijzigingen te lokaal te verwerken, is door ze middels een merge naar je feature branch te halen. In dat geval maakt Git een merge-commit aan en komen de wijzigingen van de master terug in jouw eigen branch. Het nadeel van deze methode is dat de historie lastiger te lezen kan zijn vanwege de vele merge commits die op deze manier gedaan worden. Het voordeel is dat deze actie altijd veilig is, doordat bestaande branches en commits met rust worden gelaten.
Optie 2 voer een rebase uit van de master naar je feature branch
Een tweede manier om de wijzigingen van de master branch in je feature branch te krijgen, is met een rebase. In dit geval zal git je feature “oppakken” en de wijzigingen van de master voor je feature zetten. Het gevolg hiervan is dat de oude commits op de feature branch “stale” worden en dat er volledig nieuwe commits geschreven worden om de project historie te herschrijven. Het voordeel van deze manier van werken is een schonere historie in Git met minder merge-commits. Het belangrijkste nadeel is dat het herschrijven van de project historie een potentieel gevaarlijke actie is.
Risico bij het uitvoeren van een rebase
Zoals je in het bovenliggende plaatje ziet, zal een rebase je volledige branch “oppakken” en verplaatsen ten opzichte van de commits op de branch die je naar je feature rebaset. Maar stel dat je feature branch gepubliceerd is en dat er andere collega’s ook op werken. In dat geval is het werk wat beiden doen uit sync en is het heel lastig om dat weer recht te trekken. Gebruik daarom geen rebase op werk dat al naar een remote branch gepubliceerd is.
Wanneer gebruik je rebase en wanneer merge
Als je aan het werk bent aan een lokale feature die je wilt gaan afronden en in de tussentijd zijn er wijzigingen gedaan die je lokaal wilt verwerken, dan is een rebase een prima manier om deze wijzigingen te integreren. In de uiteindelijke historie geeft dat een mooier overzicht en omdat de wijzigingen toch enkel lokaal staan is er geen enkel risico. Is echter je branch gepubliceerd, dan is het niet verstandig een rebase uit te voeren en verwerk je eventuele wijzigingen met een merge.
Maar wat is nu een pull request?
Dan misschien nog als toetje op de pudding: wat is nu een pull request? Je hebt een feature gemaakt en het team geeft aan dat je deze feature na afloop met een pull request terug naar de master moet brengen. Eigenlijk is een pull request hierbij een speciaal soort merge waarbij een mechanisme in werking treedt dat ontwikkelaars ondersteunt om de wijzigingen eerst te beoordelen voordat de merge definitief wordt gemaakt. Dit is een mooie manier om de wijzigingen van een ontwikkelaar te laten peer reviewen door één of meerdere andere ontwikkelaars.