refactor: rename 01_essentials to 01-essentials

This commit is contained in:
Bjarke Sporring
2026-01-11 23:05:03 +01:00
parent 8d63b2d22e
commit 5f78245734
54 changed files with 0 additions and 0 deletions

View File

@@ -0,0 +1,839 @@
# 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!

View File

@@ -0,0 +1,216 @@
#!/usr/bin/env pwsh
<#
.SYNOPSIS
Resets the challenge environment to a specific checkpoint.
.DESCRIPTION
This script allows you to jump to any checkpoint in the module,
resetting your repository to that state. Useful for skipping ahead,
starting over, or practicing specific sections.
.PARAMETER Checkpoint
The checkpoint to reset to: start, merge, or merge-conflict.
If not specified, displays help information.
.EXAMPLE
.\reset.ps1
Shows available checkpoints and current status.
.EXAMPLE
.\reset.ps1 start
Resets to the beginning (branching basics section).
.EXAMPLE
.\reset.ps1 merge
Jumps to the merging section (feature-login branch already exists).
.EXAMPLE
.\reset.ps1 merge-conflict
Jumps to the conflict resolution section (merge already complete).
#>
param(
[ValidateSet('start', 'merge', 'merge-conflict', '')]
[string]$Checkpoint = ''
)
# Checkpoint to tag mapping
$checkpointTags = @{
'start' = 'checkpoint-start'
'merge' = 'checkpoint-merge'
'merge-conflict' = 'checkpoint-merge-conflict'
}
# Checkpoint descriptions
$checkpointDescriptions = @{
'start' = 'Branching Basics - Create and work with feature branches'
'merge' = 'Merging Branches - Merge feature-login into main'
'merge-conflict' = 'Resolving Conflicts - Fix merge conflicts in config.json'
}
# ============================================================================
# Display help if no checkpoint specified
# ============================================================================
if ($Checkpoint -eq '') {
Write-Host "`n=== Module 03: Branching and Merging - Checkpoints ===" -ForegroundColor Cyan
Write-Host "`nAvailable checkpoints:" -ForegroundColor White
Write-Host ""
foreach ($key in @('start', 'merge', 'merge-conflict')) {
$desc = $checkpointDescriptions[$key]
Write-Host " $key" -ForegroundColor Green -NoNewline
Write-Host " - $desc" -ForegroundColor White
}
Write-Host "`nUsage:" -ForegroundColor Cyan
Write-Host " .\reset.ps1 <checkpoint>" -ForegroundColor White
Write-Host ""
Write-Host "Examples:" -ForegroundColor Cyan
Write-Host " .\reset.ps1 start # Start from the beginning" -ForegroundColor White
Write-Host " .\reset.ps1 merge # Jump to merging section" -ForegroundColor White
Write-Host " .\reset.ps1 merge-conflict # Jump to conflict resolution" -ForegroundColor White
Write-Host ""
# Try to detect current checkpoint
if (Test-Path "challenge/.git") {
Push-Location "challenge"
$currentBranch = git branch --show-current 2>$null
$currentCommit = git rev-parse HEAD 2>$null
# Check which checkpoint we're at
$currentCheckpoint = $null
foreach ($cp in @('start', 'merge', 'merge-conflict')) {
$tagCommit = git rev-parse $checkpointTags[$cp] 2>$null
if ($currentCommit -eq $tagCommit) {
$currentCheckpoint = $cp
break
}
}
if ($currentCheckpoint) {
Write-Host "Current checkpoint: " -ForegroundColor Yellow -NoNewline
Write-Host "$currentCheckpoint" -ForegroundColor Green -NoNewline
Write-Host " (on branch $currentBranch)" -ForegroundColor Yellow
} else {
Write-Host "Current status: " -ForegroundColor Yellow -NoNewline
Write-Host "In progress (on branch $currentBranch)" -ForegroundColor White
}
Pop-Location
}
Write-Host ""
exit 0
}
# ============================================================================
# Validate challenge directory exists
# ============================================================================
if (-not (Test-Path "challenge")) {
Write-Host "[ERROR] Challenge directory not found." -ForegroundColor Red
Write-Host "Run .\setup.ps1 first to create the challenge environment." -ForegroundColor Yellow
exit 1
}
if (-not (Test-Path "challenge/.git")) {
Write-Host "[ERROR] No git repository found in challenge directory." -ForegroundColor Red
Write-Host "Run .\setup.ps1 first to create the challenge environment." -ForegroundColor Yellow
exit 1
}
# Navigate to challenge directory
Push-Location "challenge"
# ============================================================================
# Verify the checkpoint tag exists
# ============================================================================
$targetTag = $checkpointTags[$Checkpoint]
$tagExists = git tag -l $targetTag
if (-not $tagExists) {
Write-Host "[ERROR] Checkpoint tag '$targetTag' not found." -ForegroundColor Red
Write-Host "Run ..\setup.ps1 to recreate the challenge environment." -ForegroundColor Yellow
Pop-Location
exit 1
}
# ============================================================================
# Check for uncommitted changes
# ============================================================================
$statusOutput = git status --porcelain 2>$null
if ($statusOutput) {
Write-Host "`n[WARNING] You have uncommitted changes!" -ForegroundColor Yellow
Write-Host "The following changes will be lost:" -ForegroundColor Yellow
Write-Host ""
git status --short
Write-Host ""
$response = Read-Host "Continue and discard all changes? (y/N)"
if ($response -ne 'y' -and $response -ne 'Y') {
Write-Host "`nReset cancelled." -ForegroundColor Cyan
Pop-Location
exit 0
}
}
# ============================================================================
# Reset to checkpoint
# ============================================================================
Write-Host "`nResetting to checkpoint: $Checkpoint" -ForegroundColor Cyan
Write-Host "Description: $($checkpointDescriptions[$Checkpoint])" -ForegroundColor White
Write-Host ""
try {
# Reset to the checkpoint tag
git reset --hard $targetTag 2>&1 | Out-Null
# Clean untracked files
git clean -fd 2>&1 | Out-Null
# Ensure we're on main branch
$currentBranch = git branch --show-current
if ($currentBranch -ne 'main') {
git switch main 2>&1 | Out-Null
git reset --hard $targetTag 2>&1 | Out-Null
}
Write-Host "[SUCCESS] Reset to checkpoint '$Checkpoint' complete!" -ForegroundColor Green
Write-Host ""
# Show what to do next
switch ($Checkpoint) {
'start' {
Write-Host "Next steps:" -ForegroundColor Cyan
Write-Host " 1. Create a new branch: git switch -c feature-login" -ForegroundColor White
Write-Host " 2. Create login.py and make 2+ commits" -ForegroundColor White
Write-Host " 3. Verify: ..\verify.ps1 start" -ForegroundColor White
}
'merge' {
Write-Host "Next steps:" -ForegroundColor Cyan
Write-Host " 1. View branch structure: git log --oneline --graph --all" -ForegroundColor White
Write-Host " 2. Merge feature-login: git merge feature-login" -ForegroundColor White
Write-Host " 3. Verify: ..\verify.ps1 merge" -ForegroundColor White
}
'merge-conflict' {
Write-Host "Next steps:" -ForegroundColor Cyan
Write-Host " 1. Attempt merge: git merge update-config" -ForegroundColor White
Write-Host " 2. Resolve conflicts in config.json" -ForegroundColor White
Write-Host " 3. Complete merge: git add config.json && git commit" -ForegroundColor White
Write-Host " 4. Verify: ..\verify.ps1 merge-conflict" -ForegroundColor White
}
}
Write-Host ""
Write-Host "View current state: git log --oneline --graph --all" -ForegroundColor Cyan
Write-Host ""
} catch {
Write-Host "[ERROR] Failed to reset to checkpoint." -ForegroundColor Red
Write-Host $_.Exception.Message -ForegroundColor Red
Pop-Location
exit 1
}
Pop-Location
exit 0

