Files
git-workshop/01_essentials/03-branching-and-merging/README.md
2026-01-11 14:50:40 +01:00

21 KiB

Module 03: Branching and Merging

About This Module

Welcome to Module 03! This module is different from the others - it uses a checkpoint system that lets you work through three related concepts in one continuous repository:

  1. Branching Basics - Create and work with feature branches
  2. Merging Branches - Combine branches together
  3. Resolving Merge Conflicts - Fix conflicts when Git can't merge automatically

Instead of three separate modules, you'll progress through checkpoints in a single Git repository, building on each previous section. You can jump between checkpoints, skip ahead, or restart any section at any time!

Why Checkpoints?

Branching, merging, and conflict resolution are naturally connected - you can't understand merging without branches, and you can't master conflicts without trying to merge. The checkpoint system lets you learn these concepts as a continuous workflow, just like real development.

Quick Start

Setup

Create the challenge environment:

.\setup.ps1

This creates a complete Git repository with all checkpoints ready.

Working with Checkpoints

View available checkpoints:

.\reset.ps1

Jump to a specific checkpoint:

.\reset.ps1 start           # Checkpoint 1: Branching Basics
.\reset.ps1 merge           # Checkpoint 2: Merging Branches
.\reset.ps1 merge-conflict  # Checkpoint 3: Resolving Conflicts

Verify your progress:

.\verify.ps1                 # Verify all checkpoints complete
.\verify.ps1 start           # Verify Checkpoint 1 only
.\verify.ps1 merge           # Verify Checkpoint 2 only
.\verify.ps1 merge-conflict  # Verify Checkpoint 3 only

Complete checkpoints in order:

  1. Start with Checkpoint 1 (Branching Basics)
  2. Progress to Checkpoint 2 (Merging)
  3. Finish with Checkpoint 3 (Merge Conflicts)

Or skip to any checkpoint if you already know the earlier concepts!


Checkpoint 1: Branching Basics

Learning Objectives

  • Understand what a branch is in Git
  • Create new branches with git switch -c
  • Switch between branches with git switch
  • View all branches with git branch
  • Understand that branches are independent lines of development

Your Task

Create a feature branch called feature-login, add a login.py file, and make commits to demonstrate that branches allow independent development.

Steps:

  1. Navigate to the challenge directory: cd challenge
  2. Create a new branch: git switch -c feature-login
  3. Create a file: login.py (with any content you like)
  4. Commit your file: git add login.py && git commit -m "Add login module"
  5. Make another change to login.py and commit it
  6. Switch back to main: git switch main
  7. Notice that login.py doesn't exist on main!
  8. Switch back to your feature: git switch feature-login
  9. Notice that login.py exists again!

Verify: Run .\verify.ps1 start to check your solution.

What is a Branch?

A branch in Git is an independent line of development. Think of it as a parallel universe for your code - you can make changes without affecting the main timeline.

Visual representation:

main:         A---B---C
                   \
feature-login:      D---E
  • Both branches share commits A and B
  • Branch main continues with commit C
  • Branch feature-login goes in a different direction with commits D and E
  • Changes in one branch don't affect the other!

Why Use Branches?

Branches let you:

  • Experiment safely - Try new ideas without breaking main
  • Work in parallel - Multiple features can be developed simultaneously
  • Organize work - Each feature/fix gets its own branch
  • Collaborate better - Team members work on separate branches

Key Concepts

  • Branch: A lightweight movable pointer to a commit
  • HEAD: A pointer showing which branch you're currently on
  • main: The default branch (formerly called "master")
  • Feature branch: A branch created for a specific feature or task

Useful Commands

# View all branches (current branch marked with *)
git branch

# Create a new branch
git branch feature-login

# Switch to a branch
git switch feature-login

# Create AND switch in one command
git switch -c feature-login

# Switch back to previous branch
git switch -

# Delete a branch (only if merged)
git branch -d feature-login

# Force delete a branch
git branch -D feature-login

Understanding HEAD

HEAD is Git's way of saying "you are here." It points to your current branch.

When you run git switch main, HEAD moves to point to main. When you run git switch feature-login, HEAD moves to point to feature-login.


Checkpoint 2: Merging Branches

Prerequisites: Complete Checkpoint 1 OR run .\reset.ps1 merge

Learning Objectives

  • Understand what merging means in Git
  • Merge a feature branch back into main
  • Use git merge to combine branches
  • Understand merge commits
  • Visualize merged branches with git log --graph

Your Task

You've completed work on your feature-login branch. Now merge it back into main to include the login functionality in your main codebase.

