feat: add initial module 05
This commit is contained in:
106
module-05-conflicts/README.md
Normal file
106
module-05-conflicts/README.md
Normal file
@@ -0,0 +1,106 @@
|
|||||||
|
# Module 05: Merge Conflicts
|
||||||
|
|
||||||
|
## Learning Objectives
|
||||||
|
|
||||||
|
In this module, you will:
|
||||||
|
- Understand what merge conflicts are and why they occur
|
||||||
|
- Recognize conflict markers in files
|
||||||
|
- Manually resolve merge conflicts
|
||||||
|
- Complete a merge after resolving conflicts
|
||||||
|
- Use `git status` to identify conflicted files
|
||||||
|
|
||||||
|
## 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 conflicting changes on two branches.
|
||||||
|
|
||||||
|
### Your Task
|
||||||
|
|
||||||
|
You will intentionally create and resolve a merge conflict - a crucial skill for collaborative development!
|
||||||
|
|
||||||
|
**The Scenario:**
|
||||||
|
- The `main` branch and `feature-updates` branch both modified the same lines in `app.py`
|
||||||
|
- When you try to merge them, Git can't automatically resolve the differences
|
||||||
|
- You must manually resolve the conflict
|
||||||
|
|
||||||
|
**Steps:**
|
||||||
|
|
||||||
|
1. Navigate to the challenge directory: `cd challenge`
|
||||||
|
2. Verify you're on main: `git branch`
|
||||||
|
3. Attempt to merge feature-updates: `git merge feature-updates`
|
||||||
|
4. Git will report a conflict! Don't panic - this is expected
|
||||||
|
5. Check status: `git status` (shows conflicted files)
|
||||||
|
6. Open `app.py` in a text editor
|
||||||
|
7. Look for conflict markers:
|
||||||
|
```
|
||||||
|
<<<<<<< HEAD
|
||||||
|
(your current branch's version)
|
||||||
|
=======
|
||||||
|
(the other branch's version)
|
||||||
|
>>>>>>> feature-updates
|
||||||
|
```
|
||||||
|
8. Manually resolve by editing the file:
|
||||||
|
- Remove the conflict markers (`<<<<<<<`, `=======`, `>>>>>>>`)
|
||||||
|
- Keep the version you want, or combine both changes
|
||||||
|
9. Save the file
|
||||||
|
10. Mark as resolved: `git add app.py`
|
||||||
|
11. Complete the merge: `git commit`
|
||||||
|
12. View the result: `git log --oneline --graph`
|
||||||
|
|
||||||
|
> **Important Notes:**
|
||||||
|
> - Conflicts occur when the **same lines** are changed differently in both branches
|
||||||
|
> - Conflict markers show both versions - you choose what to keep
|
||||||
|
> - You can keep one version, the other, or combine them creatively
|
||||||
|
> - After editing, you MUST `git add` to mark the conflict as resolved
|
||||||
|
> - Then `git commit` to complete the merge
|
||||||
|
> - Use `git merge --abort` if you want to cancel and start over
|
||||||
|
|
||||||
|
## Key Concepts
|
||||||
|
|
||||||
|
- **Merge Conflict**: Occurs when the same lines in a file are changed differently in both branches being merged.
|
||||||
|
- **Conflict Markers**: Special markers Git inserts to show the conflicting versions:
|
||||||
|
- `<<<<<<< HEAD`: Marks the start of your current branch's changes
|
||||||
|
- `=======`: Separates the two conflicting versions
|
||||||
|
- `>>>>>>> branch-name`: Marks the end of the other branch's changes
|
||||||
|
- **Conflict Resolution**: The process of manually editing the file to resolve the differences and remove conflict markers.
|
||||||
|
- **Staging Resolution**: Using `git add` to tell Git you've resolved the conflict.
|
||||||
|
|
||||||
|
## Useful Commands
|
||||||
|
|
||||||
|
```bash
|
||||||
|
git merge <branch> # Attempt merge (may cause conflict)
|
||||||
|
git status # See which files have conflicts
|
||||||
|
git diff # View conflicts in detail
|
||||||
|
cat <file> # View file with conflict markers
|
||||||
|
git add <file> # Mark conflict as resolved
|
||||||
|
git commit # Complete the merge
|
||||||
|
git commit -m "message" # Complete merge with message
|
||||||
|
git merge --abort # Cancel merge and go back
|
||||||
|
```
|
||||||
|
|
||||||
|
## Verification
|
||||||
|
|
||||||
|
Once you've resolved the conflict and completed the merge, verify your solution:
|
||||||
|
|
||||||
|
```powershell
|
||||||
|
.\verify.ps1
|
||||||
|
```
|
||||||
|
|
||||||
|
The verification script will check that you've successfully resolved the conflict and completed the merge.
|
||||||
|
|
||||||
|
## 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.
|
||||||
26
module-05-conflicts/reset.ps1
Normal file
26
module-05-conflicts/reset.ps1
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
#!/usr/bin/env pwsh
|
||||||
|
<#
|
||||||
|
.SYNOPSIS
|
||||||
|
Resets the Module 05 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 05 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"
|
||||||
124
module-05-conflicts/setup.ps1
Normal file
124
module-05-conflicts/setup.ps1
Normal file
@@ -0,0 +1,124 @@
|
|||||||
|
#!/usr/bin/env pwsh
|
||||||
|
<#
|
||||||
|
.SYNOPSIS
|
||||||
|
Sets up the Module 05 challenge environment for learning about merge conflicts.
|
||||||
|
|
||||||
|
.DESCRIPTION
|
||||||
|
This script creates a challenge directory with a Git repository that
|
||||||
|
contains conflicting changes on two branches. Students will practice
|
||||||
|
resolving merge conflicts.
|
||||||
|
#>
|
||||||
|
|
||||||
|
Write-Host "`n=== Setting up Module 05 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"
|
||||||
|
|
||||||
|
# Create initial app.py with clear line numbers
|
||||||
|
Write-Host "Creating initial application..." -ForegroundColor Green
|
||||||
|
$initialContent = @"
|
||||||
|
# app.py - Main application
|
||||||
|
|
||||||
|
def main():
|
||||||
|
print("Application starting...")
|
||||||
|
# Lines 5-7 will be modified differently on each branch
|
||||||
|
print("Version: 1.0")
|
||||||
|
print("Status: Development")
|
||||||
|
print("Mode: Standard")
|
||||||
|
# End of conflicting section
|
||||||
|
print("Application ready!")
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
||||||
|
"@
|
||||||
|
Set-Content -Path "app.py" -Value $initialContent
|
||||||
|
|
||||||
|
git add .
|
||||||
|
git commit -m "Initial application setup" | Out-Null
|
||||||
|
|
||||||
|
# Create feature-updates branch
|
||||||
|
Write-Host "Creating feature-updates branch..." -ForegroundColor Green
|
||||||
|
git checkout -b feature-updates 2>$null | Out-Null
|
||||||
|
|
||||||
|
# On feature branch: Modify lines 5-7 (Version 2.0, Beta, Advanced)
|
||||||
|
$featureContent = @"
|
||||||
|
# app.py - Main application
|
||||||
|
|
||||||
|
def main():
|
||||||
|
print("Application starting...")
|
||||||
|
# Lines 5-7 will be modified differently on each branch
|
||||||
|
print("Version: 2.0")
|
||||||
|
print("Status: Beta")
|
||||||
|
print("Mode: Advanced")
|
||||||
|
# End of conflicting section
|
||||||
|
print("Application ready!")
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
||||||
|
"@
|
||||||
|
Set-Content -Path "app.py" -Value $featureContent
|
||||||
|
|
||||||
|
git add .
|
||||||
|
git commit -m "Update to version 2.0 with advanced features" | Out-Null
|
||||||
|
|
||||||
|
# Switch back to main
|
||||||
|
Write-Host "Switching back to main branch..." -ForegroundColor Green
|
||||||
|
git checkout main 2>$null | Out-Null
|
||||||
|
|
||||||
|
# On main: Modify THE SAME lines 5-7 differently (Version 1.5, Production, Basic)
|
||||||
|
$mainContent = @"
|
||||||
|
# app.py - Main application
|
||||||
|
|
||||||
|
def main():
|
||||||
|
print("Application starting...")
|
||||||
|
# Lines 5-7 will be modified differently on each branch
|
||||||
|
print("Version: 1.5")
|
||||||
|
print("Status: Production")
|
||||||
|
print("Mode: Basic")
|
||||||
|
# End of conflicting section
|
||||||
|
print("Application ready!")
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
||||||
|
"@
|
||||||
|
Set-Content -Path "app.py" -Value $mainContent
|
||||||
|
|
||||||
|
git add .
|
||||||
|
git commit -m "Update to version 1.5 for production" | 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 "`nThe conflict scenario:" -ForegroundColor Cyan
|
||||||
|
Write-Host " - Main branch: Version 1.5, Production, Basic mode" -ForegroundColor White
|
||||||
|
Write-Host " - Feature branch: Version 2.0, Beta, Advanced mode" -ForegroundColor White
|
||||||
|
Write-Host " - SAME LINES modified differently = CONFLICT!" -ForegroundColor Yellow
|
||||||
|
Write-Host "`nNext steps:" -ForegroundColor Cyan
|
||||||
|
Write-Host " 1. cd challenge" -ForegroundColor White
|
||||||
|
Write-Host " 2. Try to merge: git merge feature-updates" -ForegroundColor White
|
||||||
|
Write-Host " 3. See the conflict! git status will show 'both modified: app.py'" -ForegroundColor White
|
||||||
|
Write-Host " 4. Open app.py and look for conflict markers (<<<<<<< ======= >>>>>>>)" -ForegroundColor White
|
||||||
|
Write-Host " 5. Manually resolve by editing app.py" -ForegroundColor White
|
||||||
|
Write-Host " 6. Remove conflict markers and keep desired version" -ForegroundColor White
|
||||||
|
Write-Host " 7. Stage: git add app.py" -ForegroundColor White
|
||||||
|
Write-Host " 8. Complete: git commit" -ForegroundColor White
|
||||||
|
Write-Host " 9. Run '..\verify.ps1' to check your solution" -ForegroundColor White
|
||||||
|
Write-Host ""
|
||||||
123
module-05-conflicts/verify.ps1
Normal file
123
module-05-conflicts/verify.ps1
Normal file
@@ -0,0 +1,123 @@
|
|||||||
|
#!/usr/bin/env pwsh
|
||||||
|
<#
|
||||||
|
.SYNOPSIS
|
||||||
|
Verifies the Module 05 challenge solution.
|
||||||
|
|
||||||
|
.DESCRIPTION
|
||||||
|
This script checks that:
|
||||||
|
- The challenge directory exists
|
||||||
|
- A Git repository exists
|
||||||
|
- No merge conflicts remain
|
||||||
|
- The merge was completed successfully
|
||||||
|
- Conflict markers have been removed from files
|
||||||
|
#>
|
||||||
|
|
||||||
|
Write-Host "`n=== Verifying Module 05 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 there are any unresolved conflicts
|
||||||
|
$gitStatus = git status --porcelain 2>$null
|
||||||
|
$hasConflicts = git status | Select-String "Unmerged paths" 2>$null
|
||||||
|
|
||||||
|
if ($hasConflicts) {
|
||||||
|
Write-Host "[FAIL] Unresolved merge conflicts still exist" -ForegroundColor Red
|
||||||
|
Write-Host "[HINT] Open app.py, resolve conflicts, then: git add app.py && git commit" -ForegroundColor Yellow
|
||||||
|
$allChecksPassed = $false
|
||||||
|
} else {
|
||||||
|
Write-Host "[PASS] No unresolved conflicts" -ForegroundColor Green
|
||||||
|
}
|
||||||
|
|
||||||
|
# Check if app.py exists
|
||||||
|
if (-not (Test-Path "app.py")) {
|
||||||
|
Write-Host "[FAIL] app.py not found" -ForegroundColor Red
|
||||||
|
Write-Host "[HINT] Did you run setup.ps1?" -ForegroundColor Yellow
|
||||||
|
$allChecksPassed = $false
|
||||||
|
Set-Location ..
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
|
||||||
|
# Check if app.py contains conflict markers
|
||||||
|
$appContent = Get-Content "app.py" -Raw
|
||||||
|
if ($appContent -match "<<<<<<< HEAD" -or $appContent -match "=======" -or $appContent -match ">>>>>>>") {
|
||||||
|
Write-Host "[FAIL] Conflict markers still present in app.py" -ForegroundColor Red
|
||||||
|
Write-Host "[HINT] Edit app.py to remove all conflict markers (<<<<<<< ======= >>>>>>>)" -ForegroundColor Yellow
|
||||||
|
$allChecksPassed = $false
|
||||||
|
} else {
|
||||||
|
Write-Host "[PASS] No conflict markers in app.py" -ForegroundColor Green
|
||||||
|
}
|
||||||
|
|
||||||
|
# Check if a merge commit exists
|
||||||
|
$mergeCommits = git log --merges --oneline 2>$null
|
||||||
|
if ($mergeCommits) {
|
||||||
|
Write-Host "[PASS] Merge commit exists (conflict was resolved and committed)" -ForegroundColor Green
|
||||||
|
} else {
|
||||||
|
# Check if we're in the middle of a merge
|
||||||
|
if (Test-Path ".git/MERGE_HEAD") {
|
||||||
|
Write-Host "[FAIL] Merge not completed - still in progress" -ForegroundColor Red
|
||||||
|
Write-Host "[HINT] After resolving conflicts and staging with 'git add', run 'git commit'" -ForegroundColor Yellow
|
||||||
|
$allChecksPassed = $false
|
||||||
|
} else {
|
||||||
|
Write-Host "[FAIL] No merge commit found" -ForegroundColor Red
|
||||||
|
Write-Host "[HINT] Did you merge feature-updates into main?" -ForegroundColor Yellow
|
||||||
|
$allChecksPassed = $false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
# Check that file has actual content (not just conflict markers removed)
|
||||||
|
if ($appContent -match "def main\(\):" -and $appContent -match "print") {
|
||||||
|
Write-Host "[PASS] app.py contains valid Python code" -ForegroundColor Green
|
||||||
|
} else {
|
||||||
|
Write-Host "[FAIL] app.py appears to be incomplete or damaged" -ForegroundColor Red
|
||||||
|
$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 resolved a merge conflict!" -ForegroundColor Cyan
|
||||||
|
Write-Host "You now understand:" -ForegroundColor Cyan
|
||||||
|
Write-Host " - How merge conflicts occur (same lines changed differently)" -ForegroundColor White
|
||||||
|
Write-Host " - How to recognize conflict markers" -ForegroundColor White
|
||||||
|
Write-Host " - How to manually resolve conflicts" -ForegroundColor White
|
||||||
|
Write-Host " - How to complete a merge after resolution (git add + git commit)" -ForegroundColor White
|
||||||
|
Write-Host "`nThis is a crucial skill for collaborative development!" -ForegroundColor Green
|
||||||
|
Write-Host "Ready 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 "[TIP] If stuck, run 'git status' to see what state you're in." -ForegroundColor Cyan
|
||||||
|
Write-Host ""
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user