View File

@@ -0,0 +1,279 @@
#!/usr/bin/env pwsh
<#
.SYNOPSIS
Sets up the Module 03 checkpoint-based challenge environment.
.DESCRIPTION
This script creates a challenge directory with a complete Git repository
containing all commits and checkpoints for learning branching, merging,
and merge conflict resolution in one continuous workflow.
The script creates three checkpoints:
- checkpoint-start: Beginning of branching basics
- checkpoint-merge: Beginning of merging section
- checkpoint-merge-conflict: Beginning of conflict resolution
#>
Write-Host "`n=== Setting up Module 03: Branching and Merging ===" -ForegroundColor Cyan
# Remove existing challenge directory if it exists
if (Test-Path "challenge") {
Write-Host "Removing existing challenge directory..." -ForegroundColor Yellow
Remove-Item -Recurse -Force "challenge"
}
# Create fresh challenge directory
Write-Host "Creating challenge directory..." -ForegroundColor Green
New-Item -ItemType Directory -Path "challenge" | Out-Null
Set-Location "challenge"
# Initialize Git repository
Write-Host "Initializing Git repository..." -ForegroundColor Green
git init | Out-Null
# Configure git for this repository
git config user.name "Workshop Student"
git config user.email "student@example.com"
# ============================================================================
# PHASE 1: Branching Basics - Initial commits on main
# ============================================================================
Write-Host "`nPhase 1: Creating initial project structure..." -ForegroundColor Cyan
# Commit 1: Initial commit
$mainContent = @"
# main.py - Main application file
def main():
print("Welcome to the Application!")
print("This is the main branch")
if __name__ == "__main__":
main()
"@
Set-Content -Path "main.py" -Value $mainContent
git add .
git commit -m "Initial commit" | Out-Null
# Commit 2: Add main functionality
$mainContent = @"
# main.py - Main application file
def main():
print("Welcome to the Application!")
print("This is the main branch")
run_application()
def run_application():
print("Application is running...")
print("Ready for new features!")
if __name__ == "__main__":
main()
"@
Set-Content -Path "main.py" -Value $mainContent
git add .
git commit -m "Add main functionality" | Out-Null
# Tag checkpoint-start (students begin here - will create feature-login)
Write-Host "Creating checkpoint: start" -ForegroundColor Green
git tag checkpoint-start
# ============================================================================
# PHASE 2: Create feature-login branch (what students will do in checkpoint 1)
# ============================================================================
Write-Host "Phase 2: Creating feature-login branch..." -ForegroundColor Cyan
# Create and switch to feature-login branch
git switch -c feature-login | Out-Null
# Commit 3: Add login module
$loginContent = @"
# login.py - User login module
def login(username, password):
"""Authenticate a user."""
print(f"Authenticating user: {username}")
# TODO: Add actual authentication logic
return True
def logout(username):
"""Log out a user."""
print(f"Logging out user: {username}")
return True
"@
Set-Content -Path "login.py" -Value $loginContent
git add .
git commit -m "Add login module" | Out-Null
# Commit 4: Add password validation
$loginContent = @"
# login.py - User login module
def validate_password(password):
"""Validate password strength."""
if len(password) < 8:
return False
return True
def login(username, password):
"""Authenticate a user."""
if not validate_password(password):
print("Password too weak!")
return False
print(f"Authenticating user: {username}")
# TODO: Add actual authentication logic
return True
def logout(username):
"""Log out a user."""
print(f"Logging out user: {username}")
return True
"@
Set-Content -Path "login.py" -Value $loginContent
git add .
git commit -m "Add password validation" | Out-Null
# Switch back to main
git switch main | Out-Null
# Now create divergence - add commits to main while feature-login exists
Write-Host "Creating divergent history on main..." -ForegroundColor Cyan
# Commit 5: Add app.py with basic functionality
$appContent = @"
# app.py - Main application entry point
from main import main
def run():
"""Run the application."""
print("Starting application...")
main()
print("Application finished.")
if __name__ == "__main__":
run()
"@
Set-Content -Path "app.py" -Value $appContent
git add .
git commit -m "Add app.py entry point" | Out-Null
# Commit 6: Add README
$readmeContent = @"
# My Application
Welcome to my application!
## Features
- Main functionality
- More features coming soon
## Setup
Run: python app.py
"@
Set-Content -Path "README.md" -Value $readmeContent
git add .
git commit -m "Add README documentation" | Out-Null
# Tag checkpoint-merge (students begin merging here - divergent branches ready)
Write-Host "Creating checkpoint: merge" -ForegroundColor Green
git tag checkpoint-merge
# ============================================================================
# PHASE 3: Merge feature-login into main (what students will do in checkpoint 2)
# ============================================================================
Write-Host "Phase 3: Merging feature-login into main..." -ForegroundColor Cyan
# Merge feature-login into main (will create three-way merge commit)
git merge feature-login --no-edit | Out-Null
# ============================================================================
# PHASE 4: Create conflict scenario (what students will do in checkpoint 3)
# ============================================================================
Write-Host "Phase 4: Creating merge conflict scenario..." -ForegroundColor Cyan
# Create config.json file on main
$initialConfig = @"
{
"app": {
"name": "MyApp",
"version": "1.0.0",
"port": 3000
}
}
"@
Set-Content -Path "config.json" -Value $initialConfig
git add config.json
git commit -m "Add initial configuration" | Out-Null
# On main branch: Add timeout setting
$mainConfig = @"
{
"app": {
"name": "MyApp",
"version": "1.0.0",
"port": 3000,
"timeout": 5000
}
}
"@
Set-Content -Path "config.json" -Value $mainConfig
git add config.json
git commit -m "Add timeout configuration" | Out-Null
# Create update-config branch from the commit before timeout was added
git switch -c update-config HEAD~1 | Out-Null
# On update-config branch: Add debug setting (conflicting change)
$featureConfig = @"
{
"app": {
"name": "MyApp",
"version": "1.0.0",
"port": 3000,
"debug": true
}
}
"@
Set-Content -Path "config.json" -Value $featureConfig
git add config.json
git commit -m "Add debug mode configuration" | Out-Null
# Switch back to main
git switch main | Out-Null
# Tag checkpoint-merge-conflict (students begin conflict resolution here - on main with timeout, update-config has debug)
Write-Host "Creating checkpoint: merge-conflict" -ForegroundColor Green
git tag checkpoint-merge-conflict
# ============================================================================
# Reset to checkpoint-start so students begin at the beginning
# ============================================================================
Write-Host "`nResetting to checkpoint-start..." -ForegroundColor Yellow
git reset --hard checkpoint-start | Out-Null
git clean -fd | Out-Null
# Return to module directory
Set-Location ..
Write-Host "`n=== Setup Complete! ===" -ForegroundColor Green
Write-Host "`nYour challenge environment is ready in the 'challenge/' directory." -ForegroundColor Cyan
Write-Host "`nThis module uses a CHECKPOINT SYSTEM:" -ForegroundColor Yellow
Write-Host " You'll work through 3 sections in one continuous repository:" -ForegroundColor White
Write-Host " 1. Branching Basics (checkpoint: start)" -ForegroundColor White
Write-Host " 2. Merging Branches (checkpoint: merge)" -ForegroundColor White
Write-Host " 3. Resolving Merge Conflicts (checkpoint: merge-conflict)" -ForegroundColor White
Write-Host "`nCommands:" -ForegroundColor Cyan
Write-Host " .\reset.ps1 - Show available checkpoints" -ForegroundColor White
Write-Host " .\reset.ps1 start - Jump to branching section" -ForegroundColor White
Write-Host " .\reset.ps1 merge - Jump to merging section" -ForegroundColor White
Write-Host " .\verify.ps1 - Verify all sections complete" -ForegroundColor White
Write-Host " .\verify.ps1 start - Verify only branching section" -ForegroundColor White
Write-Host "`nNext steps:" -ForegroundColor Cyan
Write-Host " 1. Read the README.md for detailed instructions" -ForegroundColor White
Write-Host " 2. cd challenge" -ForegroundColor White
Write-Host " 3. Start with Checkpoint 1: Branching Basics" -ForegroundColor White
Write-Host ""