Scenario:

  • You created the feature-login branch and added login functionality
  • Meanwhile, development continued on main (README and app.py were added)
  • Now you need to merge your login feature into main

Steps:

  1. Make sure you're in the challenge directory: cd challenge
  2. Check which branch you're on: git branch
  3. Switch to main if needed: git switch main
  4. View the branch structure: git log --oneline --graph --all
  5. Merge feature-login into main: git merge feature-login
  6. View the result: git log --oneline --graph --all

Verify: Run .\verify.ps1 merge to check your solution.

What is Merging?

Merging is the process of combining changes from one branch into another.

Think of it like combining two streams into one river - all the water (code) flows together.

Before Merging

You have two branches with different work:

main:         A---B---C---D
                   \
feature-login:      E---F
  • Main branch progressed with commits C and D
  • Feature-login branch has commits E and F
  • They diverged at commit B

After Merging

You bring the feature branch into main:

main:         A---B---C---D---M
                   \       /
feature-login:      E-----F
  • Commit M is a merge commit - it combines both branches
  • Main now has all the work from both branches
  • Your login feature is now part of main!

How to Merge

Merging is simple - just two steps:

1. Switch to the branch you want to merge INTO:

git switch main

This is the branch that will receive the changes.

2. Merge the other branch:

git merge feature-login

This brings changes from feature-login into main.

That's it! Git automatically combines the changes.

Understanding Merge Commits

When you merge, Git creates a special commit called a merge commit.

What makes it special?

  • It has TWO parent commits (one from each branch)
  • It represents the point where branches come back together
  • The message typically says "Merge branch 'feature-login'"

See your merge commit:

git log --oneline

Look for the merge commit at the top - it will say something like:

abc1234 Merge branch 'feature-login'

Types of Merges

Three-way merge (what you just did):

  • Both branches have new commits
  • Git creates a merge commit
  • History shows both branches clearly

Fast-forward merge:

  • Main hasn't changed since the branch was created
  • Git just moves the main pointer forward
  • No merge commit needed!
# Before (fast-forward merge)
main:         A---B
                   \
feature:            C---D

# After (main just moves forward)
main:         A---B---C---D

Visualizing Branches

The --graph flag is your best friend:

git log --oneline --graph --all

What the graph shows:

  • * = A commit
  • | = A branch line
  • / and \ = Branches splitting/joining
  • Branch names in parentheses

Example output:

*   a1b2c3d (HEAD -> main) Merge branch 'feature-login'
|\
| * e4f5g6h (feature-login) Add password validation
| * i7j8k9l Add login module
* | m1n2o3p Add README documentation
* | q4r5s6t Add app.py entry point
|/
* u7v8w9x Add main functionality
* y1z2a3b Initial commit

Useful Commands

# Merge a branch into your current branch
git merge <branch-name>

# Abort a merge if something goes wrong
git merge --abort

# View merge commits only
git log --merges

# View branch structure
git log --oneline --graph --all

# See which branches have been merged into main
git branch --merged main

# See which branches haven't been merged
git branch --no-merged main

Checkpoint 3: Resolving Merge Conflicts

Prerequisites: Complete Checkpoint 2 OR run .\reset.ps1 merge-conflict

Learning Objectives

  • Understand what merge conflicts are and why they occur
  • Identify merge conflicts in your repository
  • Read and interpret conflict markers (<<<<<<<, =======, >>>>>>>)
  • Resolve merge conflicts manually
  • Complete a merge after resolving conflicts

Your Task

You have an update-config branch that modified config.json, and the main branch also modified config.json in a different way. When you try to merge, Git can't automatically combine them - you'll need to resolve the conflict manually.

Your mission:

  1. Attempt to merge the update-config branch into main
  2. Git will tell you there's a conflict - don't panic!
  3. Resolve the conflict by keeping BOTH settings (timeout AND debug)
  4. Complete the merge

Steps:

  1. Make sure you're in challenge directory: cd challenge
  2. Verify you're on main: git branch
  3. Try to merge: git merge update-config
  4. Git will report a conflict!
  5. Open config.json in your text editor
  6. Follow the resolution guide below
  7. Save the file
  8. Stage the resolved file: git add config.json
  9. Complete the merge: git commit

Verify: Run .\verify.ps1 merge-conflict to check your solution.

What Are Merge Conflicts?

A merge conflict occurs when Git cannot automatically combine changes because both branches modified the same part of the same file.

Example scenario:

main branch:    changes line 5 to: "timeout": 5000
update-config:  changes line 5 to: "debug": true

