Files
git-workshop/01-essentials/03-branching-and-merging/README.md
2026-01-11 23:05:03 +01:00

840 lines
21 KiB
Markdown

# 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:
```bash
.\setup.ps1
```
This creates a complete Git repository with all checkpoints ready.
### Working with Checkpoints
**View available checkpoints:**
```bash
.\reset.ps1
```
**Jump to a specific checkpoint:**
```bash
.\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:**
```bash
.\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
```
### Recommended Workflow
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
```bash
# 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:**
```bash
git switch main
```
This is the branch that will receive the changes.
**2. Merge the other branch:**
```bash
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:**
```bash
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:
```bash
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
```bash
# 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
```bash
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
```bash
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**:
```json
{
"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)**
```json
"timeout": 5000
```
**Option 2: Keep ONLY their changes (debug)**
```json
"debug": true
```
**Option 3: Keep BOTH changes** ← This is what we want!
```json
"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):**
```json
{
"app": {
"name": "MyApp",
"version": "1.0.0",
"port": 3000,
<<<<<<< HEAD
"timeout": 5000
=======
"debug": true
>>>>>>> update-config
}
}
```
**After (resolved):**
```json
{
"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:
```bash
git add config.json
```
#### Step 9: Check Status
```bash
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:
```bash
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**
```json
<<<<<<< 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**
```bash
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**
```json
"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:
```bash
git merge --abort
```
This returns your repository to the state before you started the merge. No harm done!
### Useful Commands
```bash
# 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
```bash
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
```bash
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
```bash
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
```bash
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)
```bash
.\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!"
```bash
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:
```bash
# 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:
```bash
git merge --abort
git status # Verify you're back to clean state
```
### "I want to start this checkpoint over!"
Use the reset script:
```bash
.\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:
```bash
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?"
```bash
.\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**
```bash
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**
```bash
git switch feature-dark-mode # Resume work
# ... make more changes ...
git add .
git commit -m "Add dark mode styles"
```
**Day 3: Ready to merge**
```bash
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:
```bash
.\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!