diff --git a/module-04-merging/README.md b/module-04-merging/README.md new file mode 100644 index 0000000..11b87f5 --- /dev/null +++ b/module-04-merging/README.md @@ -0,0 +1,97 @@ +# Module 04: Merging + +## Learning Objectives + +In this module, you will: +- Understand what merging means in Git +- Perform a fast-forward merge +- Perform a three-way merge +- Understand when merge commits are created +- Use `git merge` to combine branches + +## Challenge + +### Setup + +Run the setup script to create your challenge environment: + +```powershell +.\setup.ps1 +``` + +This will create a `challenge/` directory with a Git repository that has a main branch and a feature branch ready to merge. + +### Your Task + +This challenge has two parts that teach you about the two types of merges in Git: + +**Part 1: Fast-Forward Merge** +1. Merge the existing `feature-api` branch into main +2. Observe that this is a "fast-forward" merge (no merge commit created) + +**Part 2: Three-Way Merge** +3. Create a new branch called `feature-ui` +4. Make commits on the feature-ui branch +5. Switch back to main and make a commit there too (creates divergence) +6. Merge feature-ui into main +7. Observe that this creates a merge commit (three-way merge) + +**Suggested Approach:** + +1. Navigate to the challenge directory: `cd challenge` +2. Check current branch: `git branch` (should be on main) +3. View existing branches: `git branch -a` +4. Merge feature-api: `git merge feature-api` +5. View the log: `git log --oneline --graph` +6. Create feature-ui branch: `git checkout -b feature-ui` +7. Create a new file `ui.py` and commit it +8. Make another commit on feature-ui (modify ui.py) +9. Switch back to main: `git checkout main` +10. Make a change on main (modify api.py) and commit it +11. Merge feature-ui: `git merge feature-ui` +12. View the merge history: `git log --oneline --graph --all` + +> **Important Notes:** +> - A **fast-forward merge** happens when main hasn't changed since the feature branch was created +> - A **three-way merge** creates a merge commit when both branches have diverged +> - You can see merge commits with `git log --merges` +> - The `--graph` option helps visualize the branch history +> - After merging, the feature branch still exists but you can delete it with `git branch -d` + +## Key Concepts + +- **Merge**: Combining changes from different branches into one branch. +- **Fast-Forward Merge**: When the target branch hasn't changed, Git simply moves the branch pointer forward. No merge commit is created. +- **Three-Way Merge**: When both branches have new commits, Git creates a merge commit that has two parent commits. +- **Merge Commit**: A special commit with two (or more) parent commits, representing the point where branches were merged. +- **Divergent Branches**: Branches that have different commits since they split from a common ancestor. + +## Useful Commands + +```bash +git merge # Merge branch into current branch +git log --oneline --graph # View merge history visually +git log --graph --all # View all branches and merges +git log --merges # Show only merge commits +git branch -d # Delete a merged branch (optional) +``` + +## Verification + +Once you've completed both merges, verify your solution: + +```powershell +.\verify.ps1 +``` + +The verification script will check that you've successfully merged both feature branches and understand the different merge types. + +## Need to Start Over? + +If you want to reset the challenge and start fresh: + +```powershell +.\reset.ps1 +``` + +This will remove the challenge directory and run the setup script again, giving you a clean slate. diff --git a/module-04-merging/reset.ps1 b/module-04-merging/reset.ps1 new file mode 100644 index 0000000..576a8fa --- /dev/null +++ b/module-04-merging/reset.ps1 @@ -0,0 +1,26 @@ +#!/usr/bin/env pwsh +<# +.SYNOPSIS + Resets the Module 04 challenge environment. + +.DESCRIPTION + This script removes the existing challenge directory and runs + the setup script again to create a fresh challenge environment. +#> + +Write-Host "`n=== Resetting Module 04 Challenge ===" -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" +} else { + Write-Host "No existing challenge directory found." -ForegroundColor Cyan +} + +Write-Host "" +Write-Host "----------------------------------------" -ForegroundColor Cyan +Write-Host "" + +# Run setup script +& "$PSScriptRoot\setup.ps1" diff --git a/module-04-merging/setup.ps1 b/module-04-merging/setup.ps1 new file mode 100644 index 0000000..230fc29 --- /dev/null +++ b/module-04-merging/setup.ps1 @@ -0,0 +1,128 @@ +#!/usr/bin/env pwsh +<# +.SYNOPSIS + Sets up the Module 04 challenge environment for learning about merging. + +.DESCRIPTION + This script creates a challenge directory with a Git repository that + contains a main branch and a feature branch ready to merge. Students + will practice both fast-forward and three-way merges. +#> + +Write-Host "`n=== Setting up Module 04 Challenge ===" -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" + +# Commit 1: Initial API file on main +Write-Host "Creating initial API structure on main..." -ForegroundColor Green +$apiContent = @" +# api.py - API module + +def api_handler(): + print("API Handler initialized") + return True +"@ +Set-Content -Path "api.py" -Value $apiContent + +git add . +git commit -m "Initial API setup" | Out-Null + +# Commit 2: Add more API functionality on main +$apiContent = @" +# api.py - API module + +def api_handler(): + print("API Handler initialized") + return True + +def get_data(): + print("Fetching data from API...") + return {"status": "ok"} +"@ +Set-Content -Path "api.py" -Value $apiContent + +git add . +git commit -m "Add get_data function" | Out-Null + +# Create feature-api branch and add commits +Write-Host "Creating feature-api branch..." -ForegroundColor Green +git checkout -b feature-api 2>$null | Out-Null + +# Commit on feature-api: Add API routes +$routesContent = @" +# api-routes.py - API Routes module + +def setup_routes(): + print("Setting up API routes...") + routes = { + "/api/data": "get_data", + "/api/status": "get_status" + } + return routes +"@ +Set-Content -Path "api-routes.py" -Value $routesContent + +git add . +git commit -m "Add API routes" | Out-Null + +# Second commit on feature-api: Enhance routes +$routesContent = @" +# api-routes.py - API Routes module + +def setup_routes(): + print("Setting up API routes...") + routes = { + "/api/data": "get_data", + "/api/status": "get_status", + "/api/health": "health_check" + } + return routes + +def health_check(): + return {"healthy": True} +"@ +Set-Content -Path "api-routes.py" -Value $routesContent + +git add . +git commit -m "Add health check route" | Out-Null + +# Switch back to main branch +Write-Host "Switching back to main branch..." -ForegroundColor Green +git checkout main 2>$null | 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 "`nYou have:" -ForegroundColor Cyan +Write-Host " - A main branch with API code" -ForegroundColor White +Write-Host " - A feature-api branch with API routes ready to merge" -ForegroundColor White +Write-Host "`nNext steps:" -ForegroundColor Cyan +Write-Host " 1. cd challenge" -ForegroundColor White +Write-Host " 2. View branches: git branch -a" -ForegroundColor White +Write-Host " 3. Merge feature-api: git merge feature-api (fast-forward merge)" -ForegroundColor White +Write-Host " 4. Create feature-ui branch: git checkout -b feature-ui" -ForegroundColor White +Write-Host " 5. Make commits on feature-ui" -ForegroundColor White +Write-Host " 6. Switch back to main and make a commit there" -ForegroundColor White +Write-Host " 7. Merge feature-ui: git merge feature-ui (three-way merge)" -ForegroundColor White +Write-Host " 8. View merge history: git log --oneline --graph --all" -ForegroundColor White +Write-Host " 9. Run '..\verify.ps1' to check your solution" -ForegroundColor White +Write-Host "" diff --git a/module-04-merging/verify.ps1 b/module-04-merging/verify.ps1 new file mode 100644 index 0000000..e01da32 --- /dev/null +++ b/module-04-merging/verify.ps1 @@ -0,0 +1,140 @@ +#!/usr/bin/env pwsh +<# +.SYNOPSIS + Verifies the Module 04 challenge solution. + +.DESCRIPTION + This script checks that: + - The challenge directory exists + - A Git repository exists + - Currently on main branch + - feature-api has been merged into main + - feature-ui branch exists and has been merged + - A merge commit exists (from three-way merge) +#> + +Write-Host "`n=== Verifying Module 04 Solution ===" -ForegroundColor Cyan + +$allChecksPassed = $true + +# Check if challenge directory exists +if (-not (Test-Path "challenge")) { + Write-Host "[FAIL] Challenge directory not found. Did you run setup.ps1?" -ForegroundColor Red + exit 1 +} + +Set-Location "challenge" + +# Check if git repository exists +if (-not (Test-Path ".git")) { + Write-Host "[FAIL] Not a git repository. Did you run setup.ps1?" -ForegroundColor Red + Set-Location .. + exit 1 +} + +# Check current branch is main +$currentBranch = git branch --show-current 2>$null +if ($currentBranch -eq "main") { + Write-Host "[PASS] Currently on main branch" -ForegroundColor Green +} else { + Write-Host "[FAIL] Not on main branch (currently on: $currentBranch)" -ForegroundColor Red + Write-Host "[HINT] Switch to main with: git checkout main" -ForegroundColor Yellow + $allChecksPassed = $false +} + +# Check if feature-api branch exists +$featureApiBranch = git branch --list "feature-api" 2>$null +if ($featureApiBranch) { + Write-Host "[PASS] Branch 'feature-api' exists" -ForegroundColor Green +} else { + Write-Host "[INFO] Branch 'feature-api' not found (may have been deleted after merge)" -ForegroundColor Cyan +} + +# Check if commits from feature-api are in main +$apiRoutesCommit = git log --all --grep="Add API routes" --oneline 2>$null +$healthCheckCommit = git log --all --grep="Add health check route" --oneline 2>$null + +if ($apiRoutesCommit -and $healthCheckCommit) { + # Check if these commits are in main's history + $apiRoutesInMain = git log --grep="Add API routes" --oneline 2>$null + $healthCheckInMain = git log --grep="Add health check route" --oneline 2>$null + + if ($apiRoutesInMain -and $healthCheckInMain) { + Write-Host "[PASS] Commits from feature-api are merged into main" -ForegroundColor Green + } else { + Write-Host "[FAIL] Commits from feature-api not found in main" -ForegroundColor Red + Write-Host "[HINT] Merge feature-api with: git merge feature-api" -ForegroundColor Yellow + $allChecksPassed = $false + } +} else { + Write-Host "[FAIL] Expected commits from feature-api not found" -ForegroundColor Red + Write-Host "[HINT] Did you run setup.ps1?" -ForegroundColor Yellow + $allChecksPassed = $false +} + +# Check if api-routes.py exists (should be on main after merge) +if (Test-Path "api-routes.py") { + Write-Host "[PASS] File 'api-routes.py' exists on main (from feature-api merge)" -ForegroundColor Green +} else { + Write-Host "[FAIL] File 'api-routes.py' not found on main" -ForegroundColor Red + Write-Host "[HINT] This file should appear after merging feature-api" -ForegroundColor Yellow + $allChecksPassed = $false +} + +# Check if feature-ui branch exists +$featureUiBranch = git branch --list "feature-ui" 2>$null +if ($featureUiBranch) { + Write-Host "[PASS] Branch 'feature-ui' exists" -ForegroundColor Green + + # Check if feature-ui has commits + $uiCommitCount = git rev-list main..feature-ui --count 2>$null + if ($uiCommitCount -gt 0) { + Write-Host "[INFO] Branch 'feature-ui' has $uiCommitCount commit(s)" -ForegroundColor Cyan + } +} else { + Write-Host "[FAIL] Branch 'feature-ui' not found" -ForegroundColor Red + Write-Host "[HINT] Create feature-ui with: git checkout -b feature-ui" -ForegroundColor Yellow + $allChecksPassed = $false +} + +# Check for merge commits (indicates three-way merge happened) +$mergeCommits = git log --merges --oneline 2>$null +if ($mergeCommits) { + Write-Host "[PASS] Merge commit(s) found (three-way merge completed)" -ForegroundColor Green +} else { + Write-Host "[FAIL] No merge commits found" -ForegroundColor Red + Write-Host "[HINT] Create divergence: make commits on both main and feature-ui, then merge" -ForegroundColor Yellow + $allChecksPassed = $false +} + +# Check if ui.py exists (should be on main after merge) +if (Test-Path "ui.py") { + Write-Host "[PASS] File 'ui.py' exists on main (from feature-ui merge)" -ForegroundColor Green +} else { + Write-Host "[FAIL] File 'ui.py' not found on main" -ForegroundColor Red + Write-Host "[HINT] Create ui.py on feature-ui branch and merge it into main" -ForegroundColor Yellow + $allChecksPassed = $false +} + +Set-Location .. + +# Final summary +if ($allChecksPassed) { + Write-Host "`n" -NoNewline + Write-Host "=====================================" -ForegroundColor Green + Write-Host " CONGRATULATIONS! CHALLENGE PASSED!" -ForegroundColor Green + Write-Host "=====================================" -ForegroundColor Green + Write-Host "`nYou've successfully learned about Git merging!" -ForegroundColor Cyan + Write-Host "You now understand:" -ForegroundColor Cyan + Write-Host " - Fast-forward merges (when main hasn't changed)" -ForegroundColor White + Write-Host " - Three-way merges (when branches have diverged)" -ForegroundColor White + Write-Host " - How to use git merge to combine branches" -ForegroundColor White + Write-Host " - Merge commits and how to view them" -ForegroundColor White + Write-Host "`nReady for the next module!" -ForegroundColor Green + Write-Host "" +} else { + Write-Host "`n[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 +}