Git doesn't know which one you want (or if you want both)! So it asks you to decide.

When do conflicts happen?

  • Two branches modify the same lines in a file
  • One branch deletes a file that another branch modifies
  • Complex changes Git can't merge automatically
  • Different files are changed (no conflict!)
  • Different parts of the same file are changed (no conflict!)

Don't fear conflicts! They're a normal part of collaborative development. Git just needs your help to decide what the final code should look like.

Step-by-Step: Resolving Your First Conflict

Step 1: Attempt the Merge

cd challenge
git merge update-config

You'll see:

Auto-merging config.json
CONFLICT (content): Merge conflict in config.json
Automatic merge failed; fix conflicts and then commit the result.

Don't panic! This is normal. Git is just asking for your help.

Step 2: Check What Happened

git status

You'll see:

On branch main
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:   config.json

This tells you that config.json needs your attention!

Step 3: Open the Conflicted File

Open config.json in your text editor. You'll see special conflict markers:

{
  "app": {
    "name": "MyApp",
    "version": "1.0.0",
    "port": 3000,
<<<<<<< HEAD
    "timeout": 5000
=======
    "debug": true
>>>>>>> update-config
  }
}

Step 4: Understand the Conflict Markers

<<<<<<< HEAD
    "timeout": 5000        ← Your current branch (main)
=======
    "debug": true          ← The branch you're merging (update-config)
>>>>>>> update-config

What each marker means:

  • <<<<<<< HEAD - Start of your changes (current branch)
  • ======= - Separator between the two versions
  • >>>>>>> update-config - End of their changes (branch being merged)

Step 5: Decide What to Keep

You have three options:

Option 1: Keep ONLY your changes (timeout)

    "timeout": 5000

Option 2: Keep ONLY their changes (debug)

    "debug": true

Option 3: Keep BOTH changes ← This is what we want!

    "timeout": 5000,
    "debug": true

For this challenge, choose Option 3 - keep both settings!

Step 6: Edit the File

Delete ALL the conflict markers and keep both settings:

Before (with conflict markers):

{
  "app": {
    "name": "MyApp",
    "version": "1.0.0",
    "port": 3000,
<<<<<<< HEAD
    "timeout": 5000
=======
    "debug": true
>>>>>>> update-config
  }
}

After (resolved):

{
  "app": {
    "name": "MyApp",
    "version": "1.0.0",
    "port": 3000,
    "timeout": 5000,
    "debug": true
  }
}

Important:

  • Remove <<<<<<< HEAD
  • Remove =======
  • Remove >>>>>>> update-config
  • Keep both the timeout and debug settings
  • Ensure valid JSON syntax (notice the comma after timeout!)

Step 7: Save the File

Save config.json with your changes.

Step 8: Stage the Resolved File

Tell Git you've resolved the conflict:

git add config.json

Step 9: Check Status

git status

You'll see:

On branch main
All conflicts fixed but you are still merging.
  (use "git commit" to conclude merge)

Perfect! Git confirms the conflict is resolved.

Step 10: Complete the Merge

Commit the merge:

git commit

Git will open an editor with a default merge message. You can accept it or customize it.

Done! Your merge is complete!

Common Mistakes to Avoid

Forgetting to remove conflict markers

<<<<<<< HEAD     Don't leave these in!
    "timeout": 5000,
    "debug": true
>>>>>>> update-config     Don't leave these in!

This breaks your code! Always remove ALL markers.

Committing without staging

git commit    # Error! You didn't add the file

Always git add the resolved file first!

Keeping only one side when both are needed If you delete one setting, you lose that work. For this challenge, you need BOTH!

Breaking syntax

"timeout": 5000     Missing comma!
"debug": true

Always verify your file is valid after resolving!

Aborting a Merge

Changed your mind? You can abort the merge anytime:

git merge --abort

This returns your repository to the state before you started the merge. No harm done!

Useful Commands

# Attempt a merge
git merge <branch-name>

# Check which files have conflicts
git status

# Abort the merge and start over
git merge --abort

# After resolving conflicts:
git add <resolved-file>
git commit

# View conflicts in a different style
git diff --ours         # Your changes
git diff --theirs       # Their changes
git diff --base         # Original version

Pro Tips

💡 Prevent conflicts

  • Pull changes frequently: git pull
  • Communicate with your team about who's working on what
  • Keep branches short-lived and merge often

💡 Make conflicts easier

  • Work on different files when possible
  • If you must edit the same file, coordinate with teammates
  • Make small, focused commits