View File

@@ -0,0 +1,320 @@
#!/usr/bin/env pwsh
<#
.SYNOPSIS
Verifies the Module 03 challenge solution (checkpoint-aware).
.DESCRIPTION
This script can verify completion of individual checkpoints or
the entire module. Without arguments, it verifies all checkpoints.
.PARAMETER Checkpoint
The checkpoint to verify: start, merge, or merge-conflict.
If not specified, verifies all checkpoints.
.EXAMPLE
.\verify.ps1
Verifies all three checkpoints are complete.
.EXAMPLE
.\verify.ps1 start
Verifies only the branching basics checkpoint.
.EXAMPLE
.\verify.ps1 merge
Verifies only the merging checkpoint.
#>
param(
[ValidateSet('start', 'merge', 'merge-conflict', '')]
[string]$Checkpoint = ''
)
$script:allChecksPassed = $true
# ============================================================================
# Helper Functions
# ============================================================================
function Write-Pass {
param([string]$Message)
Write-Host "[PASS] $Message" -ForegroundColor Green
}
function Write-Fail {
param([string]$Message)
Write-Host "[FAIL] $Message" -ForegroundColor Red
$script:allChecksPassed = $false
}
function Write-Hint {
param([string]$Message)
Write-Host "[HINT] $Message" -ForegroundColor Yellow
}
# ============================================================================
# Checkpoint 1: Branching Basics Verification
# ============================================================================
function Verify-Branching {
Write-Host "`n=== Checkpoint 1: Branching Basics ===" -ForegroundColor Cyan
# Save current branch
$originalBranch = git branch --show-current 2>$null
# Check if feature-login branch exists
$branchExists = git branch --list "feature-login" 2>$null
if ($branchExists) {
Write-Pass "Branch 'feature-login' exists"
} else {
Write-Fail "Branch 'feature-login' not found"
Write-Hint "Create the branch with: git switch -c feature-login"
return
}
# Check if feature-login has commits beyond main (or if they've been merged)
$commitCount = git rev-list main..feature-login --count 2>$null
$mergeCommitExists = (git log --merges --oneline 2>$null | Select-String "Merge.*feature-login")
if ($mergeCommitExists -and $commitCount -eq 0) {
# Commits were merged into main - this is correct!
Write-Pass "Branch 'feature-login' commits have been merged into main"
} elseif ($commitCount -ge 2) {
Write-Pass "Branch 'feature-login' has $commitCount new commits"
} else {
Write-Fail "Branch 'feature-login' needs at least 2 new commits (found: $commitCount)"
Write-Hint "Make sure you've committed login.py and made at least one more commit"
}
# Switch to feature-login and check for login.py
git switch feature-login 2>$null | Out-Null
if (Test-Path "login.py") {
Write-Pass "File 'login.py' exists in feature-login branch"
} else {
Write-Fail "File 'login.py' not found in feature-login branch"
Write-Hint "Create login.py and commit it to the feature-login branch"
}
# Switch to main and verify login.py doesn't exist there yet (unless merged)
git switch main 2>$null | Out-Null
# Check if merge happened - if so, login.py can exist on main
$mergeCommitExists = (git log --merges --oneline 2>$null | Select-String "Merge.*feature-login")
if (-not $mergeCommitExists) {
# No merge yet - login.py should NOT be on main
if (-not (Test-Path "login.py")) {
Write-Pass "File 'login.py' does NOT exist in main branch (branches are independent!)"
} else {
Write-Fail "File 'login.py' should not exist in main branch yet (before merge)"
Write-Hint "Make sure you created login.py only on the feature-login branch"
}
}
# Switch back to original branch
if ($originalBranch) {
git switch $originalBranch 2>$null | Out-Null
}
}
# ============================================================================
# Checkpoint 2: Merging Verification
# ============================================================================
function Verify-Merging {
Write-Host "`n=== Checkpoint 2: Merging Branches ===" -ForegroundColor Cyan
# Check current branch is main
$currentBranch = git branch --show-current 2>$null
if ($currentBranch -eq "main") {
Write-Pass "Currently on main branch"
} else {
Write-Fail "Should be on main branch (currently on: $currentBranch)"
Write-Hint "Switch to main with: git switch main"
}
# Check if login.py exists on main (indicates merge happened)
if (Test-Path "login.py") {
Write-Pass "File 'login.py' exists on main branch (merged successfully)"
} else {
Write-Fail "File 'login.py' not found on main branch"
Write-Hint "Merge feature-login into main with: git merge feature-login"
}
# Check for merge commit
$mergeCommitExists = (git log --merges --oneline 2>$null | Select-String "Merge.*feature-login")
if ($mergeCommitExists) {
Write-Pass "Merge commit exists"
} else {
Write-Fail "No merge commit found"
Write-Hint "Create a merge commit with: git merge feature-login"
}
# Check commit count (should have both branches' commits)
$commitCount = [int](git rev-list --count HEAD 2>$null)
if ($commitCount -ge 6) {
Write-Pass "Repository has $commitCount commits (merge complete)"
} else {
Write-Fail "Repository should have at least 6 commits after merge (found: $commitCount)"
}
}
# ============================================================================
# Checkpoint 3: Merge Conflicts Verification
# ============================================================================
function Verify-MergeConflicts {
Write-Host "`n=== Checkpoint 3: Resolving Merge Conflicts ===" -ForegroundColor Cyan
# Check current branch is main
$currentBranch = git branch --show-current 2>$null
if ($currentBranch -eq "main") {
Write-Pass "Currently on main branch"
} else {
Write-Fail "Should be on main branch (currently on: $currentBranch)"
Write-Hint "Switch to main with: git switch main"
}
# Check that merge is not in progress
if (Test-Path ".git/MERGE_HEAD") {
Write-Fail "Merge is still in progress (conflicts not resolved)"
Write-Hint "Resolve conflicts in config.json, then: git add config.json && git commit"
return
} else {
Write-Pass "No merge in progress (conflicts resolved)"
}
# Check if config.json exists
if (Test-Path "config.json") {
Write-Pass "File 'config.json' exists"
} else {
Write-Fail "File 'config.json' not found"
Write-Hint "Merge update-config branch with: git merge update-config"
return
}
# Verify config.json is valid JSON
try {
$configContent = Get-Content "config.json" -Raw
$config = $configContent | ConvertFrom-Json -ErrorAction Stop
Write-Pass "File 'config.json' is valid JSON"
} catch {
Write-Fail "File 'config.json' is not valid JSON"
Write-Hint "Make sure you removed all conflict markers (<<<<<<<, =======, >>>>>>>)"
return
}
# Check for conflict markers
if ($configContent -match '<<<<<<<|=======|>>>>>>>') {
Write-Fail "Conflict markers still present in config.json"
Write-Hint "Remove all conflict markers (<<<<<<<, =======, >>>>>>>)"
return
} else {
Write-Pass "No conflict markers in config.json"
}
# Verify both settings are present (timeout and debug)
if ($config.app.timeout -eq 5000) {
Write-Pass "Timeout setting preserved (5000)"
} else {
Write-Fail "Timeout setting missing or incorrect"
Write-Hint "Keep the timeout: 5000 setting from main branch"
}
if ($config.app.debug -eq $true) {
Write-Pass "Debug setting preserved (true)"
} else {
Write-Fail "Debug setting missing or incorrect"
Write-Hint "Keep the debug: true setting from update-config branch"
}
# Verify merge commit exists for update-config
$updateConfigMerge = (git log --merges --oneline 2>$null | Select-String "Merge.*update-config")
if ($updateConfigMerge) {
Write-Pass "Merge commit exists for update-config branch"
} else {
Write-Fail "No merge commit found for update-config"
Write-Hint "Complete the merge with: git commit (after resolving conflicts)"
}
}
# ============================================================================
# Main Script Logic
# ============================================================================
# Check if challenge directory exists
if (-not (Test-Path "challenge")) {
Write-Host "[ERROR] Challenge directory not found." -ForegroundColor Red
Write-Host "Run .\setup.ps1 first to create the challenge environment." -ForegroundColor Yellow
exit 1
}
Push-Location "challenge"
# Check if git repository exists
if (-not (Test-Path ".git")) {
Write-Host "[ERROR] Not a git repository." -ForegroundColor Red
Write-Host "Run ..\setup.ps1 first to create the challenge environment." -ForegroundColor Yellow
Pop-Location
exit 1
}
# Run appropriate verification
if ($Checkpoint -eq '') {
# Verify all checkpoints
Write-Host "`n=== Verifying All Checkpoints ===" -ForegroundColor Cyan
Verify-Branching
Verify-Merging
Verify-MergeConflicts
} else {
# Verify specific checkpoint
switch ($Checkpoint) {
'start' { Verify-Branching }
'merge' { Verify-Merging }
'merge-conflict' { Verify-MergeConflicts }
}
}
Pop-Location
# Final summary
Write-Host ""
if ($script:allChecksPassed) {
Write-Host "=========================================" -ForegroundColor Green
Write-Host " CONGRATULATIONS! CHALLENGE PASSED!" -ForegroundColor Green
Write-Host "=========================================" -ForegroundColor Green
if ($Checkpoint -eq '') {
Write-Host "`nYou've completed the entire module!" -ForegroundColor Cyan
Write-Host "You've mastered:" -ForegroundColor Cyan
Write-Host " ✓ Creating and working with branches" -ForegroundColor White
Write-Host " ✓ Merging branches together" -ForegroundColor White
Write-Host " ✓ Resolving merge conflicts" -ForegroundColor White
Write-Host "`nReady for the next module!" -ForegroundColor Green
} else {
Write-Host "`nCheckpoint '$Checkpoint' complete!" -ForegroundColor Cyan
switch ($Checkpoint) {
'start' {
Write-Host "Next: Move to the merging checkpoint" -ForegroundColor White
Write-Host " ..\reset.ps1 merge OR continue to merge feature-login" -ForegroundColor Yellow
}
'merge' {
Write-Host "Next: Move to the conflict resolution checkpoint" -ForegroundColor White
Write-Host " ..\reset.ps1 merge-conflict" -ForegroundColor Yellow
}
'merge-conflict' {
Write-Host "Module complete! Ready for the next module!" -ForegroundColor Green
}
}
}
Write-Host ""
exit 0
} else {
Write-Host "[SUMMARY] Some checks failed. Review the hints above and try again." -ForegroundColor Red
Write-Host "[INFO] You can run this verification script as many times as needed." -ForegroundColor Yellow
Write-Host ""
exit 1
}