---
config:
theme: 'base'
---
gitGraph
commit id: "d8d6683"
commit id: "18152d6"
commit id: "0a17da5"
commit id: "22b1b17"
branch cool-feature
checkout cool-feature
commit id: "24e6e1a"
checkout main
branch another-feature
checkout another-feature
commit id: "19f7b7a" tag: "another-feature"
checkout main
merge cool-feature tag: "HEAD" tag: "main" tag: "cool-feature"
Les 3: Samenwerken met Git en GitHub
Inleiding
Les doelen
In deze les bekijken we volgende punten:
- Lokale wijzigingen pushen en pullen naar een gedeelde GitHub repo.
- Samenwerken op dezelfde branch, mergen en conflicten oplossen.
- Werken met feature branches en Pull Requests binnen één repository.
Herhaling
Quiz
- Wat doet git add?
- Wat is het verschil tussen commit en push?
- Wat is er een remote?
- Wat zijn de 4 verschillende “states” waarin een bestand zich kan bevinden?
Commandos
Deze commandos uit de vorige lessen heb je vandaag nodig:
git status |
Informatie over huidige staat van de directory/repo. Belangrijkste commando. Vertelt meestal wat je moet of kan doen. |
git add <filename> |
Bestand(en) stagen.git add . : Stage alle aangepaste en nieuwe bestanden. |
git commit |
Commit alles wat gestaged is. Maakt een permanente nieuwe “versie”.git commit -m "message" : Geeft direct een commit message mee.git commit -a : Commit rechtstreeks alle aangepaste bestanden. |
git log [filename] |
Commit geschiedenis bekijken. Van nieuw naar oud. filename optie.git log --oneline : Compacte output. Één lijn per commit.git log --stat : Statistieken over aanpassingen in de commit.git log -p : Ook volledige diff (patch) van elke commit. |
git diff [filename] |
Toont aanpassingen t.o.v. laatste commit.git diff commit1..commit2 : Toont aanpassingen tussen commit 1 en 2. |
git show [commit_id] |
Toont alle informatie, inclusief diff, van één commit.git restore --staged : Reeds gestagede veranderingen herstellen. |
git clone [remote] |
Maakt een lokale kopie van een remote repo. Niet in repo uitvoeren. |
git remote -v |
Lijst met alle gekende remotes |
git push |
Stuur nieuwe commits op huidige branch naar remote. |
git fetch |
Download nieuwe commits vanaf remote. Update lokale branch niet. |
git pull [filename] |
Fetch + update (merge) in lokale branch. |
Git lifecycle
GitHub
- Git is gedistribueert. Elke clone bevat de volledige repo.
- Remote = Een andere repo, in principe op server zoals GitHub.
- Enkel
clone,pushenfetch/pullmaken contact met een remote.
Commit Tree en Mergen
Fast-Forward Merge
True (3-Way) Merge
---
config:
theme: 'base'
---
gitGraph
commit id: "d8d6683"
commit id: "18152d6"
commit id: "0a17da5"
commit id: "22b1b17"
commit id: "24e6e1a"
branch another-feature
checkout another-feature
commit id: "19f7b7a" tag: "another-feature"
checkout main
commit id: "7c13567"
merge another-feature tag: "HEAD" tag: "main"
GitHub Desktop
Tot nu toe werkten we enkel met git CLI commandos. Dit blijft de beste manier om goed inzicht te krijgen in de onderliggende concepten en werking van Git. In veel gevallen
Soms kan het toch handig zijn een ander perspectief te krijgen, als ook een visueel overzicht. Er bestaan verschillende applicaties (en plugins voor IDEs als VSCode en PyCharm) die boven op Git bouwen.
Als alternatief voor de git CLI bekijken we kort GitHub Desktop. We kiezen voor GitHub Desktop omdat deze beschikbaar is voor alle platformen en natuurlijk volledig geïntegreerd is met GitHub (bvb voor authenticatie).
Installatie en Configuratie
Installeer GitHub Desktop via https://desktop.github.com/download/.
GitHub Website
Ook rechtstreeks via de GitHub website kan je wijzigingen maken en committen! Dit is op zich niet aan te raden maar kan soms handig zijn om snel een triviale wijziging (bvb. in een README bestand) te maken, of om een wijziging te maken die je vervolgens als test probeert te pullen in je lokale clone.
Oefening
Oefening 1:
- Gebruik GitHub Desktop om je eigen test repo uit les 2 (bvb
hello) te clonen. - Bekijk de commit history en veranderingen.
- Open via GitHub Desktop de repo in je IDE (VSCode, …).
- Maak een eenvoudige wijziging in een van de bestanden en voeg ook een nieuw bestand toe.
- Open een terminal en gebruik de Git CLI voor de volgende stappen:
- Bekijk de status.
- Stage het nieuwe en gewijzigde bestand.
- Commit de wijzigingen.
- Bekijk op nieuw de status.
- Bekijk de commit geschiedenis.
- Bekijk de status en nieuwe commit in GitHub Desktop
- Push de nieuwe commit met GitHub Desktop en bekijk het resultaat op de website.
Oefening 2:
- Gebruik de GitHub website om een eenvoudige wijziging te maken en te committen.
- Fetch/Pull de nieuw commit met GitHub Desktop.
- Bekijk de commit history en veranderingen.
- Gebruik Git CLI commando’s in je IDE/Terminal om:
- Bekijk de status.
- Bekijk de commit geschiedenis.
Samenwerken
In Remotes hebben we de basisconcepten van remotes bekeken.
Je lokale repo bevat een kopie van de remote(s) zoals die was op het moment van de laatste fetch (of op het moment van de initiële clone). Als je samenwerkt met verschillende ontwikkelaars kan het natuurlijke gebeuren dat iemand anders de remote wijzigt (push) sinds jou laatste fetch.
Basis
Bob en Alice werken samen aan een nieuwe feature. Hiervoor hebben ze een aparte branch aangemaakt (new-feat) en naar de gemeenschappelijke Git server gepusht. De start situatie voor Bob ziet er als volgt uit (andere branches zoals main worden gemakshalve niet weergegeven):
Waarom zouden Bob en Alice niet gewoon rechtstreeks op de main branch werken?
De main branch wordt altijd gezien als de stabiele en “officiële” versie van de code. Die code moet altijd functioneel zijn en vormt ook de basis waaruit alle ontwikkelaars werken. Het is dus erg belangrijk dat de main branch stabiel blijft.
Door op aparte branches te werken kan nieuwe code ook eerst nagekeken (review) worden door andere ontwikkelaars. Als alles OK is kan zo een branch in de main branch gemergd worden.
Meestal hebben slechts een beperkt aantal ontwikkelaars de nodig rechten om mergen in (laat staan om rechtstreeks te pushen naar) main.
Bob
In Bobs lokale repo heeft hij natuurlijk een new-feat branch. Dit is een lokale branch waar Bob rechtstreeks in kan werken.
Bob heeft een een lokale representatie van de new-feat branch zoals die bestaat in de remote. Dit is een remote branch. Remote branches hebben altijd een naam in de vorm <remote-name>/<branch-name>. In dit geval dus origin/new-feat.
Als Bob iets commit in zijn lokale new-feat branch zal er niets veranderen in zijn origin/new-feat branch.
Met het git branch -a (-a voor all) krijgen we zowel de lokale als de remote branches te zien. Het * teken geeft aan op welke lokale branch we momenteel zitten.
$ git branch -a
main
* new-feat
remotes/origin/HEAD -> origin/main
remotes/origin/main
remotes/origin/new-featMet git status krijgen we informatie over de verhouding tussen de (huidige) lokale branch en een eventuele remote branch.
$ git status
On branch new-feat
Your branch is up to date with 'origin/new-feat'.
nothing to commit, working tree cleanDe lokale new-feat branch is gelinkt met de remote origin/new-feat branch. We zeggen dat new-feat origin/new-feat trackt (tracking). We zien ook dat de lokale new-feat up to date is met de remote origin/new-feat.
Let op: bij het uitvoeren van git status (en de meeste andere git commandos) wordt er geen contact gemaakt met de server. De lokale new-feat is dus up to date met origin/new-feat zoals die bestond op het moment van de laatste git fetch!
Met git remote show krijgen we nog meer informatie over één bepaalde remote.
$ git remote show origin
* remote origin
Fetch URL: https://github.com/dvx76/git-demo.git
Push URL: https://github.com/dvx76/git-demo.git
HEAD branch: main
Remote branches:
main tracked
new-feat tracked
Local branches configured for 'git pull':
main merges with remote main
new-feat merges with remote new-feat
Local refs configured for 'git push':
main pushes to main (up to date)
new-feat pushes to new-feat (up to date)Alice
Bobs collega, Alice, heeft ook een lokale clone van dezelfde repo. Alice vindt de benaming origin niet zo duidelijk en heeft de remote hernoemt naar server.
Alice commit iets op haar lokale new-feat branch. Hierdoor komt haar lokale new-feat voor de staan (ahead) op de remote server/new-feat. Een git status vertelt Alice het volgende:
git status
On branch new-feat
Your branch is ahead of 'server/new-feat' by 1 commit.
(use "git push" to publish your local commits)
nothing to commit, working tree cleannew-feat is dus 1 commit ahead op de remote.
Met git push update Alice de remote.
Bob moet fetchen
Bob loopt nu eigenlijk achter op de server, maar weet het nog niet. Vanuit zijn standpunt is hij nog perfect up to date! Met het git fetch commando wordt zijn lokale representatie van de remote geüpdate.
Met git fetch is enkel origin/new-feat lokaal geüpdate! De lokale new-feat branch is (nog) niet aangepast en verwijst nog steeds naar dezelfde commit. Zoals gewoonlijk geeft git status alle informatie die we nodig hebben:
$ git status
On branch new-feat
Your branch is behind 'origin/new-feat' by 1 commit, and can be fast-forwarded.
(use "git pull" to update your local branch)
nothing to commit, working tree clean- Bob’s lokale branch zit 1 commit achter (behind) op de remote
- Hij kan fast-forwarden, omdat hij zelf geen nieuwe commits op
new-featheeft - Met
git pull(ofgit merge) update hij de lokale branch
Oefening
Vorm groepen van twee en kies wie Alice en Bob is
- Clone de repo https://github.com/dvx76/git-demo.git
- Switch naar the branch
team-1voor groep 1, … - Alice maakt een aanpassing aan een bestand en commit dit
- Alice pusht naar de remote
- Bob fetcht van de remote
- Bob update de lokale branch
- Bob maakt een aanpassing aan een bestand en commit dit
- Bob pusht naar de remote
- Alice update de lokale branch
Wat zal er gebeuren als Bob en Alice “tegelijk” een nieuw commit proberen pushen?
Mergen
Tot nu toe was het voor Bob erg eenvoudig om de commit(s) van Alice op zijn eigen lokale branch te krijgen. Hij had namelijk zelf nog niets gecommit op diezelfde branch!
In de praktijk gaan dit zelden zo gemakkelijk. Bob zit natuurlijk niet te wachten op Alice en heeft zelf al een of meer commits op zijn lokale new-feat branch staan.
Opnieuw heeft Alice haar nieuwe commit al gepusht naar de server. Bob heeft ondertussen op zijn lokale branch 2 commits toegevoegd.
---
config:
theme: 'base'
gitGraph:
mainBranchName: 'Alice'
---
gitGraph
commit id: "22b1b17"
commit id: "629f30e"
commit id: "4c62d28" tag: "HEAD" tag: "new-feat" tag: "server/new-feat"
---
config:
theme: 'base'
gitGraph:
mainBranchName: 'Server'
---
gitGraph
commit id: "22b1b17"
commit id: "629f30e"
commit id: "4c62d28" tag: "HEAD" tag: "new-feat"
---
config:
theme: 'base'
gitGraph:
mainBranchName: 'Bob'
---
gitGraph
commit id: "22b1b17"
commit id: "629f30e" tag: "origin/new-feat"
commit id: "9cfcf72"
commit id: "5cc2948" tag: "HEAD" tag: "new-feat"
Bob probeert te pushen
Bob is tevreden met zijn commits en wil ze naar de server pushen. Hij krijgt de volgende foutmelding:
$ git push
To https://github.com/dvx76/git-demo.git
! [rejected] new-feat -> new-feat (non-fast-forward)
error: failed to push some refs to 'https://github.com/dvx76/git-demo.git'
hint: Updates were rejected because the tip of your current branch is behind
hint: its remote counterpart. If you want to integrate the remote changes,
hint: use 'git pull' before pushing again.
hint: See the 'Note about fast-forwards' in 'git push --help' for details.The tip of your current branch is behind its remote counterpart. Git merkt dat Bob’s lokale branch achterloopt op de remote. Daardoor kan Bob niet pushen want anders zou de commit van Alice verloren gaan. Bob moet dus zijn lokale branch eerst updated met git pull.
Maar helaas:
$ git pull
remote: Enumerating objects: 5, done.
remote: Counting objects: 100% (5/5), done.
remote: Compressing objects: 100% (3/3), done.
remote: Total 3 (delta 0), reused 3 (delta 0), pack-reused 0 (from 0)
Unpacking objects: 100% (3/3), 1.00 KiB | 513.00 KiB/s, done.
From https://github.com/dvx76/git-demo
629f30e..4c62d28 new-feat -> origin/new-feat
hint: Diverging branches can't be fast-forwarded, you need to either:
hint:
hint: git merge --no-ff
hint:
hint: or:
hint:
hint: git rebase
hint:
hint: Disable this message with "git config set advice.diverging false"Diverging branches can’t be fast-forwarded. Git kan niet automatisch de nieuw commits uit de remote op Bob’s lokale branch overzetten omdat zijn eigen commits in de weg staan.
De situatie ziet er ongeveer als volgt uit:
---
config:
theme: 'base'
gitGraph:
mainBranchName: 'origin/new-feat'
---
gitGraph
commit id: "22b1b17"
commit id: "629f30e"
branch new-feat
commit id: "9cfcf72"
commit id: "5cc2948"
checkout origin/new-feat
commit id: "4c62d28"
De foutmelding van het git pull commando geeft ook twee mogelijke opties:
git merge, ofgit rebase
Merge
Mergen (three-way merge, zonder fast-forward) kennen we al. Bij het git merge commando stelt Git automatisch de commit message “Merge remote-tracking branch 'refs/remotes/origin/new-feat' into new-feat” voor die we gewoon kunnen aanvaarden.
$ git merge
Merge made by the 'ort' strategy.
hello.py | 7 +++++--
1 file changed, 5 insertions(+), 2 deletions(-)
$ git status
On branch new-feat
Your branch is ahead of 'origin/new-feat' by 3 commits.
(use "git push" to publish your local commits)
nothing to commit, working tree clean
$ git log --oneline
9c72952 (HEAD -> new-feat) Merge remote-tracking branch 'refs/remotes/origin/new-feat' into new-feat
5cc2948 Add helper function for goodbye
9cfcf72 Add initial goodbye module
4c62d28 (origin/new-feat) Use a function to say hello
629f30e Hello from Alice
22b1b17 (origin/main, origin/HEAD, main) Add module docstring in hello.pyWat opvalt is dat we nu drie commits voorlopen op de remote. Terwijl we maar twee nieuwe commits hebben om te pushen. Dit komt door de merge die een extra merge-commit heeft toegevoegd.
---
config:
theme: 'base'
gitGraph:
mainBranchName: 'origin/new-feat'
---
gitGraph
commit id: "22b1b17"
commit id: "629f30e"
branch new-feat
commit id: "9cfcf72"
commit id: "5cc2948"
checkout origin/new-feat
commit id: "4c62d28"
checkout new-feat
merge origin/new-feat id: "9c72952"
Bob zou nu naar de remote kunnen pushen met een gewoon git push commando.
Oefening
We werken verder met de Alice-Bob-teams en de https://github.com/dvx76/git-demo.git repo.
- Alice maakt een aanpassing, commit deze en pusht naar de remote.
- Bob maakt een aanpassing maar niet in hetzelfde bestand en commit deze.
- Bob probeert te pushen.
- Bob probeert te pullen.
- Bob merget de remote branch in zijn lokale branch en pusht dan.
- Alice pullt opnieuw en beiden bekijken de commit history.
Conflicten
Bob en Alice werkten in verschillende bestanden. Daardoor kon Git zonder tussenkomst de commits van Alice in Bob’s lokale branch mergen. Maar wat als beiden binnen hetzelfde bestand hebben gewerkt? Of om specifiek te zijn: op dezelfde lijnen binnen hetzelfde bestand!
De start situatie is opnieuw hetzelfde alleen bevat Bob’s nieuwe commit nu een aanpassing in hetzelfde bestand als Alice’s commit…
Alles verloopt hetzelfde tot het moment dat Bob probeert de remote in zijn lokale branch te merge:
$ git merge
Auto-merging README.md
CONFLICT (content): Merge conflict in README.md
Automatic merge failed; fix conflicts and then commit the result.
$ git status
On branch new-feat
Your branch and 'origin/new-feat' have diverged,
and have 1 and 1 different commits each, respectively.
(use "git pull" if you want to integrate the remote branch with yours)
You have unmerged paths.
(fix conflicts and run "git commit")
(use "git merge --abort" to abort the merge)
Unmerged paths:
(use "git add <file>..." to mark resolution)
both modified: README.md
no changes added to commit (use "git add" and/or "git commit -a")Git kon er niet in slagen de commit(s) van de remote branch automatisch te mergen in de lokale branch. Op dat moment stopt Git met de merge en geeft de controle terug over aan jou om het probleem (conflict) op te lossen. Er wordt ook aangegeven in welke bestand(en) er problemen zijn.
Met git status krijgen we nog wat extra details.
Als we het bestand in kwestie nu bekijken krijgen we iets vreemds te zien:
README.md
A dummy repo to use during Git courses.
<<<<<<< HEAD
Bob was here
=======
Alice was here.
>>>>>>> refs/remotes/origin/new-featDit is Git’s manier om aan te geven waar in het bestand er een conflict is, en wat het conflict precies is. Elke blok tussen <<<<<<< en >>>>>>> is één conflict dat opgelost moet worden. Tussen <<<<<<< en ======= zien we de code zoals die bestaat op de target branch (in dit geval Bob’s lokale branch). Tussen ======= en >>>>>>> de code uit de source branch (in dit geval de remote branch).
Het is nu aan Bob om te beslissen hoe hij dit willen oplossen. Er zijn eigenlijk 4 mogelijkheden:
- Gebruik Bob’s versie (Current Change).
- Gebruik Alice’s versie (Incoming Change).
- Gebruik beide (na elkaar).
- Maak zelf een aangepaste versie.
Bob kiest voor optie 4 en maakt er het volgende van:
README.md
A dummy repo to use during Git courses.
Bob and Alice were here.Na het opslaan van het bestand krijgt Bob deze status:
git status
On branch new-feat
Your branch and 'origin/new-feat' have diverged,
and have 1 and 1 different commits each, respectively.
(use "git pull" if you want to integrate the remote branch with yours)
You have unmerged paths.
(fix conflicts and run "git commit")
(use "git merge --abort" to abort the merge)
Unmerged paths:
(use "git add <file>..." to mark resolution)
both modified: README.md
no changes added to commit (use "git add" and/or "git commit -a")Rest nog alle aanpassingen samen te committen in een merge-commit. Hierbij krijgen we opnieuw een voorgestelde commit message in de editor, net zoals bij een gewone merge.
$ git commit -aOefening
We werken verder met de Alice-Bob-teams en de https://github.com/dvx76/git-demo.git repo.
- Switch naar the branch
team-1voor groep 1, … - Alice maakt een aanpassing, commit deze en pusht naar de remote.
- Bob maakt een aanpassing op dezelfde lijn als Alice en commit deze.
- Bob probeert te pushen.
- Bob probeert te pullen.
- Bob merget de remote branch in zijn lokale branch en pusht dan.
- Alice pullt opnieuw en beiden bekijken de commit history.
Feature branches & Pull Requests
Een Feature Branch is niets meer dan een gewone branch waar nieuwe functionaliteit in wordt ontwikkeld. Hiervoor hebben we het gehad over samenwerken binnen zo een feature branch. Uiteindelijk zal de nieuwe code af zijn en is het de bedoeling dat die code een weg vindt naar de main branch.
We zouden een ontwikkelaar met de nodige machtiging kunnen vragen de code in de feature branch te bekijken, feedback te geven, en uiteindelijk in main te mergen. Zo een process is bijzonder onhandig en maakt het bovendien moeilijk om verschillende personen te betrekken. Bij grote projecten verlies je ook nog eens snel het overzicht.
Een Pull Request is eigenlijk een formele implementatie van dit process. Met een pull request vraag je om de aanpassingen uit jou feature branch te pullen naar de main branch. De GitHub website voorziet hiervoor een specifieke interface waar jij een pull request kan openen. Iedereen kan dan de veranderingen in de request bekijken en rechtstreeks feedback geven op specifieke stukken code. Zo nodig wordt de nieuwe code dan verder aangepast. Als iedereen tevreden is wordt de pull request aanvaard en automatisch gemerged in main.
Pull Requests zijn een functionaliteit van GitHub en niet van Git zelf. Er bestaat dus bvb. geen git pull-request commando.
- Git wordt gebruikt om nieuwe code te committen in een branch en te pushen naar GitHub.
- GitHub wordt gebruikt om een pull request te openen. Die pull request gebruikt Git om bvb. een een diff te laten zijn tussen de feature branch en de
mainbranch. - GitHub gebruikt ook Git om uiteindelijk de feature branch te mergen in
main.
Sommige andere hosting platforms zoals GitLab gebruiken de term Merge Request i.p.v. Pull Request voor hetzelfde process en dezelfde functionaliteit. De term merge request is op zich logischer aangezien de feature branch wordt gemerged via de merge request. GitHub is echter zo populair dat er doorgaans vooral over pull requests wordt gesproken.
Een Pull Request openen
We werken verder van uit de https://github.com/dvx76/git-demo repo. We willen een nieuwe feature branch starten met de bedoeling deze via een pull request in main te mergen. Om de kans om extra merges en conflicten te minimaliseren is het dus belangrijk eerst de lokale main branch te updaten voordat we de nieuwe branch maken.
$ git switch main
$ git pull main
$ git switch -c string-examples
De git-demo repo bevat een python_examples directory waar we voorbeelden willen van basis Python syntax en functies. Als voorbeeld voegen we iets toe in strings.py.
$ git diff
diff --git a/python_examples/strings.py b/python_examples/strings.py
index 65aa152..88b317a 100644
--- a/python_examples/strings.py
+++ b/python_examples/strings.py
@@ -1 +1,7 @@
"""Voorbeelden: werken met strings."""
+
+# String "slicen": Met string_var[x:y] krijg je het deel van de string
+# van karakter x t.e.m. karakter y. Het eerste karakter is 0!
+string_var = "Welkom bij Syntra"
+print(string_var[3:6])
+# output: kom
$ git status
On branch string-examples
Changes not staged for commit:
(use "git add <file>..." to update what will be committed)
(use "git restore <file>..." to discard changes in working directory)
modified: python_examples/strings.py
no changes added to commit (use "git add" and/or "git commit -a")
$ git commit -a -m "Add string example"
[string-examples 99ff974] Add string example
1 file changed, 6 insertions(+)
$ git status
On branch string-examples
nothing to commit, working tree cleanOm te pushen moeten we Git eerst vertellen naar welke remote en branch we willen pushen.
Bij het pushen krijgen we al direct van GitHub (en niet Git zelf, maar wel via Git) een behulpzame link om rechtstreeks en pull request voor deze nieuwe branch te openen!
$ git push
fatal: The current branch string-examples has no upstream branch.
To push the current branch and set the remote as upstream, use
git push --set-upstream origin string-examples
To have this happen automatically for branches without a tracking
upstream, see 'push.autoSetupRemote' in 'git help config'.
$ git push --set-upstream origin string-examples
Enumerating objects: 7, done.
Counting objects: 100% (7/7), done.
Delta compression using up to 10 threads
Compressing objects: 100% (4/4), done.
Writing objects: 100% (4/4), 1.12 KiB | 1.12 MiB/s, done.
Total 4 (delta 2), reused 0 (delta 0), pack-reused 0 (from 0)
remote: Resolving deltas: 100% (2/2), completed with 2 local objects.
remote:
remote: Create a pull request for 'string-examples' on GitHub by visiting:
remote: https://github.com/dvx76/git-demo/pull/new/string-examples
remote:
To https://github.com/dvx76/git-demo.git
* [new branch] string-examples -> string-examples
branch 'string-examples' set up to track 'origin/string-examples'.Naast deze rechtstreekse URL zijn er nog een aantal andere manieren om een pull request te openen. Van de homepage van het project (https://github.com/dvx76/git-demo) klik je op Pull requests en dan door naar New pull request. Naar moeten links de target branch (hier main) en rechts de source branch (hier string-examples) geselecteerd worden. Vervolgens krijgen we een overzicht van de pull request: 1 commit, 1 aangepast bestand, enz…
Als we op Create pull request klikken kunnen we verdere details invullen:
- De titel van de PR, deze hou je best kort en duidelijk, net zoals de eerste lijn van een commit.
- De beschrijven, hier leg je uit wat de bedoeling is van de aanpassingen in de PR.
- Andere velden en opties zijn optioneel en laten we nog leeg.
Als de PR eenmaal is aangemaakt krijg hij een unieke ID en kan je hem terugvinden in de lijst met PRs (https://github.com/dvx76/git-demo/pulls).
Een Pull Request reviewen
We bekijken samen hoe je feedback kan geven op de PR, algemeen als ook op specifieke stukken nieuwe code.
Eenmaal tevreden met de inhoud van de PR wordt deze toegestaan (approve) en gemerged.
Oefening
Werk voor deze oefening individueel.
- Zorg de je lokale
mainbranch van degit-demorepo up-to-date is. - Kies een van de bestanden uit
python_exampleswaar je iets aan kan toevoegen. Je mag ook altijd een nieuw bestand toevoegen. - Maak een nieuwe branch aan. Kies de naam in functie van wat je van plan bent toe te voegen.
- Commit je verandering en push de branch.
- Open een pull request om je branch in
mainte mergen. - Als je klaar bent bekijk dan de andere pull requests en geef feedback. Bekijk de feedback op je eigen pull request.
- We bekijken samen elke pull request en lossen eventuele conflicten op.
Extra: Git Rebase
Om conflicten op te lossen en een feature branch te updaten met de main branch hebben we tot nu toe merge gebruikt. Het is je misschien opgevallen dat daardoor en commit history nogal slordig en onoverzichtelijk wordt, ongeveer zoals dit:
$ git log --oneline --no-decorate --graph
* b71af35 Another strings example
* d5130be Merge branch 'main' into new-feat
|\
| * dda5919 Updates to numbers
* | b82b0de Another feature
* | b4df073 Merge branch 'main' into new-feat
...Dat komt omdat er telkens een merge commit wordt toegevoegd (met 2 parents dus, de oorspronkelijk laatste commit op de feature branch, en de laatste commit op main).
Een rebase is een manier om de nieuwe commits op de feature branch (new-feat) opnieuw te maken vanaf de laatste commit op de source branch (main). Als je dit handmatig doet zou je door volgende stappen moeten gaan:
- Ga terug naar het branchpunt (
git reset --hard 629f30e, komen we later op terug) - Pull/merge de source branch, dit kan nu met fast-forward (
git pull) - Maak de aanpassingen van elke commit opnieuw en maak nieuwe commits (
git commit -a)
Veel werk, zelfs voor eenvoudige commits. git rebase doet dit allemaal automatisch.
Rebase kan gebruikt worden in verschillende situaties - Bij pull requests, waarbij de target branch (meestal main) waar in willen mergen nieuwe commits heeft gekregen sinds we de feature branch hebben aangemaakt. In dit geval rebasen we de feature branch op main. - Tijdens het samenwerken op eenzelfde remote branch (zoals met Bob en Alice in de vorige hoofdstukken). In dat geval rebasen we de lokale branch op de remote.
$ git rebase
Successfully rebased and updated refs/heads/new-feat.
$ git status
On branch new-feat
Your branch is ahead of 'origin/new-feat' by 2 commits.
(use "git push" to publish your local commits)
nothing to commit, working tree clean
$ git log --oneline
8077d15 (HEAD -> new-feat) Add helper function for goodbye
0320454 Add initial goodbye module
4c62d28 (origin/new-feat) Use a function to say hello
629f30e Hello from AliceDitmaal hebben we slechts onze 2 nieuwe commits te pushen.
Merk op dat de twee commits ook effectief nieuw zijn. De aanpassingen in elke commit zal nog wel hetzelfde zijn, maar de commit ID is verandert want ook de parent van elke commit is verandert!
---
config:
theme: 'base'
gitGraph:
mainBranchName: 'origin/new-feat'
---
gitGraph
commit id: "22b1b17"
commit id: "629f30e"
commit id: "4c62d28"
branch new-feat
commit id: "0320454"
commit id: "8077d15"
Oefening
Rebase is een erg krachtig concept en wordt veel gebruikt, maar kan in het begin moeilijk te begrijpen zijn. Een oefening op https://learngitbranching.js.org/, met visualization van de commit tree, kan hierbij helpen.
De volgende oefening zijn interessant in het kader van rebase:
- Main - Introduction Sequence - 4 (Rebase introduction)
- Remote - Push & Pull - 7 (Diverged History)
Merge of Rebase?
Mergen of committen? Elk heeft zijn voor en nadelen. In de volgende tabel krijg je een overzicht van de belangrijkste punten:
| Voordelen | Nadelen | |
|---|---|---|
| Merge |
|
|
| Rebase |
|
|
Rebase Conflicts
Net zoals bij een merge kunnen bij een rebase ook conflicten optreden.
We keren terug naar de vorige situatie waarbij Bob twee nieuw commits heeft. Hij voegt een derde commit toe die ook hello.py aanpast, net op dezelfde lijnen als de uitstaande commit van Alice.
---
config:
theme: 'base'
gitGraph:
mainBranchName: 'origin/new-feat'
---
gitGraph
commit id: "22b1b17"
commit id: "629f30e"
branch new-feat
checkout origin/new-feat
commit id: "4c62d28"
checkout new-feat
commit id: "9cfcf72"
commit id: "5cc2948"
commit id: "9465e01"
Als Bob nu probeert te rebasen gebeurt het volgende:
$ git rebase
Auto-merging hello.py
CONFLICT (content): Merge conflict in hello.py
error: could not apply 9465e01... Use goodbye module in hello
hint: Resolve all conflicts manually, mark them as resolved with
hint: "git add/rm <conflicted_files>", then run "git rebase --continue".
hint: You can instead skip this commit: run "git rebase --skip".
hint: To abort and get back to the state before "git rebase", run "git rebase --abort".
hint: Disable this message with "git config set advice.mergeConflict false"
Could not apply 9465e01... Use good module in helloGit kon de eerste tween commits (9cfcf72, 5cc2948) zonder problemen toepassen maar bij de derde commit krijgen we een conflict dat we zelf moeten oplossen.
Net als bij een gewone merge conflict moeten we de bestanden met conflicten handmatig oplossen. Als we daarmee klaar zijn kunnen we de rebase laten verdergaan met git rebase --continue. We krijgen dan ook nog de kans om de commit message aan te passen indien nodig. We krijgen dus geen merge-commit! Zoals gebruikelijk geeft git status ons altijd een duidelijk beeld van wat er gaande is en wat er moet gebeuren.
$ git status
interactive rebase in progress; onto 4c62d28
Last commands done (3 commands done):
pick 5cc2948 Add helper function for goodbye
pick 9465e01 Use good module in hello
(see more in file .git/rebase-merge/done)
No commands remaining.
You are currently rebasing branch 'new-feat' on '4c62d28'.
(fix conflicts and then run "git rebase --continue")
(use "git rebase --skip" to skip this patch)
(use "git rebase --abort" to check out the original branch)
Changes to be committed:
(use "git restore --staged <file>..." to unstage)
modified: goodbye.py
Unmerged paths:
(use "git restore --staged <file>..." to unstage)
(use "git add <file>..." to mark resolution)
both modified: hello.py
$ git add hello.py
$ git rebase --continue
[detached HEAD 896d701] Use goodbye module in hello
2 files changed, 4 insertions(+), 1 deletion(-)
Successfully rebased and updated refs/heads/new-feat.Het kan zeker voorkomen dat na het oplossen van een conflict er tijdens het toepassen van de resteren commits opnieuw een conflict optreedt.
Zoals git rebase en git status al aangeven kunnen we er ook voor kiezen om de problematische commit helemaal over te slaan, met het git rebase --skip commando. Dit kan bijvoorbeeld voorkomen als de wijzigen in de commit niet meer relevant zijn.






