Git en GitHub – Merge Conflicts
Inleiding
Een versiebeheersysteem (VCS = Version Control System) biedt mogelijkheden voor het laten werken van meerdere mensen aan eenzelfde project.
De situatie kan zich echter voordoen dat je bezig bent met een bestand en tegelijkertijd met jou iemand anders ook met het bestand bezig is geweest.
Het versiebeheersysteem weet dan niet meer wiens wijzigingen uiteindelijk opgenomen moeten worden in de remote repository met een merge conflict als resultaat. In deze post zullen we het nader hebben over merge conflicts, wanneer ze precies optreden en hoe ze op te lossen.
We illustreren het één en ander aan de hand van dezelfde index.html uit de eerdere posts [Git en GitHub en Git en GitHub(2)] met ook nu weer Git en GitHub als versiebeheersystemen.
Merge Conflict
Een merge conflict ontstaat zodra je je wijzigingen wilt doorvoeren (push) in de remote repository en de uitgangssituatie van waaruit je je pull uit de remote repository hebt gedaan opeens is gewijzigd.
Dit omdat in de tussentijd iemand anders wijzigingen heeft doorgevoerd aan hetzelfde bestand op precies dezelfde plekken waarmee jij ook bezig bent geweest en de wijzigingen van die ander inmiddels zijn doorgevoerd in de remote repository.
We lichten het één en ander toe aan de hand van onderstaand voorbeeld.
> local group
Een gebruiker (laten we die local group noemen) trekt met een pull opdracht de gegevens uit de GitHub remote repository naar zijn/haar lokale Git repository.
In de GitHub remote repository staat op het moment van de pull opdracht in bestand Index.html de tekst:
De wereld is rond en draait om de zon en de zon maakt deel uit van de melkweg en de melkweg is één van de vele sterrenstelsels in het universum
en dat is de uitgangssituatie voor gebruiker local group.
> wappie
In de tussentijd doet een andere gebruiker (laten we die wappie noemen) ook een pull opdracht naar zijn/haar lokale Git repository. Gebruiker wappie voegt aan index.html (het bestand waar gebruiker localgroup ook mee bezig is) deze tekst toe:
De wereld is een computersimulatie waarin mensen nietsvermoedend gevangen worden gehouden door aliens met medeweten van de regering.
Gebruiker wappie doet niks met branches en pull requests en het brengt alle wijzigingen aan in de master branche en het pushes alles meteen terug naar de GitHub remote repository terwijl gebruiker localgroup nog bezig is met zijn/haar wijzigingen.
> conflict
Gebruiker localgroup doet wel aan branches en het pushes na de gedane arbeid zijn/haar branch naar de GitHub remote repository waarbij gebruiker localgroup deze tekst wil toevoegen aan index.html:
De melkweg maakt deel uit van de lokale groep en de lokale groep bestaat uit iets meer dan 40 sterrenstelsels waaronder de Andromedastelsel.
We willen na de push een pull request doen maar… GitHub ziet opeens de tekst van gebruiker wappie, een tekst waar gebruiker localgroup niet mee bekend is en die ook niet voorkwam in de uitgangssituatie voor gebruiker localgroup:
GitHub gaat niet voor jou kiezen welke tekst gebruikt gaat worden. We hebben dankzij gebruiker wappie een merge conflict !
Merge Conflict oplossen
We gaan voor het doen oplossen van de merge conflict uit van een scenario waarin we in GitHub alles oplossen bij de Pull Request. We zien dan in GitHub wat met elkaar conflicteert waarbij we een keuze maken in wat doorgevoerd mag worden en we datgene verwijderen wat niet doorgevoerd wordt.
We illustreren het één en ander aan de hand van dit bestand (index.html) dat voor beide gebruikers de uitgangssituatie is:
> wappie
Gebruiker wappie kloont de GitHub remote repository naar zijn/haar lokale Git repository:
git clone https://github.com/mrasoftGitHub/GitMRA.git .
Je kunt, eenmaal gekloond, in de toekomst een pull doen om je lokale Git repository gesynchroniseerd te krijgen met een bijgewerkte GitHub remote repository.
wappie doet onderstaand met bestand index.html. Twee regels worden ingevoegd met de regels 13 en 14 als resultaat:
en het pushes alles meteen terug naar de GitHub remote repository:
git commit -a -m "<wappie tekst>"
git push origin master
> local group
Gebruiker local group doet onderstaand met bestand index.html in branche localgroup. Gebruiker local group voegt ook twee regels in en ook hier hebben we de regels 13 en 14:
en het pushes branche localgroup naar de GitHub remote repository:
git commit -a -m "<localgroup tekst>"
git push origin localgroup
> resolve
Gebruiker localgroup wil een pull request doen om de wijzigingen in branche localgroup op te nemen in hoofdbranche master en GitHub constateert dat het samenvoegen niet kan.
Geruststellend geeft GitHub aan dat de creatie van de pull request geen probleem is (graag zelfs want jij mag van GitHub de merge conflict in die pull request oplossen).
We geven eventueel nog een toelichting “Wat is er nu weer gebeurd dat we opeens een merge conflict hebben?” (sukkels, waarom werken jullie zo langs elkaar heen, ga met elkaar in conclaaf en los het op!):
We gebruiken de web editor van GitHub om conflicts te resolven:
En GitHub toont wat met elkaar conflicteert. We zien wat gebruiker wappie heeft gedaan (en heeft doorgevoerd in branche master) en we zien wat gebruiker local group heeft gedaan (en heeft doorgevoerd in branche localgroup). We moeten een keuze maken in wat we willen opnemen in hoofdbranche master:
Helaas voor wappie, ingefluisterd door de aliens hechten we toch meer waarde aan de bevindingen van gebruiker local group en de waarnemingen van ruimtetelescoop Hubble (en andere ruimtetelescopen) dan aan een vage, niet te bewijzen complottheorie. We verwijderen de tekst van gebruiker wappie en we markeren het geheel as resolved:
We committen de merge:
We do Merge the pull request (wat nu wel lukt omdat we wappie’s conflicterende tekst hebben weggehaald):
We bevestigen nogmaals de merge:
En hoofdbranche master is bijgewerkt. We kunnen in GitHub de merge conflict bekijken en de tekst van gebruiker wappie heeft een rode kleur wat inhoudt dat we voor het bijwerken van de hoofdbranche niet gekozen hebben voor de opvattingen van gebruiker wappie:
We hebben in het voorbeeld hierboven ervoor gekozen om alles op te lossen via de web editor van GitHub, maar een ander scenario is dat gebruiker local group kiest voor het doen samenvoegen van hoofdbranche master met sub branche localgroup op de lokale PC en vanuit de lokale PC de merge conflict oplost.
Deze Git-commando’s kunnen gebruikt worden voor het doen overhalen van de inhoud van branche master uit de remote repository naar branche localgroup op de lokale PC:
# ga naar branch localgroup
git switch localgroup
# haal de inhoud van branch master uit
# de remote repository
# over naar de branche
# waar je momenteel in zit (localgroup)
git pull origin master
Bij het overhalen verschijnt een melding dat er een merge conflict is: (CONFLICT (content) : Merge conflict in index.html, Automatic merge failed; fix conflicts and then commit the result).
Je kunt vervolgens de conflicterende tekst weghalen met je lokale editor. Na het opslaan doe je weer een push naar de GitHub remote repository:
# werk de local git repository bij
# (zonder de conflicterende teksten)
git commit -a -m "<tekst>"
# zet branch localgroup over
# naar de remote repository
git push origin localgroup
En in GitHub is voor de desbetreffende pull request door het voorgaande een automatic merge weer mogelijk. De pull request kan verder zonder problemen uitgevoerd worden.
Slot
Een VCS (Version Control System) met een remote repository biedt mogelijkheden voor het doen delen van je werk met anderen en het laten werken van meerdere mensen aan eenzelfde project.
Het kan echter voorkomen dat twee mensen tegelijkertijd bezig zijn met eenzelfde bestand en op precies dezelfde plekken in dat bestand wijzigingen aanbrengen. Versiebeheersystemen zoals Git en GitHub weten dan niet meer wiens wijzigingen overgenomen moeten worden en je krijgt een Merge Conflict.
Deze post begon met een uiteenzetting over wanneer een merge conflict precies optreedt. We hebben ter illustratie een scenario aangehaald waarin de index.html uit de eerdere posts [Git en GitHub en Git en GitHub(2)] parallel door twee personen wordt bijgewerkt en de tweede persoon wordt geconfronteerd met een merge conflict.
Een merge conflict kan opgelost worden in GitHub bij de Pull Request waarbij gebruik gemaakt wordt van de web editor van GitHub en dat hebben we in deze post laten zien.
We zijn in deze post ook kort ingegaan op een scenario dat de gebruiker die geconfronteerd wordt met een merge conflict kiest voor het doen samenvoegen van de hoofdbranche master met zijn/haar sub branche op zijn/haar lokale PC en vanuit de lokale PC de merge conflict oplost in de remote repository.
Hopelijk ben je met deze posting weer wat wijzer geworden en ik hoop je weer terug te zien in één van mijn volgende blog posts. Klik op de Home-button om te zien wat ik nog meer geschreven heb…