Subsections of Git sessions
Session 11: Git: Your code's history book
Imagine: you work on your game for three hours. You add a cool new weapon. But… now the rest of your game doesn’t work anymore. And you no longer know what exactly you changed. Three hours of work gone.
Git is the solution. Git remembers every version of your files. Like an endless “undo” button that never forgets what you did.
In this session you install Git, you make your first repository and you record what you do for good: step by step, version by version. And the fun part: Git doesn’t only work for code. Also for notes, school reports and stories.
What is Git?
Git is a version control system. It keeps track of what you change in your files, when you did it, and why. Every time you finish a piece of work, you make a commit: a snapshot of all your files at that moment.
What makes Git special:
- Every version is kept. You can always go back to a previous commit if something breaks.
- You work locally. Git runs on your computer. No internet needed.
- Git is fast. Even projects with thousands of files are checked in milliseconds.
Git was made by Linus Torvalds, the same person who built Linux. He needed something to work on the Linux kernel with thousands of programmers at the same time. In 2005 he built Git in a weekend. Today almost every developer in the world uses it.
Git is not only for code
Git was built for source code, but it works with every text file. A text file is any file you can open and read with Notepad or a simple editor: .py, .html, .css, .json, .txt, .csv, .md (Markdown), .yml, .toml, you name it.
What Git is not good at: binary files. Those are files that don’t consist of readable text: images (.png, .jpg), videos (.mp4), compiled programs (.exe), Word documents (.docx). Git can track them, but it is slower and you can’t see what exactly changed. With text files git diff shows every letter you added or removed. With a .png Git only says “this file has changed”, but not what changed about the image.
Markdown and notes
Many note-taking apps these days use Markdown (.md files) to store your documents. Think of:
- Obsidian: your notes are just
.md files in a folder on your computer - Notion: exports to Markdown
- Joplin: stores everything as Markdown
- Typora, Zettlr, Logseq: all Markdown-based
Because Markdown files are ordinary text files, you can let Git loose on them. You keep the history of your notes, you can go back to a previous version of a document, and you can share your notes via GitHub, exactly like you do with code.
Putting a folder of Markdown notes under Git is just as simple as a Python project:
mkdir mijn-notities
cd mijn-notities
git init
echo "# My Notes" > start.md
git add start.md
git commit -m "First note: start page"
From that moment on Git keeps every change to your notes. Writing a report for school in Markdown? Commit every paragraph. Working on worldbuilding for a story? Git remembers every version of your plot.
When to use Git for notes and when not
| Do use Git | Better use something else |
|---|
Notes in Markdown (.md) | Notes in Word (.docx) |
Configuration files (.json, .yml) | Large images or videos with your notes |
| Writing: reports, stories, blogs | Real-time collaboration like Google Docs (Git is too slow for that) |
| Your CoderDojo cheatsheets | Passwords or personal diaries (unless private repo) |
In short: anything that is text you can put in Git. Anything that is binary, better not.
Why version control?
Without Git your workflow looks like this:
game.py
game_backup.py
game_backup2.py
game_final.py
game_final_echt.py
game_final_echt_nieuwe_wapens.py
Recognise that? With Git you only need one file: game.py. Git remembers the rest.
What version control gives you:
- Never lose work again. Everything you commit keeps existing. Always.
- Understand what happened. You see exactly which lines you changed and when.
- Experiment without risk. Make a separate copy of your code (a branch), try something weird, and throw it away if it doesn’t work. Your original code stays intact.
- Work together. Several people can work on the same project at the same time without overwriting each other’s code.
What do you NOT put in Git?
Git is made for text files: files you write yourself: code, notes, configuration. There are things you’d better keep out of Git:
| Do put in Git | Do NOT put in Git |
|---|
Your Python files (.py) | Passwords, API keys, tokens |
| Images your game uses | Files your program creates itself (.exe, .pyc) |
Sound files (.wav, .mp3) | The __pycache__ folder |
| Text files, configuration | Large files (>50 MB) like videos |
Your README.md | Settings of your own specific computer |
Why no passwords in Git? Because Git remembers everything, forever. Even if you delete a password later, it is still in the history. Anyone who ever sees your code can scroll back to that commit. And if your code ever ends up on GitHub, your password is on the internet. Forever.
Use a .gitignore file to tell Git which files it should ignore. You’ll find out about that in a moment.
Step 0: Git setup
Windows
- Go to git-scm.com and download the Windows installer.
- Double-click the downloaded file.
- Click through the installation. The default options are fine.
- Important: when picking the text editor, choose Nano or Notepad++ (not Vim, unless you already know Vim).
- After the installation, open Git Bash (search for it in the start menu).
Mac
Open Terminal (search for “Terminal” in Spotlight) and type:
If Git is not installed, macOS asks you to install the developer tools. Click “Install”. Done.
Linux (Ubuntu/Debian)
Checking that it works
Open a terminal (Git Bash on Windows) and type:
You see something like git version 2.47.0. That means: Git is ready.
Step 1: Tell Git who you are
Git wants to know who you are, so it can put your name on every commit. You do this once, after that Git remembers it.
git config --global user.name "Your Name"
git config --global user.email "your@email.com"
Use the same email address you will use for GitHub later. That makes linking easier.
Tip: --global means: this setting applies to all your Git projects. You only have to do this once.
Step 2: Making your first repository
A repository (or “repo”) is a folder where Git keeps track of the versions. Let’s make one.
First make a new folder for your project:
mkdir mijn-eerste-git-project
cd mijn-eerste-git-project
Now you tell Git: “This folder is a repository.”
You see: Initialized empty Git repository in .../mijn-eerste-git-project/.git/
Git has created a hidden .git folder. That is where it keeps everything: the history, the commits, the configuration. Never touch that folder by hand, because Git manages it itself.
Step 3: Committing your first file
Create a file. For example a Python file with one line:
echo 'print("Hello Git!")' > hallo.py
Now you tell Git: “Keep an eye on this file.”
With git add you put files in the staging area: a waiting room. You say to Git: “I want these changes in my next commit.”
Check what is ready:
Git shows:
On branch master
Changes to be committed:
new file: hallo.py
Now comes the commit itself:
git commit -m "My first commit: added hallo.py"
What happens here? -m stands for “message”. The text between quotes is your commit message: a short explanation of what you changed. Git has now made a permanent snapshot of your project.
Good commit messages: Write in English (that is the convention in almost all projects). Start with a verb: “Add”, “Fix”, “Update”. Keep it short: 72 characters max.
Step 4: Tracking changes
Open hallo.py in a text editor. Change the line to:
print("Hello Git! You remember my code.")
Save the file. Now look at what Git sees:
Git knows that hallo.py has changed. But what exactly has changed?
git diff shows exactly which lines you added (green with +) and removed (red with -). This is one of the most powerful things about Git: you literally see what changed, character by character, since your last commit.
Commit the change:
git add hallo.py
git commit -m "Update: greeting extended"
Step 5: Back in time
This is where Git gets magical. Suppose: you regret your last change. You want to go back to the first version.
First show all commits:
You see something like:
a1b2c3d Update: greeting extended
e4f5g6h My first commit: added hallo.py
Every commit has a unique code, a hash. That long code (shortened to 7 characters) identifies exactly that one version of your project.
To see what hallo.py looked like in the first commit:
git show e4f5g6h:hallo.py
There is your original print("Hello Git!") again.
Do you really want to go back in time? That is possible:
git checkout e4f5g6h -- hallo.py
Now hallo.py is back the way it was in your first commit. Check with cat hallo.py. You see the old version. But don’t worry: your second commit is not gone. With git checkout master -- hallo.py you go back to the newest version.
Step 6: What does NOT go in Git: .gitignore
Create a file that Git should ignore:
echo "GEHEIM_WACHTWOORD=12345" > geheimen.txt
git status now shows this file as “untracked”. Git has seen it, but doesn’t know if you want to track it. You can ignore it with a .gitignore file:
echo "geheimen.txt" > .gitignore
Now run git status again and geheimen.txt has disappeared from the list. Git ignores it. (Do add .gitignore itself to Git with git add .gitignore and git commit, so others know what has to be ignored too.)
A good .gitignore for a Python project:
# Python
__pycache__/
*.pyc
*.pyo
# Secrets
*.env
secrets.txt
# Your editor
.vscode/
.idea/
Showcase
Show a coach and a buddy:
- Your repository with at least 3 commits.
- The result of
git log --oneline: your commit history. - A
git diff that shows what you changed. - Your
.gitignore file.
See you next time!
“Next time: two versions of your code at the same time. You work on a new feature while the old version keeps working. That’s called branches, and it’s what makes Git really powerful.”
Take it home
- Easy: Make a repository for your notes. Put a Markdown file with what you learned today in Git, and commit it.
- Medium: Change something in your code or notes, use
git diff to look at the change, and commit it with a good message. - Hard: Make three commits with different changes. Use
git show to look at each version. Use git checkout to go back to the first commit, and then to the last one again. - Very hard: Make a Python project with a good
.gitignore. Make sure __pycache__/ and .pyc files really are ignored (check with git status).
Stuck? Ask a coach at the next dojo, or just try something else. Programming is doing. Learning Git is doing.
Session 12: Git Branches: Parallel universes for your code
Last session you learned to make commits: snapshots of your code on one timeline. Everything neatly one after the other.
But what if you want to try out a new idea? Adding a laser gun to your game, for example. You don’t know whether it will work. You don’t want to break your working code.
That is what branches are for.
A branch is a copy of your code where you can experiment freely. Your main code (the master branch) stays safe. If your experiment works, you paste it back into master. Doesn’t it work? You throw the branch away. Your master branch never noticed a thing.
Note: On GitHub and in many new projects the main branch is called main instead of master. That is exactly the same, only the name is different. In this course we use master, but if you come across main online, you know it means the same thing.
What you’ll learn today
- What a branch is and how Git stores branches internally
- Creating, switching and merging branches
- What a merge conflict is and how to solve it
- When you should and shouldn’t use a branch
Step 0: Recap: where are you now?
Open your terminal in last session’s project. Check where you are:
git status
git log --oneline
You have a few commits on master. This is your stable base: you’ll branch off from here in a moment.
Step 1: Your first branch
You’re going to add a new feature: a highscore.txt file that keeps the highest score. But first you make a branch:
git branch highscore-feature
Git has now created a new branch. But you are still on master. Check which branches there are:
You see:
highscore-feature
* master
The asterisk next to master means: “this is where you are now.” Switch to your new branch:
git switch highscore-feature
(Older Git versions use git checkout highscore-feature. Both work.)
git branch one more time: the asterisk is now next to highscore-feature. Everything you commit now happens on this branch. master stays untouched.
Tip: You can create a branch and switch to it straight away in one command:
git switch -c mijn-nieuwe-branch
-c stands for “create”. This is faster and you never forget to switch.
Step 2: Doing work on a branch
Create a new file:
echo "HIGHSCORE: 0" > highscore.txt
Commit your work:
git add highscore.txt
git commit -m "Add highscore.txt with start value 0"
Add another file that reads the highscore:
echo 'def lees_highscore():' > highscore_manager.py
echo ' with open("highscore.txt") as f:' >> highscore_manager.py
echo ' return int(f.read().split(": ")[1])' >> highscore_manager.py
Commit again:
git add highscore_manager.py
git commit -m "Add highscore_manager: function to read the highscore"
Now look at your log:
You see all your commits from master, plus the two new ones. Git remembers the whole chain.
Step 3: Two worlds at once
Switch back to master:
Look at what is here:
highscore.txt and highscore_manager.py are… gone. They only exist on the highscore-feature branch. On master everything is still exactly as you left it.
This is the magic of branches: two (or more) versions of your project, at the same time on your computer, without getting in each other’s way.
Switch back and forth once more to feel it:
git switch highscore-feature # the files are back
git switch master # the files are gone again
Step 4: Merging with git merge
Your highscore feature works. Time to put it back into master. This is called merging.
Make sure you are on master:
Merge the branch:
git merge highscore-feature
Git shows something like Updating a1b2c3d..e4f5g6h and Fast-forward. Your highscore-feature commits are now part of master. Check:
highscore.txt and highscore_manager.py are now on master. All commits from the feature branch have been included in the history.
Step 5: What are merge conflicts?
Suppose: you have changed something on master in highscore.txt, for example “HIGHSCORE: 100” instead of “HIGHSCORE: 0”. And at the same time you have changed highscore.txt on another branch too, to “HIGHSCORE: 500”.
If you now try to merge, Git doesn’t know which version is the right one. That is a merge conflict. Git asks you to decide.
Let’s provoke it on purpose.
On master:
echo "HIGHSCORE: 100" > highscore.txt
git add highscore.txt
git commit -m "Update highscore to 100 on master"
Make a new branch and change the same file there:
git switch -c andere-highscore
echo "HIGHSCORE: 500" > highscore.txt
git add highscore.txt
git commit -m "Update highscore to 500"
Switch back to master and try to merge:
git switch master
git merge andere-highscore
Git says: CONFLICT (content): Merge conflict in highscore.txt. Open highscore.txt in your editor. You see:
<<<<<<< HEAD
HIGHSCORE: 100
=======
HIGHSCORE: 500
>>>>>>> andere-highscore
These are the two versions. HEAD is your master version. Below it is the version from andere-highscore. You choose which one you keep, or you combine them.
Remove the markers and choose one version:
Save the file. Tell Git that the conflict is resolved:
git add highscore.txt
git commit -m "Merge: chose highscore from andere-highscore"
Conflict solved. Git can carry on again.
Step 6: Cleaning up branches
Your feature is merged. You don’t need the branch anymore:
git branch -d highscore-feature
git branch -d andere-highscore
-d stands for “delete”. Git refuses to delete a branch that hasn’t been merged yet: that is a safety valve. If you really want to throw it away without merging, you use -D (capital letter). But be careful with that.
When a branch, when not?
| Do use a branch | No branch |
|---|
| New feature that takes time | Fixing a typo in a comment |
| Experiment you don’t know will work | Small bugfix of one line |
| Something that can break your working code | You work alone and your change is clear |
| You work together with others | (with solo work master is often enough) |
Rule of thumb: If you doubt, make a branch. A branch costs nothing. Losing code does.
Tips for working smoothly with branches
- Keep branches short. A branch of 3 hours is fine. A branch of 3 weeks becomes a merge nightmare: the longer you wait to merge, the more has changed on
master in the meantime, and the bigger the chance of conflicts. - One thing per branch. “Add highscore” is a good branch. “Add highscore, menu, and new levels” is too much: split it up.
- Merge often. When you finish your feature, merge it back into
master straight away. Small, frequent merges are easier than one big monster merge. - Give branches clear names.
highscore-feature is good. test123 or branch2 are bad. In a week you won’t remember what was in test123. - Check where you are before you start.
git branch or git status tells you which branch you are on. Make this a habit, so you avoid accidentally writing code on master that really belongs on a feature branch.
Showcase
Show a coach and a buddy:
git branch with at least two branches (including master).- A different file or different code on each branch.
- Switching back and forth: the files appear and disappear.
- A successful merge of a feature branch into
master.
See you next time!
“Until now all your code only lives on your laptop. Next time we put it online. You make a GitHub account, push your repository to the internet, and your game can be seen all over the world. And: you can work together with others. GitHub: your code out into the world.”
Take it home
- Easy: Make a branch for a small feature in an existing project. Commit your work and merge it back.
- Medium: Deliberately create a merge conflict (two branches that change the same file) and solve it.
- Hard: Work with three branches at the same time on the same project. Merge them back into
master one by one. Check after every merge whether everything still works. - Very hard: Make a branch, commit three changes, switch back to
master, make a change in the same file there too, and merge the branch. Solve the conflict carefully and check with git log --graph what the history looks like.
Session 13: GitHub: Your code online, for everyone
Until now all your code lives on your laptop. Handy for you, but nobody else can get to it. And if your laptop crashes, you lose everything.
GitHub is a website where you put Git repositories online. It is a backup, a portfolio, and a collaboration platform in one. Today you put your code on GitHub. At the end of this session anyone with an internet connection can look at your projects, and you at theirs.
What is GitHub?
GitHub is not the same as Git. Git is the version control system that runs on your computer. GitHub is a website (github.com) that hosts Git repositories: a kind of Google Drive for code, but with Git underneath.
What GitHub adds to Git:
- Backup in the cloud. Your code is not only local. Laptop broken? Your code survives.
- Working together. Several people can work on the same repo. GitHub manages who is allowed to do what.
- Pull requests. You ask permission to put your changes into someone’s project, with discussion and review.
- Issues. Reporting bugs, suggesting features, tracking tasks: all in your repo.
- Portfolio. Your GitHub profile is your business card. Employers look at it.
GitHub is not the only option; there are alternatives such as GitLab and Bitbucket. But GitHub is the biggest, with more than 100 million users. In these sessions we use GitHub.
Step 0: Making a GitHub account
- Open github.com in your browser.
- Click on Sign up.
- Fill in your email address. Use the same address you set in session 11 with
git config: that saves hassle. - Choose a username. This becomes your identity on GitHub. Pick something you’ll still like in 5 years. You can change your username later, but old links to your profile won’t work anymore.
- Verify your account via the email GitHub sends.
- Choose the Free subscription. Everything you need is free: unlimited public and private repositories.
Tip for coaches: check whether the ninjas have access to their email during the session. Some laptops are not logged in to webmail. Have a plan B ready: if email verification doesn’t work, ninjas can verify GitHub later at home. The rest of the session works without verification too.
Step 1: Your first repository on GitHub
You have a local project on your computer (from session 11). You are going to put it online now.
On GitHub, click the + icon at the top right β New repository.
Fill in:
| Field | What you fill in |
|---|
| Repository name | mijn-eerste-git-project (same as your local folder) |
| Description | “My first Git project (CoderDojo session 11)” |
| Public / Private | Choose Public: others may see your code |
| Initialize with README | Do NOT tick: you already have a local project |
Click Create repository.
GitHub now shows instructions. Choose the block under "β¦or push an existing repository from the command line". Copy those three commands: you’ll need them in a moment.
Step 2: Linking your local repo to GitHub
In your terminal (in your project folder):
git remote add origin https://github.com/JOUW_USERNAME/mijn-eerste-git-project.git
What happens here? remote is an external location where your repo also lives. origin is the name you give that location. “origin” is the default name for your most important remote. You can have several remotes (for example origin for GitHub, backup for GitLab), but one is usually enough.
Check whether it worked:
You see:
origin https://github.com/JOUW_USERNAME/mijn-eerste-git-project.git (fetch)
origin https://github.com/JOUW_USERNAME/mijn-eerste-git-project.git (push)
fetch = this is where you get code from. push = this is where you send code to. Usually they are the same.
Step 3: Putting your code online with git push
Now comes the moment: sending your local commits to GitHub.
git push -u origin master
push = send my commits to the remote. -u origin master = “remember that master on my computer belongs with master on origin.” Next time you can simply type git push, because Git remembers the link.
GitHub asks you to log in. There are two ways:
- Via the browser: GitHub opens a browser window, you click “Authorize”. Done.
- With a Personal Access Token: create one via GitHub β Settings β Developer settings β Personal access tokens β Tokens (classic). Give the token a name, tick
repo, copy the token, and paste it as the password in the terminal.
For ninjas: method 1 (browser) is the easiest. If that doesn’t work, help with a token.
After a successful push, refresh your GitHub page. Your files are there! Your hallo.py, your commit history: everything.
Step 4: Pushing changes
Make a change locally:
echo 'print("GitHub is cool!")' >> hallo.py
git add hallo.py
git commit -m "Add GitHub enthusiasm"
Push to GitHub:
You no longer need -u origin master, because Git knows the way. Refresh GitHub: your new commit is there.
Step 5: Starting a new project via GitHub
This is the reverse route: you start on GitHub and bring it to your computer.
On GitHub: New repository. Call it python-spelletje. This time do tick Add a README file; GitHub then makes a repo with one file in it. Click Create repository.
Now you bring this repo to your computer. This is called cloning:
cd ~ # go to your home folder
git clone https://github.com/JOUW_USERNAME/python-spelletje.git
GitHub creates a folder python-spelletje with the README in it. And it is a full Git repository straight away: the .git folder is already in it. You don’t need to do git init.
cd python-spelletje
git log --oneline # you see the first commit GitHub made for you
Now you can carry on working locally and push your commits to GitHub, exactly like in Steps 3 to 4.
Step 6: What if someone else makes changes too?
Suppose: you worked on python-spelletje at home and pushed. Now you are on the dojo laptop and want to carry on. You don’t have the newest version yet.
git pull fetches the newest commits from GitHub to your computer. It is two actions in one: git fetch (fetching) + git merge (merging with your local code).
Always do git pull before you start working, otherwise you fall behind and you get merge conflicts.
Summary of the workflow:
| Command | What it does |
|---|
git pull | Fetch the newest version from GitHub |
Work on your code, make commits (git add, git commit) | |
git push | Send your commits to GitHub |
Remember: pull before you start, push when you’re done.
Showcase
Show a coach and a buddy:
- Your GitHub profile with at least one repository.
- The commit history of your repo on GitHub (click on “X commits” above the file list).
- A fresh
git push that has just arrived on GitHub.
See you next time!
“Now your code is online. But what do you put in a commit message? How do you write a message that is still clear in three months? And how do you work with a team without breaking things? Next time: the professional side of Git: best practices every developer uses.”
Take it home
- Easy: Push an existing local project to a new GitHub repository.
- Medium: Make 3 commits locally, push them, and check on GitHub whether they are all visible.
- Hard: Clone a repo from GitHub, make a change, commit, and push back.
- Very hard: Simulate working on two computers: clone a repo, make a commit and push. Go to another folder, clone the same repo again (as if it were another computer), make a different commit, and try to push. What happens? Solve it with
git pull.
Session 14: Git Best Practices: Write commits you'll still understand later
You can type Git commands. Your code is on GitHub. But there’s a difference between “using Git” and “using Git well.”
This session is about the habits experienced developers apply every day. No new commands, just sharper rules. At the end you write commit messages you’ll still get something out of a year from now, and you work with a branching strategy that keeps your project tidy.
What you’ll learn today
- How to write a commit message that says something
- Three simple rules for branching
- What
git stash is and when to use it - The pull-before-you-push rule
Part 1: Commit messages that say something
A bad commit message looks like this:
git commit -m "fix"
git commit -m "update"
git commit -m "changed stuff"
Three months from now you look back. What was “fix”? Which “things”? You don’t know any more. You have to dig through the code to work out what happened. That’s a waste of time.
The good commit message: 3 parts
A professional commit message has three parts:
1. A short summary (max 72 characters)
Write in English. Start with a verb in the present tense. This is called “imperative mood”: as if you’re giving an order to the codebase. Think: “Add”, “Fix”, “Remove”, “Update”, “Refactor”.
Add highscore tracking
Fix star spawning off-screen
Remove unused collision code
2. A blank line
3. A longer explanation (optional, if it’s needed)
Add highscore tracking
Saves the highest score in highscore.txt. The score is
updated after every game-over. The file is created if it
doesn't exist yet.
This replaces the old method where the score only lived in
memory and got lost when the game closed.
The longer explanation tells why you changed something, not just what. The code itself already shows the “what”. The “why” is what you need in three months.
Commit message rules at a glance
| Do this | Not this |
|---|
| “Add player health bar” | “added health bar thing” |
| “Fix collision detection on left wall” | “fix” |
| “Remove debug print statements” | “cleanup” |
| Max 72 characters for the title | A whole story in the title |
| Present tense, English | Past tense (“added”, “fixed”) |
Why English? Because nearly every open source project uses English. Code is international. You write your Python code in English too (def calculate_score). Your commit messages follow that same language.
Why present tense? A commit describes what this change does, not what you did. “Add feature” (this commit adds a feature), not “Added feature” (I added a feature once). Git itself uses present tense too: Merge branch 'feature', not Merged.
Multi-line commits in the terminal
You can write a commit message over several lines by not closing the quotes:
git commit -m "Add highscore tracking
Saves the highest score in highscore.txt. The file is
created automatically on the first game-over."
Note: you only type the closing quote on the last line. Everything in between is part of your message.
When do you commit?
Commit often. Commit small.
Not: working for three hours, one enormous commit with 47 changed files.
Yes: a commit every 15 to 30 minutes, each time one logical piece is done.
A rule of thumb: if your commit message contains “and”, your commit is too big. “Add highscore tracking and fix menu bug and update sprites” β those should be three separate commits.
Small commits make it easier to:
- Understand what changed and when
- Undo one specific change without breaking other things
- Solve merge conflicts (small chunks = fewer conflicts)
Part 2: Branching: three simple rules
You already know how to make branches (session 12). Now: when and why.
Rule 1: master always works
The master branch is your shop window. Someone who clones your repo has to be able to run your code without error messages. master never contains half-finished work.
Not OK on master: code with # TODO: still needs finishing, commented-out functions, experiments you’ll “fix later.”
Fine on master: working code. Full stop.
Rule 2: One feature, one branch
A branch does exactly one thing. No more.
- Good:
feature/player-health-bar - Bad:
feature/health-bar-and-menu-and-sound-effects
If, while working on a feature, you think: “Oh, I can quickly fix that menu bug too”: stop. Make a new branch for the bugfix. Merge that one first. Then carry on with your feature.
Rule 3: Branches have a short life
A branch that exists for more than a few days becomes a problem. master changes in the meantime, and your branch falls behind. The longer you wait to merge, the bigger the chance of merge conflicts.
Merge your branch as soon as the feature is done. For small things (a 10-minute bugfix): you might not even need a separate branch.
Branch naming
Give branches names you’ll still understand a week from now:
feature/highscore-tracking
bugfix/star-spawn-offscreen
experiment/particle-effects
The prefix (feature/, bugfix/, experiment/) immediately tells you what kind of work is in this branch. It’s a convention, not a technical requirement, but it helps.
Part 3: Handy workflow commands
git stash: putting work aside
Say: you’re working on a feature branch. Your code is half done. You want to switch to master for a quick bugfix, but you don’t want to commit your half-finished work. That’s what git stash is for:
Git stores all your changes temporarily and puts your working directory back to the last commit. Now you can switch, do the bugfix, commit, and come back:
git switch master
# ... do the bugfix, commit ...
git switch feature-branch
git stash pop
git stash pop brings your stored changes back. Everything is as you left it: half done, but safely kept.
git pull --rebase: a cleaner history
Normally git pull does a merge. That creates an extra merge commit. Sometimes you don’t want that; you want a straight line of commits without branches.
This fetches the newest commits and puts your local commits on top of them, as if you made them after the remote commits. The result is a linear history: no merge commits that only say “Merge branch ‘master’”.
Note: only use --rebase on branches that you alone use. On shared branches a plain git pull (merge) is safer.
The pull-before-you-push rule
Before you git push:
Always. Even if you think nobody else pushed. It takes one second and stops GitHub from refusing your push with “Updates were rejected because the remote contains work that you do not have locally.”
This rule matters most when you work together. If you’re the only one working on a repo, the risk is smaller, but the habit is worth gold.
Part 4: The .gitignore you always need
Every project has files that don’t belong in Git. Your .gitignore is your first line of defence against accidentally committing passwords.
Minimal .gitignore for a Python project:
# Python
__pycache__/
*.pyc
*.pyo
# Virtual environment
venv/
.venv/
# Environment variables (often contain passwords/keys)
.env
# Your editor
.vscode/
.idea/
*.swp
*.swo
# OS files
.DS_Store
Thumbs.db
Why ignore __pycache__/? These are compiled Python files that your program creates automatically. They differ per Python version and per computer. Putting them in Git only adds noise.
Why ignore .env? .env files often contain secret keys, API keys, database passwords. Those must never, ever go into Git.
Showcase
Show a coach and a buddy:
- Your last 5 commits, with good commit messages.
- Your
.gitignore file. - A branch name that follows the feature/ prefix convention.
See you next time!
“Now you work with Git like a professional. But there’s one more concept that every team uses: the pull request. Your code is ready, but before it goes into master, someone else has to approve it. How does that work? Next time: pull requests, the review wall that every change has to pass through.”
Take it home
- Easy: Rewrite the commit messages of your last 5 commits. Use the rules from this session.
- Medium: Create a branch with the
feature/ prefix, work in it, merge it back, and delete it. Do the same for a bugfix/ branch. - Hard: Use
git stash to save half-finished work, switch to master, make a quick fix, push, and come back to your feature with git stash pop. - Very hard: Create a situation where
git pull fails (clone your repo in two folders, make a different commit in both, push the first one, and try to push the second). Solve it: git pull, fix the merge conflict, and only then push.
Session 15: Pull Requests: Your project's front door
You built a feature on a branch. Good commit messages, tidy work. Now you want to get your code into master.
You could do git merge and be done. But in a team that doesn’t work. Someone else has to look at your code first: check for mistakes, for style, for things you missed. That is a pull request.
A pull request (PR) is a request: “Bring my changes in.” You open it on GitHub. Your teammates look at your code and give feedback. You change things. Only when everyone is happy does the code go to master.
In this session you make your first pull request. You review a buddy’s. And you find out what real teamwork with Git feels like.
What you’ll learn today
- What a pull request is and why teams use it
- Opening a PR on GitHub
- Updating your PR after feedback
- Reviewing someone else’s PR
- Merging a PR and cleaning up the branch
Step 0: Preparation: working in pairs
Today you work together with a buddy. Agree who is the author (who builds the feature) and who is the reviewer (who looks at the PR). Halfway through you swap.
The author needs a GitHub repo that the reviewer has access to. The easiest way:
- The author creates a repo on GitHub (public).
- The author goes to Settings β Collaborators β Add people.
- The author invites the reviewer with their GitHub username.
- The reviewer accepts the invitation (via email or GitHub notifications).
Now you can both push to the same repo.
Alternative (without collaborator access): the reviewer forks the author’s repo and opens a PR from the fork to the original. But today we keep it simple: direct collaborator access.
Step 1: Creating and pushing a feature branch (author)
The author clones the repo (if that hasn’t happened yet) and creates a feature branch:
git clone https://github.com/AUTEUR_USERNAME/ons-samenwerk-project.git
cd ons-samenwerk-project
git switch -c feature/groet-functie
Create a new file:
echo 'def groet(naam):' > groet.py
echo ' return f"Hallo {naam}!"' >> groet.py
Commit and push:
git add groet.py
git commit -m "Add groet function
Returns a greeting for the given name."
git push -u origin feature/groet-functie
Step 2: Opening a pull request (author)
- Go to your repo on GitHub.
- GitHub now shows a yellow bar: “feature/groet-functie had recent pushes”: click Compare & pull request. (If you don’t see the bar: click the Pull requests tab, then New pull request, choose
base: master β compare: feature/groet-functie.) - Write a clear title: “Add groet function”
- Write a description. A good PR description has three parts:
## What
A function `groet(naam)` that returns a greeting.
## Why
We need a reusable greeting for the user interface.
This stops us having to write the same string in
several places.
## How to test
```python
from groet import groet
print(groet("CoderDojo")) # "Hallo CoderDojo!"
5. Click **Create pull request**.
Your PR is now open. Everyone with access to the repo can see it. GitHub shows the diff: exactly which lines you added (green) and removed (red).
## Step 3: Reviewing a PR (reviewer)
The reviewer opens the PR on GitHub. These are the steps of a review:
### 1. Read the description
Do you understand what this PR does? If not, ask for clarification.
### 2. Look at the diff
Click the **Files changed** tab. GitHub shows every changed line. Look at:
- **Does the code work?** Would you run it yourself if you cloned it?
- **Is the style consistent?** The same naming conventions as the rest of the project?
- **Are there mistakes?** Typos, missing imports, logic errors?
- **Are there no secrets in it?** Passwords, API keys, tokens?
- **Is it understandable?** Can someone seeing this code for the first time follow what happens?
### 3. Give feedback
Click a line to add a comment. Be specific:
**Good feedback:**
> In `groet.py` line 2: what happens if `naam` is empty? Maybe add a default value?
**Bad feedback:**
> This isn't good.
### 4. Submit your review
Click **Review changes**. You have three options:
- **Comment**: just feedback, no decision.
- **Approve**: the code is good, it can be merged.
- **Request changes**: something has to change before the PR can be merged.
On your first review: choose **Approve** if everything looks good, or **Request changes** if you want something changed.
## Step 4: Handling feedback (author)
The reviewer left a comment. The author changes the code:
```bash
# Make sure you're on your feature branch
git switch feature/groet-functie
Change groet.py based on the feedback. For example:
def groet(naam="wereld"):
return f"Hallo {naam}!"
Commit and push:
git add groet.py
git commit -m "Add default parameter to groet function"
git push
The new commit automatically appears in the PR. The reviewer sees the update and can look again.
Step 5: Merging and cleaning up
If the reviewer has Approved, it’s time to merge.
On GitHub, in the PR, you click Merge pull request. Choose Create a merge commit (the default option). Click Confirm merge.
The feature branch is now merged into master. On GitHub you can delete the branch with the Delete branch button that appears after merging.
Locally you have to clean up too:
git switch master
git pull # fetch the merge that just happened on GitHub
git branch -d feature/groet-functie # delete the local branch
Your master is now up to date. Your feature branch is gone, locally and on GitHub. Ready for the next piece of work.
The full PR workflow at a glance
1. git switch -c feature/iets β Create a feature branch
2. Work, commit, work, commit
3. git push -u origin feature/iets β Push to GitHub
4. Open a PR on GitHub β Ask for a review
5. Reviewer looks, gives feedback
6. Change code, commit, push β Handle feedback
7. Reviewer approved
8. Merge the PR on GitHub β Code to master
9. git switch master && git pull β Bring master up to date locally
10. git branch -d feature/iets β Clean up the branch
Reviewing someone else’s PR: how do you do that well?
A review is not: “Looks good.” A good review is specific, constructive and respectful.
Questions you ask yourself during a review:
- Do I understand what this code does? (If not: ask for better comments or a clearer description.)
- Does the code do what the PR description promises?
- Can this be simpler?
- Is anything missing? (Error handling, edge cases, documentation)
- Are there secrets, passwords or personal data in it?
- Does the code follow the style of the rest of the project?
How to give feedback:
Start with what’s good. Then be specific about what could be better. End with a clear conclusion.
Example:
The function works exactly as described. Two suggestions:
- On line 2: a default value for
naam would be handy. - Consider adding a docstring that explains what the function returns.
Other than that it looks good. If you change these two things, I’ll gladly approve it.
Showcase
Swap roles with your buddy and do the whole workflow once more: now you are the reviewer.
Show a coach:
- An open pull request on GitHub with a description.
- At least one review comment on a buddy’s PR.
- A successfully merged PR: the feature code is now on
master.
See you next time!
This was the last Git session. What you can do now:
- Version-control your code with Git (
init, add, commit, log, diff) - Experiment on branches without breaking
master (branch, switch, merge) - Share your code online via GitHub (
push, pull, clone) - Write professional commit messages
- Work together via pull requests: opening and reviewing
This is not “extra”. This is how developers work every day. Whether you make games, build websites, or train AI: Git and GitHub are the tools that keep your project manageable. Use them.
Take it home
- Easy: Open a pull request for a change in one of your own projects.
- Medium: Ask a friend or family member to make a GitHub account. Invite them as a collaborator and let them review a PR.
- Hard: Contribute to a real open source project. Search GitHub for issues with the
good first issue label. Fork the repo, make a fix, and open a PR. - Very hard: Build a small project with two others. Use branches, pull requests and reviews. Work as if you’re in a professional team.
Session 16: Markdown: Write notes that look like the web
You might know HTML from the internet: <h1>, <p>, <a>. But for notes and documentation HTML is far too much typing. That’s what Markdown is for.
Markdown is a mini-language you write in plain text. It looks readable without having to convert it first. And with one push of a button it becomes neat HTML: headings, lists, links, tables.
In this session you learn the whole basis of Markdown. At the end you write notes that look professional, on GitHub, in Obsidian, or in any other program that understands Markdown.
What you’ll learn today
- Making headings and paragraphs
- Formatting text: bold, italic, strikethrough
- Lists and bullet points
- Links to other pages and websites
- Adding images
- Making tables
- Horizontal lines and code blocks
Why Markdown?
Markdown is everywhere:
- GitHub: every repo has a
README.md in Markdown. Issues, pull requests, wikis: all Markdown. - Obsidian, Joplin, Logseq: note-taking apps that save your documents as
.md files. - Discord, Slack, Reddit: support Markdown for quick formatting in messages.
- Hugo (this website!): all the session pages you see here are written in Markdown.
- Jupyter Notebooks: the text cells are Markdown.
The big advantage: you write plain text. No complicated tags. And the result is always readable, even as plain text.
Step 0: Creating a Markdown file
Markdown files end in .md. Make one:
mkdir mijn-notities
cd mijn-notities
echo "# My First Note" > test.md
You can open .md files in any text editor: Notepad, VS Code, Thonny, Obsidian. VS Code has a built-in preview: click the icon with the magnifying glass and the book at the top right.
Step 1: Headings and paragraphs
You make headings with #. The more #, the smaller the heading:
# This is a title (h1)
## This is a subtitle (h2)
### This is a smaller heading (h3)
#### Even smaller (h4)
You make a paragraph by just typing text. A blank line between them starts a new paragraph:
This is the first paragraph. It just runs on.
This is the second paragraph. Because there's a blank line in between.
Tip: you use one # only once per document: for the title. The rest starts at ##.
Step 2: Formatting text
**This is bold**
*This is italic*
~~This is strikethrough~~
You can also **combine *bold and italic*** in the same sentence.
The result:
**bold** becomes bold*italic* becomes italic~~strikethrough~~ becomes strikethrough
Note: no spaces between the asterisks and the text. ** bold ** doesn’t work. **bold** does.
Some editors also accept underscores: __bold__ and _italic_. But asterisks are the standard: use those.
Step 3: Horizontal lines
You make a horizontal line with three (or more) dashes:
Or with asterisks:
The result is a line across the full width. Use it sparingly: one or two per document is enough. Too many lines make your notes messy.
Step 4: Lists
Unnumbered list
Use -, * or +:
- Python
- Git
- Markdown
- GitHub
You can nest lists by indenting (2 or 4 spaces):
- Programming languages
- Python
- JavaScript
- Version control
- Git
- GitHub
Numbered list
1. Open Thonny
2. Write your code
3. Click Run
It doesn’t matter which numbers you type: Markdown numbers automatically. This:
1. Step one
1. Step two
1. Step three
…gives exactly the same result as 1, 2, 3. Handy if you want to add a step later without renumbering everything.
Checklist (GitHub style)
- [x] Install Git
- [x] Make your first commit
- [ ] Learn branches
- [ ] Open a pull request
[x] is ticked, [ ] is open. Works in GitHub issues, pull requests, and many note-taking apps.
Step 5: Links
External links (to websites)
[click here for the CoderDojo site](https://python.coderdojohasselt.be)
The word between [ ] is the clickable text. The URL between ( ) is the destination.
Internal links (to other pages in your project)
[View session 11](11-git-intro/)
This links to the file 11-git-intro/_index.md in the same folder.
Quick link (show the URL directly)
This shows the URL as a clickable link, without separate text.
Step 6: Images
An image is almost the same as a link, but with a ! in front:

The text between [ ] is the alt text: it appears if the image doesn’t load, or is read out by screen readers.
Images and Git: Small images (SVG, small PNGs) you can put in Git. Big images (>1 MB) and videos better not, because they make your repo slow.
Step 7: Tables
| Command | What it does |
|----------|-------------|
| `git init` | Create a new repository |
| `git add` | Get files ready for a commit |
| `git commit` | Record changes |
| `git push` | Send commits to GitHub |
The | characters form the columns. The --- line separates the header from the data. The : in the separator line determines the alignment:
| Left aligned | Centred | Right aligned |
|:-----------------|:-----------:|------------------:|
| left | middle | right |
Step 8: Code and code blocks
Inline code
Use backticks for short pieces of code in a sentence:
Use `git status` to see what has changed.
Code blocks
For several lines of code you use three backticks:
```python
def groet(naam):
return f"Hallo {naam}!"
```
The language (python) after the first backticks gives syntax highlighting. This works for dozens of languages: bash, html, css, javascript, json, yaml, markdown.
Code block without a language
```
This is just text
without syntax highlighting
```
Step 9: Blockquotes
Use > for quotes or important remarks:
> Git is not a backup. Git is a time machine.
> Someone on the internet
Several > lines one after another form one block. An empty > line starts a new paragraph inside the quote.
Step 10: Everything together: a real README
A good README.md combines everything you know now. Here’s an example:
# My Project
A short description of what this project does.
## Installation
```bash
git clone https://github.com/jouw-naam/mijn-project.git
cd mijn-project
```
## Usage
1. Open `main.py` in Thonny.
2. Click **Run**.
3. Choose a level and start.
## What you'll learn
- [x] Pygame Zero basics
- [x] Collision detection
- [ ] Highscore system
- [ ] Sound effects
## Links
- [CoderDojo Hasselt](https://coderdojohasselt.be)
- [Source code on GitHub](https://github.com/jouw-naam/mijn-project)
Cheatsheet
| What | Markdown |
|---|
| Heading level 1 | # Title |
| Heading level 2 | ## Subtitle |
| Heading level 3 | ### Smaller heading |
| Bold | **bold** |
| Italic | *italic* |
| Strikethrough | ~~strikethrough~~ |
| Horizontal line | --- or *** |
| List (unordered) | - item |
| List (numbered) | 1. item |
| Checklist | - [ ] open item |
| Link | [text](url) |
| Image |  |
| Inline code | `code` |
| Code block | ```language |
| Quote | > quote |
| Table | | column | column | |
Showcase
Show a coach and a buddy:
- A Markdown document with at least one heading, a list, a link and bold text.
- A table with at least two columns and three rows.
- A checklist with ticked and open items.
See you next time!
Markdown is simple, but it’s everywhere. Your READMEs on GitHub, your notes in Obsidian, your documentation: everything becomes more readable with Markdown. Use it. Don’t overdo the formatting. Good notes are clear, not busy.
Take it home
- Easy: Write a
README.md for your favourite Python project. Use headings, a list and a code block. - Medium: Make a note in Obsidian (or another Markdown editor) about what you learned this month. Use all the formatting from the cheatsheet at least once.
- Hard: Build a “cheatsheet” page in Markdown for a topic of your choice (Git commands, Python syntax, maths formulas). Use tables and nested lists.
- Very hard: Make a Markdown document with a nested list that goes at least three levels deep, a table with alignment, and a code block with syntax highlighting.