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:

git branch

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:

git log --oneline

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:

git switch master

Look at what is here:

ls

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:

git switch 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:

ls
git log --oneline

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:

HIGHSCORE: 500

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 branchNo branch
New feature that takes timeFixing a typo in a comment
Experiment you don’t know will workSmall bugfix of one line
Something that can break your working codeYou 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

  1. 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.
  2. One thing per branch. “Add highscore” is a good branch. “Add highscore, menu, and new levels” is too much: split it up.
  3. Merge often. When you finish your feature, merge it back into master straight away. Small, frequent merges are easier than one big monster merge.
  4. Give branches clear names. highscore-feature is good. test123 or branch2 are bad. In a week you won’t remember what was in test123.
  5. 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:

  1. git branch with at least two branches (including master).
  2. A different file or different code on each branch.
  3. Switching back and forth: the files appear and disappear.
  4. 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

  1. Easy: Make a branch for a small feature in an existing project. Commit your work and merge it back.
  2. Medium: Deliberately create a merge conflict (two branches that change the same file) and solve it.
  3. 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.
  4. 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.