Git: Masterclass
Aug 23 2023
Wat is git
?
Waarom werken met git
?
Git is een versiecontrole systeem uitgevonden door Linus Torvalds. Hij had een betere manier nodig waarmee er samen gewerkt kon worden aan een project. Zo'n samenwerking gaat vaak heel goed tot het misloopt en dan draait het helemaal de soep in. Vooral in ontwikkeling waar ontwikkelaars elkaar zelden in het echt zien en iedereen aan eigen stukjes code werkt. Soms overlappen die aanpassingen en doen die andere wijzigingen te niet. Dergelijke conflicten kunnen met git elegant opgelost worden.
Daarnaast wordt er van alles een checksum bijgehouden. Een cryptografische berekening van ieder bestand die altijd hetzelfde moet zijn. Dit biedt als voordeel dat git
steeds de integriteit van de bestanden kan garanderen.
Tot slot werkt git
volledig op jouw toestel. Je kan alles op jouw toestel aanpassen, opslaan en dan "comitten". Ben jij klaar met werken of wil je een tussentijdse backup maken, kan je jouw opgeslagen wijzigingen meteen "pushen" naar een andere repository
. Dat kan een service zijn zoals Gitlab maar ook gerust een andere computer, server en dergelijke.
Wat met tools Gitlab, Github en Bitbucket?
Deze webapplicaties werken onderliggend met git
. Ze bieden eigenlijk een repository
aan waar individuen, groepen of organisaties hun code op een stukje van de server beschikbaar kunnen maken aan iedereen die zij zelf kiezen. Daarrond hebben ze dan een grafische omgeving gebouwd waar je tegenwoordig ook extra features kan genieten. De meeste tools bieden ook een issue tracking aan of mijlpalen om vooruitgang in een project bij te houden. Sommige tools bieden ook tools aan om applicaties automatisch uit te rollen zodat ontwikkeling, testing en tot slot uitrol naar productie heel vlot kan gebeuren. Waar het echt gek wordt is als je een volledige Web IDE kan gebruiken om vanop ieder toestel aanpassingen te kunnen doen aan jouw code.
De basis
Hoe werk je met git
?
Als git
geïnstalleerd is op jouw toestel kan je meteen van start gaan. Anders moet je het nog even installeren. Op RedHat
, Fedora
en aanverwanten, kan je git
installeren door middel van dnf (dnf install git
). Voor Windows kan je best een installer downloaden en op MacOS gebruik je best Homebrew (brew install git
).
Met git
in jouw PATH
na installatie (Dat gebeurt normaal automatisch), kan je een nieuwe repo starten door in de terminal naar een map te gaan en daar volgende in te typen:
git init
Er is nu een map aangemaakt in jouw map genaamd .git
. Deze zal alle wijzigingen bijhouden. Verwijder deze niet en best doe je ook geen aanpassingen in deze map. Daarvoor gaan we commando's gebruiken.
Git
werkt met branches. Standaard start je met de master
-branch. Die naam is niet altijd interessant dus die gaan we meteen hernoemen naar iets passelijker en inclusiever; main
git branch -m main
Configuratie
Voor we echt wijzigingen gaan doen is het goed om even stil te staan bij de configuratie. Git
is zo'n sterke tool omdat je duidelijk kan maken wie welke wijzigingen gemaakt heeft. Dit zorgt voor een betere opvolging en kan dus ook zorgen voor een betere projectwerking. Om aan te geven wie jij bent, kan je dat meegeven aan git.
# Geef jouw Naam en e-mailadres op.
# Dit moet je maar eenmalig doen door de --global flag
git config --global user.name "Jouw Naam"
git config --global user.email "jouw@email-adr.es"
Je kan jouw code ook automatisch laten
signen
met GPG. Door zo'n digitale handtekening weet iedereen zeker dat deze wijziging effectief van jou komt en niet iemand anders dat in jouw naam gedaan heeft. Dit kan je zo activeren:
# Maak een GPG-key aan als je deze nog niet hebt.
# Na onderstaand commando moet je een paar vragen beantwoorden.
gpg --gen-key
# Zoek dan de key id. Die staat op de pub regel
# achter de eerste /
gpg --list-keys
# Daarna kan je jouw key doorgeven aan git
git config --global user.signingkey <Jouw GPG-key>
# In plaats van --global kan je ook enkel voor dit project signing gebruiken
git config --local commit.gpgsign true
Sla je werk op!
Nu moeten we een eerste bestand toevoegen vooraleer we echt met git
kunnen werken. Kies hier voor een README
-bestand. Dit wordt door git
en vooral de git
-tools automatisch opgepikt zodat je hier eenvoudig een korte omschrijving van jouw project kan geven. Vaak wordt hier ook instructies gelaten over hoe het project gebruikt moet worden of hoe een installatie werkt. Als we het bestand hebben aangemaakt en aangevuld, kunnen we het toevoegen aan git
en kunnen we onze eerste commit
maken om zo ons git
-avontuur echt te starten. Met de add
brengen we het bestand in de radar van git
en met de commit
maken we de checksum aan. Git kan nu perfect zien welke bestanden aangepast zijn. Probeer met de commit altijd kort en bondig aan te geven welke wijzigingen je gemaakt hebt door middel van de -m
flag. Dat helpt achteraf met problemen oplossen.
# Maak eerst het bestand aan.
touch README
# Vul dat nu met gegevens dmv onze favoriete editor
# Denk eraan dat je met :wq er uit kan door op te slaan
nvim README
# Nu voegen we het bestand toe aan git.
git add README
# En tot slot een commit
git commit -m "Eerste commit met README"
Als er bestanden of mappne zijn die niet opgenomen mogen worden in git, kan je die best zo vroeg mogelijk uit git houden. Dit doe je door het pad of bestandsnaam in
.gitignore
toe te voegen. Dit bestand ga je uiteraard wel toevoegen aan jouw git repo.
Het is de bedoeling dat productie gegevens steeds in de main
-branch zullen zitten. Niemand zou rechstreeks aanpassingen hierin mogen doen buiten de initiële commit
. In de plaats daarvan maakt iedereen een eigen branch aan. Hierin kan je dan aanpassingen doorvoeren, testen en als het goed bevonden is voeren we daarna de wijzigingen door naar de main branch. Dat gaat als volgt:
# Maak een nieuwe branch aan
git branch newfeature
# Maak een nieuw bestand aan en vul aan.
nvim myWebApp.js
# Nu voegen we het bestand toe aan git...
git add myWebApp.js
# en committen we de wijziging.
git commit -m "myWebApp.js toegevoegd"
Nog enkele belangrijke bestanden
Naast het README
bestand, zijn er nog enkele speciale bestanden waarvan je best op de hoogte bent. Niet alle projecten doen alle bestanden. Velen hebben meteen alle informatie in hun README
staan. Hieronder vind je de meest belangrijke bestanden.
- README: De basis info van een project. Vaak ook hoe je het project kan gebruiken of in gebruik kan nemen. Online tools gaan de
Markdown
in deze bestanden automatisch tonen. - LICENSE: Dit gaat over de rechten, ristricties en juridische fancy talk betreffende het project.
- CHANGELOG: Optioneel kan je hier in grote versienummers bijhouden welke grote veranderingen er zijn gebeurt.
- AUTHORS: De belangrijkste mensen die meewerken aan jouw project kan je hier extra in de kijker zetten. Vaak worden hier de medewerkers in loondienst ook toegevoegd.
- SUPPORT: Als iemand een issue in Gitlab of Github wilt aanmaken, kan je hier instructies meegeven over waar ze zeker rekening moeten houden alvorens hun issue in te sturen.
- SECURITY: Voornamelijk als er een kwetsbaarheid gevonden wordt, geef je hier aan hoe gebruikers dat best aan jou doorgeven. Daarnaast kan je ook versies van verschillende onderdelen hier uitschrijven.
- CODE_OF_CONDUCT: In de laatste jaren is dat vooral populair geworden. Je moet namelijk niet alleen samenwerken maar ook op een respectvolle manier. Maak in dit document duidelijk wat dat voor jouw project betekent.
- CONTRIBUTING: Als iemand nieuw wilt starten aan jouw project, vindt die hier hoe die kan helpen.
- ACKNOWLEDGEMENTS: Refereer hierin naar andere projecten die relevant zijn voor jouw project om die ook even extra in de kijker te zetten.
- CODEOWNERS: Wie heeft eigendom over de code
- FUNDING.yml: Hoe kunnen gebruikers jou financieel steunen
- ISSUE_TEMPLATE: Een template om een issue aan te maken.
- PULL_REQUEST_TEMPLATE: Een template om een
merge
aan te vragen
Hoe krijg ik mijn project nu gedeeld?
Als je een project aanmaakt in een online tool zoals Gitlab of Github, krijg je de vraag om ook het project te initialiseren. Doe dat enkel als je nog geen lokaal project hebt. Anders hou je het project best leeg. Hierna ga je ongetwijfeld ook de instructies van die site krijgen over hoe je jouw wijzigingen online krijgt. In grote lijnen is dat meestal zo:
# Je gaat de externe locatie definiëren
git remote add origin git@gitlab.com:eliwinderickx/backuptest.git
# Bij iedere eerste push per branch ga je misschien
# moeten meegeven naar waar de push moet gebeuren
git push --set-upstream origin main
# Daarna kan je na iedere commit een push doen
# om de commit ook online beschikbaar te maken.
git push
Wat ben ik nu aan het doen?
Je kan op ieder moment de status opvragen om zo te zien welke bestanden je hebt toegevoegd aan git
, welke je hebt aangepast of misschien zelfs verwijderd. Als je commit
hebt, kan je ook zien dat je op een propere branch aan het werken bent. Dat wil zeggen dat binnen jouw lokale git
-repo alles veilig opgeslagen is.
Commit wilt niet zeggen dat je wijzigingen opgeslagen zijn in een externe
git
-repo zoals Gitlab of Github.
De status vraag je zo op:
git status
Naast de status van de huidige branch, kan je ook een oplijsting vragen van alle branches die je lokaal beschikbaar hebt.
git branch --list
# Wil je dat visueler zien met welke branch van waar komt?
git log --all --graph --decorate --oneline --simplify-by-decoration
Nog een leuke feature is zien wie de laatste commits in een bestand gedaan heeft
git blame <bestand>
Ik ben klaar, wat nu?
Stel de feature waaraan je gewerkt hebt is klaar. Je hebt een hele reeks nieuwe aanpassingen gemaakt, alles is getest en nu wil je jouw wijzigingen naar productie brengen. Dat doe je door die wijzigingen naar de hoofd branch te brengen. In ons verhaal hierboven hebben we die main
genoemd. Om die wijzigingen nu naar de main
-branch te krijgen moeten we een merge
doen. In tools zoals Github of Gitlab kunnen we een merge request
maken. Dit nodigd dan andere gebruikers uit om de nieuwe wijzigingen te controleren en zelf ook uit te testen alvorens dit naar de productie branch gaat. Binnen de git
-applicatie kunnen we ook verscheidene soorten merge
's doen. Hier houden we het voorlopig nog even simpel.
# Eerst gaan we naar de branch die de wijzigingen moet ontvangen
git checkout main
# Daarna kunnen we de wijzigingen binnenhalen.
git merge newfeature
De wijzigingen zitten nu zowel in de main
als in de newfeature
branch. Afhankelijk van hoe je met het project omgaat, ga je misschien nu de newfeature
branch willen verwijderen. In sommige projecten moet er per unieke feature een aparte branch gemaakt worden. Deze wordt dan na succesvol toevoegen van die feature verwijderd. Grotere projecten kunnen ervoor kiezen om onder de main
branch ook nog type wijzigingen als branch te vertegenwoordigen; Taal, GUI en gelijkaardige grotere branches zullen niet verwijderd worden na de merge. Hierbinnen wordt verder gewerkt aan de volgende features.
# Om een branch te verwijderen, kan je zo doen
git branch -d newFeature
Samenwerken is niet zonder problemen
Iemand anders brengt wijzigingen naar productie
Jij bent nog aan het werken aan features in jouw eigen branch maar ondertussen heeft iemand anders al wijzigingen gemerged met de main
branch. Om problemen te vermijden, kan je nu best een rebase
doen. Dit vertaalt bij letterlijk naar vervang de basis van waar ik gestart ben door wat er in een andere branch zit. Daarbovenop kunnen we dan onze wijzigingen doen.
Als je hier wilt meevolgen, maak dan even een nieuwe branch aangenaamt
newFeature2
. Daarna kan je in jouwmain
-branch een nieuw bestand aanmaken en een commit uitvoeren.
# Ga naar de branch die de wijzigingen moet ontvangen
git checkout newFeature2
# Hier ontvangen we de nieuwe basis vanuit main
git rebase main
Bovenstaande lukt enkel als de wijzigingen in andere bestanden gebeuren. Als je dezelfde bestanden wijzigd, kom je in het vaarwater van de
stash
en hetmerge conflict
.
De stash
Wil je een rebase doen maar ben je indezelfde bestanden aan het werken? Dan kan je een stash
doen. Hiermee zet je jouw wijzigingen even aan de kant om de nieuwe code of wijzigingen binnen te halen. Als dat gedaan is kan je jouw wijzigingen terughalen.
# zet jouw wijzigingen even aan de kant.
# Je draait zo even alle wijzigingen terug tot de laatste commit
git stash
# Nu kan je de rebase doen
git rebase main
# Tot slot kan je jouw wijzigingen uit stash halen
# en opnieuw uitvoeren
git stash apply
Het merge conflict
Als je bestanden aan het wijzigen was die achter jouw rug ook al gewijzigd waren, krijg je een merge conflict. Git
kan namelijk niet in jouw plaats kiezen welke wijziging belangrijker is dan de andere. Jij gaat nu die keuze moeten maken om dit op te lossen. Voortbouwend op het scenario bij stash
hebben we net onze stash opnieuw toegepast. We waren helaas aanpassingen aan het doen in een bestand dat in een eerdere merge in de main
branch ook al wijzigingen kreeg. We hebben nu een merge conflict
. Dit merken we door twee zaken:
- de output van ons laatste commando geeft het ons mee:
CONFLICT (content): Merge conflict in <bestandsnaam>
alsook - in het bestand zelf. Hieronder een voorbeeld van hoe zo'n bestand eruit kan zien.
Oorspronkelijke code
<Iemand anders wijzigingen>
<Jouw wijzigingen>
De gemakkelijkste manier van werken is nu beide blokken code lezen:
- vanaf <<<<<<< tot =======
- vanaf ======= tot >>>>>>>
Hierna kan je dan beide blokken vervangen door één blok die ofwel beide codes zal bevatten of misschien bepaalde stukken zal aanpassen. Dit zal afhangen van zowel de code die er stond alsook de code die jij aan het schrijven was.
Achteraf moet je het bestand opnieuw toevoegen aan git en kan je een commit uitvoeren om de merge helemaal rond te krijgen.
git add <conflictbestand>
git commit -m "Conflict opgelost!"
Proficiat!
Als je goed meegevolgd hebt, snap je nu hoe git werkt. Er zijn nog scenario's die we niet overlopen hebben. Die komen vaak minder voor maar kan je zeker wel terugvinden in de officiele Git documentatie. Lees die dus zeker na voor je problemen hebt!