💡 When stuck

  • Read the conflict markers carefully
  • Look at git log to understand what each side changed
  • Ask a teammate to review your resolution
  • Use a merge tool: git mergetool

Complete Command Reference

Branching

git branch                     # List all branches
git branch feature-name        # Create a new branch
git switch branch-name         # Switch to a branch
git switch -c feature-name     # Create and switch
git switch -                   # Switch to previous branch
git branch -d feature-name     # Delete branch (if merged)
git branch -D feature-name     # Force delete branch

Merging

git merge branch-name          # Merge a branch into current branch
git merge --no-ff branch-name  # Force a merge commit
git merge --abort              # Abort a merge in progress
git log --merges               # View only merge commits

Viewing History

git log --oneline --graph --all         # Visual branch structure
git log --oneline                       # Compact commit list
git log --graph --decorate --all        # Detailed branch view
git log main..feature-login             # Commits in feature not in main
git diff main...feature-login           # Changes between branches

Conflict Resolution

git status                     # See conflicted files
git diff                       # View conflicts
git add resolved-file          # Mark file as resolved
git commit                     # Complete the merge
git merge --abort              # Give up and start over

Checkpoint Commands (This Module)

.\reset.ps1                    # Show available checkpoints
.\reset.ps1 start              # Jump to Checkpoint 1
.\reset.ps1 merge              # Jump to Checkpoint 2
.\reset.ps1 merge-conflict     # Jump to Checkpoint 3
.\verify.ps1                   # Verify all complete
.\verify.ps1 start             # Verify Checkpoint 1
.\verify.ps1 merge             # Verify Checkpoint 2
.\verify.ps1 merge-conflict    # Verify Checkpoint 3

Troubleshooting

"I'm on the wrong branch!"

git switch main           # Switch to main
git branch               # Verify current branch

"I made commits on the wrong branch!"

Don't panic! You can move them:

# You're on main but should be on feature-login
git switch feature-login     # Switch to correct branch
git merge main              # Bring the commits over
git switch main
git reset --hard HEAD~1     # Remove from main (careful!)

Or use cherry-pick (covered in a later module).

"The merge created a mess!"

Abort and try again:

git merge --abort
git status               # Verify you're back to clean state

"I want to start this checkpoint over!"

Use the reset script:

.\reset.ps1 start        # Go back to Checkpoint 1

This resets your repository to the beginning of that checkpoint.

"I can't find my branch!"

List all branches:

git branch --all         # Shows all branches including remote

The branch might have been deleted after merging (this is normal!).

"How do I know which checkpoint I'm on?"

.\reset.ps1              # Shows current checkpoint
git log --oneline --graph --all --decorate    # Shows all tags/branches

Real-World Workflow Example

Here's how professional developers use these skills:

Day 1: Start a new feature

git switch main
git pull                         # Get latest changes
git switch -c feature-dark-mode  # New feature branch
# ... make changes ...
git add .
git commit -m "Add dark mode toggle"

Day 2: Continue work

git switch feature-dark-mode     # Resume work
# ... make more changes ...
git add .
git commit -m "Add dark mode styles"

Day 3: Ready to merge

git switch main
git pull                         # Get latest main
git switch feature-dark-mode
git merge main                   # Bring main's changes into feature
# Resolve any conflicts
git switch main
git merge feature-dark-mode      # Merge feature into main
git push                         # Share with team
git branch -d feature-dark-mode  # Clean up

This is exactly what you just practiced!


What You've Learned

By completing all three checkpoints, you now understand:

Checkpoint 1: Branching Basics

  • Branches create independent lines of development
  • git switch -c creates and switches to a new branch
  • Changes in one branch don't affect others
  • Branches are lightweight and easy to create

Checkpoint 2: Merging Branches

  • Merging combines work from two branches
  • Merge commits have two parent commits
  • git merge brings changes into your current branch
  • Three-way merges create a merge commit

Checkpoint 3: Resolving Merge Conflicts

  • Conflicts happen when the same lines are changed differently
  • Conflict markers show both versions
  • You choose what the final code should look like
  • Conflicts are normal and easy to resolve with practice

Next Steps

Completed the module? Great work! You're ready to move on.

Want more practice? Jump to any checkpoint and try again:

.\reset.ps1 start        # Practice branching
.\reset.ps1 merge        # Practice merging
.\reset.ps1 merge-conflict    # Practice conflict resolution

Ready for the next module? Continue to Module 04 to learn about cherry-picking specific commits!


Need help? Review the relevant checkpoint section above, or run git status to see what Git suggests!