refactor: we're breaking out merge-conflicts
This commit is contained in:
File diff suppressed because it is too large
Load Diff
1
01-essentials/03-branching-and-merging/challenge
Submodule
1
01-essentials/03-branching-and-merging/challenge
Submodule
Submodule 01-essentials/03-branching-and-merging/challenge added at 8ae52cc25c
@@ -1,216 +1,23 @@
|
|||||||
#!/usr/bin/env pwsh
|
#!/usr/bin/env pwsh
|
||||||
<#
|
<#
|
||||||
.SYNOPSIS
|
.SYNOPSIS
|
||||||
Resets the challenge environment to a specific checkpoint.
|
Resets the Module 03 challenge environment.
|
||||||
|
|
||||||
.DESCRIPTION
|
.DESCRIPTION
|
||||||
This script allows you to jump to any checkpoint in the module,
|
This script removes the challenge directory, allowing you to start fresh.
|
||||||
resetting your repository to that state. Useful for skipping ahead,
|
Run setup.ps1 again after resetting to recreate the environment.
|
||||||
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(
|
Write-Host "`n=== Resetting Module 03 Challenge ===" -ForegroundColor Cyan
|
||||||
[ValidateSet('start', 'merge', 'merge-conflict', '')]
|
|
||||||
[string]$Checkpoint = ''
|
|
||||||
)
|
|
||||||
|
|
||||||
# Checkpoint to tag mapping
|
if (Test-Path "challenge") {
|
||||||
$checkpointTags = @{
|
Write-Host "Removing challenge directory..." -ForegroundColor Yellow
|
||||||
'start' = 'checkpoint-start'
|
Remove-Item -Recurse -Force "challenge"
|
||||||
'merge' = 'checkpoint-merge'
|
Write-Host "`n[SUCCESS] Challenge environment reset complete!" -ForegroundColor Green
|
||||||
'merge-conflict' = 'checkpoint-merge-conflict'
|
Write-Host "`nRun .\setup.ps1 to create a fresh challenge environment." -ForegroundColor Cyan
|
||||||
|
Write-Host ""
|
||||||
|
} else {
|
||||||
|
Write-Host "`n[INFO] No challenge directory found. Nothing to reset." -ForegroundColor Yellow
|
||||||
|
Write-Host "Run .\setup.ps1 to create the challenge environment." -ForegroundColor Cyan
|
||||||
|
Write-Host ""
|
||||||
}
|
}
|
||||||
|
|
||||||
# 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
|
|
||||||
|
|||||||
@@ -1,17 +1,13 @@
|
|||||||
#!/usr/bin/env pwsh
|
#!/usr/bin/env pwsh
|
||||||
<#
|
<#
|
||||||
.SYNOPSIS
|
.SYNOPSIS
|
||||||
Sets up the Module 03 checkpoint-based challenge environment.
|
Sets up the Module 03 challenge environment for branching and merging.
|
||||||
|
|
||||||
.DESCRIPTION
|
.DESCRIPTION
|
||||||
This script creates a challenge directory with a complete Git repository
|
This script creates a challenge directory with a Git repository containing
|
||||||
containing all commits and checkpoints for learning branching, merging,
|
a realistic project history with multiple merged branches. Students will see
|
||||||
and merge conflict resolution in one continuous workflow.
|
what branching and merging looks like in practice, then create their own
|
||||||
|
branches to experiment.
|
||||||
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
|
Write-Host "`n=== Setting up Module 03: Branching and Merging ===" -ForegroundColor Cyan
|
||||||
@@ -36,113 +32,75 @@ git config user.name "Workshop Student"
|
|||||||
git config user.email "student@example.com"
|
git config user.email "student@example.com"
|
||||||
|
|
||||||
# ============================================================================
|
# ============================================================================
|
||||||
# PHASE 1: Branching Basics - Initial commits on main
|
# Create a realistic project history with multiple merged branches
|
||||||
# ============================================================================
|
# ============================================================================
|
||||||
Write-Host "`nPhase 1: Creating initial project structure..." -ForegroundColor Cyan
|
Write-Host "Creating project history with multiple branches..." -ForegroundColor Cyan
|
||||||
|
|
||||||
# Commit 1: Initial commit
|
# Initial commits on main
|
||||||
$mainContent = @"
|
$readmeContent = @"
|
||||||
# main.py - Main application file
|
# My Application
|
||||||
|
|
||||||
def main():
|
A sample application for learning Git branching and merging.
|
||||||
print("Welcome to the Application!")
|
|
||||||
print("This is the main branch")
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
|
||||||
main()
|
|
||||||
"@
|
"@
|
||||||
Set-Content -Path "main.py" -Value $mainContent
|
Set-Content -Path "README.md" -Value $readmeContent
|
||||||
git add .
|
git add .
|
||||||
git commit -m "Initial commit" | Out-Null
|
git commit -m "Initial commit" | Out-Null
|
||||||
|
|
||||||
# Commit 2: Add main functionality
|
|
||||||
$mainContent = @"
|
$mainContent = @"
|
||||||
# main.py - Main application file
|
# main.py - Main application file
|
||||||
|
|
||||||
def main():
|
def main():
|
||||||
print("Welcome to the Application!")
|
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__":
|
if __name__ == "__main__":
|
||||||
main()
|
main()
|
||||||
"@
|
"@
|
||||||
Set-Content -Path "main.py" -Value $mainContent
|
Set-Content -Path "main.py" -Value $mainContent
|
||||||
git add .
|
git add .
|
||||||
git commit -m "Add main functionality" | Out-Null
|
git commit -m "Add main application file" | 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)
|
# Branch 1: feature-login (will be merged)
|
||||||
# ============================================================================
|
# ============================================================================
|
||||||
Write-Host "Phase 2: Creating feature-login branch..." -ForegroundColor Cyan
|
Write-Host "Creating feature-login branch..." -ForegroundColor Cyan
|
||||||
|
|
||||||
# Create and switch to feature-login branch
|
|
||||||
git switch -c feature-login | Out-Null
|
git switch -c feature-login | Out-Null
|
||||||
|
|
||||||
# Commit 3: Add login module
|
|
||||||
$loginContent = @"
|
$loginContent = @"
|
||||||
# login.py - User login module
|
# login.py - User authentication
|
||||||
|
|
||||||
def login(username, password):
|
def login(username, password):
|
||||||
"""Authenticate a user."""
|
"""Authenticate a user."""
|
||||||
print(f"Authenticating user: {username}")
|
print(f"Logging in user: {username}")
|
||||||
# TODO: Add actual authentication logic
|
|
||||||
return True
|
|
||||||
|
|
||||||
def logout(username):
|
|
||||||
"""Log out a user."""
|
|
||||||
print(f"Logging out user: {username}")
|
|
||||||
return True
|
return True
|
||||||
"@
|
"@
|
||||||
Set-Content -Path "login.py" -Value $loginContent
|
Set-Content -Path "login.py" -Value $loginContent
|
||||||
git add .
|
git add .
|
||||||
git commit -m "Add login module" | Out-Null
|
git commit -m "Add login module" | Out-Null
|
||||||
|
|
||||||
# Commit 4: Add password validation
|
|
||||||
$loginContent = @"
|
$loginContent = @"
|
||||||
# login.py - User login module
|
# login.py - User authentication
|
||||||
|
|
||||||
def validate_password(password):
|
def validate_password(password):
|
||||||
"""Validate password strength."""
|
"""Validate password strength."""
|
||||||
if len(password) < 8:
|
return len(password) >= 8
|
||||||
return False
|
|
||||||
return True
|
|
||||||
|
|
||||||
def login(username, password):
|
def login(username, password):
|
||||||
"""Authenticate a user."""
|
"""Authenticate a user."""
|
||||||
if not validate_password(password):
|
if not validate_password(password):
|
||||||
print("Password too weak!")
|
print("Password too weak!")
|
||||||
return False
|
return False
|
||||||
print(f"Authenticating user: {username}")
|
print(f"Logging in user: {username}")
|
||||||
# TODO: Add actual authentication logic
|
|
||||||
return True
|
|
||||||
|
|
||||||
def logout(username):
|
|
||||||
"""Log out a user."""
|
|
||||||
print(f"Logging out user: {username}")
|
|
||||||
return True
|
return True
|
||||||
"@
|
"@
|
||||||
Set-Content -Path "login.py" -Value $loginContent
|
Set-Content -Path "login.py" -Value $loginContent
|
||||||
git add .
|
git add .
|
||||||
git commit -m "Add password validation" | Out-Null
|
git commit -m "Add password validation" | Out-Null
|
||||||
|
|
||||||
# Switch back to main
|
# Switch back to main and make more commits
|
||||||
git switch main | Out-Null
|
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 = @"
|
$appContent = @"
|
||||||
# app.py - Main application entry point
|
# app.py - Application entry point
|
||||||
|
|
||||||
from main import main
|
from main import main
|
||||||
|
|
||||||
@@ -150,7 +108,6 @@ def run():
|
|||||||
"""Run the application."""
|
"""Run the application."""
|
||||||
print("Starting application...")
|
print("Starting application...")
|
||||||
main()
|
main()
|
||||||
print("Application finished.")
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
run()
|
run()
|
||||||
@@ -159,16 +116,65 @@ Set-Content -Path "app.py" -Value $appContent
|
|||||||
git add .
|
git add .
|
||||||
git commit -m "Add app.py entry point" | Out-Null
|
git commit -m "Add app.py entry point" | Out-Null
|
||||||
|
|
||||||
# Commit 6: Add README
|
# Merge feature-login into main
|
||||||
|
Write-Host "Merging feature-login into main..." -ForegroundColor Green
|
||||||
|
git merge feature-login --no-edit | Out-Null
|
||||||
|
|
||||||
|
# ============================================================================
|
||||||
|
# Branch 2: feature-api (will be merged)
|
||||||
|
# ============================================================================
|
||||||
|
Write-Host "Creating feature-api branch..." -ForegroundColor Cyan
|
||||||
|
git switch -c feature-api | Out-Null
|
||||||
|
|
||||||
|
$apiContent = @"
|
||||||
|
# api.py - API endpoints
|
||||||
|
|
||||||
|
def get_data():
|
||||||
|
"""Retrieve data from API."""
|
||||||
|
return {"status": "ok", "data": []}
|
||||||
|
|
||||||
|
def post_data(data):
|
||||||
|
"""Send data to API."""
|
||||||
|
print(f"Posting data: {data}")
|
||||||
|
return {"status": "ok"}
|
||||||
|
"@
|
||||||
|
Set-Content -Path "api.py" -Value $apiContent
|
||||||
|
git add .
|
||||||
|
git commit -m "Add API module" | Out-Null
|
||||||
|
|
||||||
|
$apiContent = @"
|
||||||
|
# api.py - API endpoints
|
||||||
|
|
||||||
|
def get_data():
|
||||||
|
"""Retrieve data from API."""
|
||||||
|
return {"status": "ok", "data": []}
|
||||||
|
|
||||||
|
def post_data(data):
|
||||||
|
"""Send data to API."""
|
||||||
|
print(f"Posting data: {data}")
|
||||||
|
return {"status": "ok"}
|
||||||
|
|
||||||
|
def delete_data(id):
|
||||||
|
"""Delete data by ID."""
|
||||||
|
print(f"Deleting data: {id}")
|
||||||
|
return {"status": "ok"}
|
||||||
|
"@
|
||||||
|
Set-Content -Path "api.py" -Value $apiContent
|
||||||
|
git add .
|
||||||
|
git commit -m "Add delete endpoint to API" | Out-Null
|
||||||
|
|
||||||
|
# Switch back to main and add documentation
|
||||||
|
git switch main | Out-Null
|
||||||
|
|
||||||
$readmeContent = @"
|
$readmeContent = @"
|
||||||
# My Application
|
# My Application
|
||||||
|
|
||||||
Welcome to my application!
|
A sample application for learning Git branching and merging.
|
||||||
|
|
||||||
## Features
|
## Features
|
||||||
|
|
||||||
- Main functionality
|
- User authentication
|
||||||
- More features coming soon
|
- Main application logic
|
||||||
|
|
||||||
## Setup
|
## Setup
|
||||||
|
|
||||||
@@ -176,104 +182,107 @@ Run: python app.py
|
|||||||
"@
|
"@
|
||||||
Set-Content -Path "README.md" -Value $readmeContent
|
Set-Content -Path "README.md" -Value $readmeContent
|
||||||
git add .
|
git add .
|
||||||
git commit -m "Add README documentation" | Out-Null
|
git commit -m "Update README with setup instructions" | Out-Null
|
||||||
|
|
||||||
# Tag checkpoint-merge (students begin merging here - divergent branches ready)
|
# Merge feature-api into main
|
||||||
Write-Host "Creating checkpoint: merge" -ForegroundColor Green
|
Write-Host "Merging feature-api into main..." -ForegroundColor Green
|
||||||
git tag checkpoint-merge
|
git merge feature-api --no-edit | Out-Null
|
||||||
|
|
||||||
# ============================================================================
|
# ============================================================================
|
||||||
# PHASE 3: Merge feature-login into main (what students will do in checkpoint 2)
|
# Branch 3: feature-database (will be merged)
|
||||||
# ============================================================================
|
# ============================================================================
|
||||||
Write-Host "Phase 3: Merging feature-login into main..." -ForegroundColor Cyan
|
Write-Host "Creating feature-database branch..." -ForegroundColor Cyan
|
||||||
|
git switch -c feature-database | Out-Null
|
||||||
|
|
||||||
# Merge feature-login into main (will create three-way merge commit)
|
$dbContent = @"
|
||||||
git merge feature-login --no-edit | Out-Null
|
# database.py - Database operations
|
||||||
|
|
||||||
# ============================================================================
|
class Database:
|
||||||
# PHASE 4: Create conflict scenario (what students will do in checkpoint 3)
|
def __init__(self):
|
||||||
# ============================================================================
|
self.connection = None
|
||||||
Write-Host "Phase 4: Creating merge conflict scenario..." -ForegroundColor Cyan
|
|
||||||
|
|
||||||
# Create config.json file on main
|
def connect(self):
|
||||||
$initialConfig = @"
|
"""Connect to database."""
|
||||||
{
|
print("Connecting to database...")
|
||||||
"app": {
|
self.connection = True
|
||||||
"name": "MyApp",
|
|
||||||
"version": "1.0.0",
|
def query(self, sql):
|
||||||
"port": 3000
|
"""Execute SQL query."""
|
||||||
}
|
print(f"Executing: {sql}")
|
||||||
}
|
return []
|
||||||
"@
|
"@
|
||||||
Set-Content -Path "config.json" -Value $initialConfig
|
Set-Content -Path "database.py" -Value $dbContent
|
||||||
git add config.json
|
git add .
|
||||||
git commit -m "Add initial configuration" | Out-Null
|
git commit -m "Add database module" | Out-Null
|
||||||
|
|
||||||
# On main branch: Add timeout setting
|
$dbContent = @"
|
||||||
$mainConfig = @"
|
# database.py - Database operations
|
||||||
{
|
|
||||||
"app": {
|
class Database:
|
||||||
"name": "MyApp",
|
def __init__(self):
|
||||||
"version": "1.0.0",
|
self.connection = None
|
||||||
"port": 3000,
|
|
||||||
"timeout": 5000
|
def connect(self):
|
||||||
}
|
"""Connect to database."""
|
||||||
}
|
print("Connecting to database...")
|
||||||
|
self.connection = True
|
||||||
|
|
||||||
|
def disconnect(self):
|
||||||
|
"""Disconnect from database."""
|
||||||
|
print("Disconnecting from database...")
|
||||||
|
self.connection = None
|
||||||
|
|
||||||
|
def query(self, sql):
|
||||||
|
"""Execute SQL query."""
|
||||||
|
print(f"Executing: {sql}")
|
||||||
|
return []
|
||||||
"@
|
"@
|
||||||
Set-Content -Path "config.json" -Value $mainConfig
|
Set-Content -Path "database.py" -Value $dbContent
|
||||||
git add config.json
|
git add .
|
||||||
git commit -m "Add timeout configuration" | Out-Null
|
git commit -m "Add disconnect method" | Out-Null
|
||||||
|
|
||||||
# Create update-config branch from the commit before timeout was added
|
# Switch to main and merge
|
||||||
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
|
git switch main | Out-Null
|
||||||
|
Write-Host "Merging feature-database into main..." -ForegroundColor Green
|
||||||
|
git merge feature-database --no-edit | Out-Null
|
||||||
|
|
||||||
# Tag checkpoint-merge-conflict (students begin conflict resolution here - on main with timeout, update-config has debug)
|
# Final update on main
|
||||||
Write-Host "Creating checkpoint: merge-conflict" -ForegroundColor Green
|
$readmeContent = @"
|
||||||
git tag checkpoint-merge-conflict
|
# My Application
|
||||||
|
|
||||||
# ============================================================================
|
A sample application for learning Git branching and merging.
|
||||||
# Reset to checkpoint-start so students begin at the beginning
|
|
||||||
# ============================================================================
|
## Features
|
||||||
Write-Host "`nResetting to checkpoint-start..." -ForegroundColor Yellow
|
|
||||||
git reset --hard checkpoint-start | Out-Null
|
- User authentication
|
||||||
git clean -fd | Out-Null
|
- API endpoints
|
||||||
|
- Database operations
|
||||||
|
- Main application logic
|
||||||
|
|
||||||
|
## Setup
|
||||||
|
|
||||||
|
Run: python app.py
|
||||||
|
|
||||||
|
## Requirements
|
||||||
|
|
||||||
|
- Python 3.6+
|
||||||
|
"@
|
||||||
|
Set-Content -Path "README.md" -Value $readmeContent
|
||||||
|
git add .
|
||||||
|
git commit -m "Update README with all features" | Out-Null
|
||||||
|
|
||||||
# Return to module directory
|
# Return to module directory
|
||||||
Set-Location ..
|
Set-Location ..
|
||||||
|
|
||||||
Write-Host "`n=== Setup Complete! ===" -ForegroundColor Green
|
Write-Host "`n=== Setup Complete! ===" -ForegroundColor Green
|
||||||
Write-Host "`nYour challenge environment is ready in the 'challenge/' directory." -ForegroundColor Cyan
|
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 "`nThe repository contains a realistic project history:" -ForegroundColor Yellow
|
||||||
Write-Host " You'll work through 3 sections in one continuous repository:" -ForegroundColor White
|
Write-Host " - Multiple feature branches (login, api, database)" -ForegroundColor White
|
||||||
Write-Host " 1. Branching Basics (checkpoint: start)" -ForegroundColor White
|
Write-Host " - All branches have been merged into main" -ForegroundColor White
|
||||||
Write-Host " 2. Merging Branches (checkpoint: merge)" -ForegroundColor White
|
Write-Host " - View the history: git log --oneline --graph --all" -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 "`nNext steps:" -ForegroundColor Cyan
|
||||||
Write-Host " 1. Read the README.md for detailed instructions" -ForegroundColor White
|
Write-Host " 1. Read the README.md for detailed instructions" -ForegroundColor White
|
||||||
Write-Host " 2. cd challenge" -ForegroundColor White
|
Write-Host " 2. cd challenge" -ForegroundColor White
|
||||||
Write-Host " 3. Start with Checkpoint 1: Branching Basics" -ForegroundColor White
|
Write-Host " 3. Explore the repository history: git log --oneline --graph --all" -ForegroundColor White
|
||||||
|
Write-Host " 4. Create your own branches and practice merging!" -ForegroundColor White
|
||||||
Write-Host ""
|
Write-Host ""
|
||||||
|
|||||||
@@ -1,34 +1,15 @@
|
|||||||
#!/usr/bin/env pwsh
|
#!/usr/bin/env pwsh
|
||||||
<#
|
<#
|
||||||
.SYNOPSIS
|
.SYNOPSIS
|
||||||
Verifies the Module 03 challenge solution (checkpoint-aware).
|
Verifies the Module 03 challenge solution.
|
||||||
|
|
||||||
.DESCRIPTION
|
.DESCRIPTION
|
||||||
This script can verify completion of individual checkpoints or
|
This script checks that you've practiced branching and merging by:
|
||||||
the entire module. Without arguments, it verifies all checkpoints.
|
- Creating at least one new branch (beyond the example branches)
|
||||||
|
- Making commits on your branch
|
||||||
.PARAMETER Checkpoint
|
- Merging your branch into main
|
||||||
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
|
$script:allChecksPassed = $true
|
||||||
|
|
||||||
# ============================================================================
|
# ============================================================================
|
||||||
@@ -51,198 +32,15 @@ function Write-Hint {
|
|||||||
Write-Host "[HINT] $Message" -ForegroundColor Yellow
|
Write-Host "[HINT] $Message" -ForegroundColor Yellow
|
||||||
}
|
}
|
||||||
|
|
||||||
# ============================================================================
|
function Write-Info {
|
||||||
# Checkpoint 1: Branching Basics Verification
|
param([string]$Message)
|
||||||
# ============================================================================
|
Write-Host "[INFO] $Message" -ForegroundColor Cyan
|
||||||
|
|
||||||
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
|
# Check challenge directory exists
|
||||||
# ============================================================================
|
# ============================================================================
|
||||||
|
|
||||||
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")) {
|
if (-not (Test-Path "challenge")) {
|
||||||
Write-Host "[ERROR] Challenge directory not found." -ForegroundColor Red
|
Write-Host "[ERROR] Challenge directory not found." -ForegroundColor Red
|
||||||
Write-Host "Run .\setup.ps1 first to create the challenge environment." -ForegroundColor Yellow
|
Write-Host "Run .\setup.ps1 first to create the challenge environment." -ForegroundColor Yellow
|
||||||
@@ -251,7 +49,6 @@ if (-not (Test-Path "challenge")) {
|
|||||||
|
|
||||||
Push-Location "challenge"
|
Push-Location "challenge"
|
||||||
|
|
||||||
# Check if git repository exists
|
|
||||||
if (-not (Test-Path ".git")) {
|
if (-not (Test-Path ".git")) {
|
||||||
Write-Host "[ERROR] Not a git repository." -ForegroundColor Red
|
Write-Host "[ERROR] Not a git repository." -ForegroundColor Red
|
||||||
Write-Host "Run ..\setup.ps1 first to create the challenge environment." -ForegroundColor Yellow
|
Write-Host "Run ..\setup.ps1 first to create the challenge environment." -ForegroundColor Yellow
|
||||||
@@ -259,62 +56,98 @@ if (-not (Test-Path ".git")) {
|
|||||||
exit 1
|
exit 1
|
||||||
}
|
}
|
||||||
|
|
||||||
# Run appropriate verification
|
Write-Host "`n=== Verifying Module 03: Branching and Merging ===" -ForegroundColor Cyan
|
||||||
if ($Checkpoint -eq '') {
|
|
||||||
# Verify all checkpoints
|
|
||||||
Write-Host "`n=== Verifying All Checkpoints ===" -ForegroundColor Cyan
|
|
||||||
|
|
||||||
Verify-Branching
|
# ============================================================================
|
||||||
Verify-Merging
|
# Count initial setup commits (should be 13 commits from setup)
|
||||||
Verify-MergeConflicts
|
# ============================================================================
|
||||||
|
$initialCommitCount = 13
|
||||||
|
|
||||||
|
# ============================================================================
|
||||||
|
# Check for new commits beyond setup
|
||||||
|
# ============================================================================
|
||||||
|
Write-Host "`nChecking your work..." -ForegroundColor Cyan
|
||||||
|
|
||||||
|
$totalCommits = [int](git rev-list --count HEAD 2>$null)
|
||||||
|
|
||||||
|
if ($totalCommits -gt $initialCommitCount) {
|
||||||
|
$newCommits = $totalCommits - $initialCommitCount
|
||||||
|
Write-Pass "Found $newCommits new commit(s) beyond the initial setup"
|
||||||
} else {
|
} else {
|
||||||
# Verify specific checkpoint
|
Write-Fail "No new commits found"
|
||||||
switch ($Checkpoint) {
|
Write-Hint "Create a branch, make some commits, and merge it into main"
|
||||||
'start' { Verify-Branching }
|
Write-Hint "Example: git switch -c my-feature"
|
||||||
'merge' { Verify-Merging }
|
}
|
||||||
'merge-conflict' { Verify-MergeConflicts }
|
|
||||||
}
|
# ============================================================================
|
||||||
|
# Check for branches (excluding the example branches)
|
||||||
|
# ============================================================================
|
||||||
|
$allBranches = git branch --list 2>$null | ForEach-Object { $_.Trim('* ') }
|
||||||
|
$exampleBranches = @('main', 'feature-login', 'feature-api', 'feature-database')
|
||||||
|
$studentBranches = $allBranches | Where-Object { $_ -notin $exampleBranches }
|
||||||
|
|
||||||
|
if ($studentBranches.Count -gt 0) {
|
||||||
|
Write-Pass "Created $($studentBranches.Count) new branch(es): $($studentBranches -join ', ')"
|
||||||
|
} else {
|
||||||
|
Write-Info "No new branches found (it's OK if you deleted them after merging)"
|
||||||
|
Write-Hint "To practice: git switch -c your-branch-name"
|
||||||
|
}
|
||||||
|
|
||||||
|
# ============================================================================
|
||||||
|
# Check for merge commits by the student
|
||||||
|
# ============================================================================
|
||||||
|
$setupUser = "Workshop Student"
|
||||||
|
$mergeCommits = git log --merges --format="%s" 2>$null
|
||||||
|
|
||||||
|
# Count how many merge commits exist beyond the initial 3
|
||||||
|
$totalMerges = ($mergeCommits | Measure-Object).Count
|
||||||
|
$setupMerges = 3 # feature-login, feature-api, feature-database
|
||||||
|
|
||||||
|
if ($totalMerges -gt $setupMerges) {
|
||||||
|
$studentMerges = $totalMerges - $setupMerges
|
||||||
|
Write-Pass "Performed $studentMerges merge(s) of your own work"
|
||||||
|
} else {
|
||||||
|
Write-Fail "No merge commits found beyond the example merges"
|
||||||
|
Write-Hint "Create a branch, add commits, then merge it: git merge your-branch-name"
|
||||||
|
}
|
||||||
|
|
||||||
|
# ============================================================================
|
||||||
|
# Check current branch
|
||||||
|
# ============================================================================
|
||||||
|
$currentBranch = git branch --show-current 2>$null
|
||||||
|
if ($currentBranch -eq "main") {
|
||||||
|
Write-Pass "Currently on main branch"
|
||||||
|
} else {
|
||||||
|
Write-Info "Currently on '$currentBranch' branch"
|
||||||
|
Write-Hint "Typically you merge feature branches INTO main"
|
||||||
}
|
}
|
||||||
|
|
||||||
Pop-Location
|
Pop-Location
|
||||||
|
|
||||||
|
# ============================================================================
|
||||||
# Final summary
|
# Final summary
|
||||||
|
# ============================================================================
|
||||||
Write-Host ""
|
Write-Host ""
|
||||||
if ($script:allChecksPassed) {
|
if ($script:allChecksPassed) {
|
||||||
Write-Host "=========================================" -ForegroundColor Green
|
Write-Host "=========================================" -ForegroundColor Green
|
||||||
Write-Host " CONGRATULATIONS! CHALLENGE PASSED!" -ForegroundColor Green
|
Write-Host " CONGRATULATIONS! CHALLENGE PASSED!" -ForegroundColor Green
|
||||||
Write-Host "=========================================" -ForegroundColor Green
|
Write-Host "=========================================" -ForegroundColor Green
|
||||||
|
Write-Host "`nYou've successfully practiced:" -ForegroundColor Cyan
|
||||||
if ($Checkpoint -eq '') {
|
Write-Host " ✓ Creating branches" -ForegroundColor White
|
||||||
Write-Host "`nYou've completed the entire module!" -ForegroundColor Cyan
|
Write-Host " ✓ Making commits on branches" -ForegroundColor White
|
||||||
Write-Host "You've mastered:" -ForegroundColor Cyan
|
Write-Host " ✓ Merging branches together" -ForegroundColor White
|
||||||
Write-Host " ✓ Creating and working with branches" -ForegroundColor White
|
Write-Host "`nReady for the next module!" -ForegroundColor Green
|
||||||
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 ""
|
Write-Host ""
|
||||||
exit 0
|
exit 0
|
||||||
} else {
|
} else {
|
||||||
Write-Host "[SUMMARY] Some checks failed. Review the hints above and try again." -ForegroundColor Red
|
Write-Host "[SUMMARY] Some checks failed. Review the hints above." -ForegroundColor Red
|
||||||
Write-Host "[INFO] You can run this verification script as many times as needed." -ForegroundColor Yellow
|
Write-Host ""
|
||||||
|
Write-Host "Quick guide:" -ForegroundColor Cyan
|
||||||
|
Write-Host " 1. Create a branch: git switch -c my-feature" -ForegroundColor White
|
||||||
|
Write-Host " 2. Make changes and commit them" -ForegroundColor White
|
||||||
|
Write-Host " 3. Switch to main: git switch main" -ForegroundColor White
|
||||||
|
Write-Host " 4. Merge your branch: git merge my-feature" -ForegroundColor White
|
||||||
|
Write-Host " 5. Run this verify script again" -ForegroundColor White
|
||||||
Write-Host ""
|
Write-Host ""
|
||||||
exit 1
|
exit 1
|
||||||
}
|
}
|
||||||
|
|||||||
487
01-essentials/04-merge-conflict/README.md
Normal file
487
01-essentials/04-merge-conflict/README.md
Normal file
@@ -0,0 +1,487 @@
|
|||||||
|
# Module 04: Merge Conflicts
|
||||||
|
|
||||||
|
## Learning Objectives
|
||||||
|
|
||||||
|
By the end of this module, you will:
|
||||||
|
- Understand what merge conflicts are and why they occur
|
||||||
|
- Use `git diff` to discover changes between branches
|
||||||
|
- Identify merge conflicts in your repository
|
||||||
|
- Read and interpret conflict markers (`<<<<<<<`, `=======`, `>>>>>>>`)
|
||||||
|
- Resolve merge conflicts manually
|
||||||
|
- Complete a merge after resolving conflicts
|
||||||
|
|
||||||
|
## Setup
|
||||||
|
|
||||||
|
Create the challenge environment:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
.\setup.ps1
|
||||||
|
```
|
||||||
|
|
||||||
|
This creates a repository with two feature branches that have conflicting changes.
|
||||||
|
|
||||||
|
## Overview
|
||||||
|
|
||||||
|
A **merge conflict** occurs when Git cannot automatically combine changes because both branches modified the same part of the same file in different ways.
|
||||||
|
|
||||||
|
**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.
|
||||||
|
|
||||||
|
## Your Task
|
||||||
|
|
||||||
|
### Part 1: Discover the Changes
|
||||||
|
|
||||||
|
Before merging, it's good practice to see what each branch changed:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cd challenge
|
||||||
|
|
||||||
|
# Check which branch you're on
|
||||||
|
git branch
|
||||||
|
|
||||||
|
# View all branches
|
||||||
|
git branch --all
|
||||||
|
```
|
||||||
|
|
||||||
|
You'll see three branches: `main`, `add-timeout`, and `add-debug`.
|
||||||
|
|
||||||
|
**Discover what each branch changed:**
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Compare main with add-timeout
|
||||||
|
git diff main add-timeout
|
||||||
|
|
||||||
|
# Compare main with add-debug
|
||||||
|
git diff main add-debug
|
||||||
|
|
||||||
|
# Compare the two feature branches directly
|
||||||
|
git diff add-timeout add-debug
|
||||||
|
```
|
||||||
|
|
||||||
|
**What did you discover?**
|
||||||
|
- Both branches modified `config.json`
|
||||||
|
- They both added a line in the same location (after `"port": 3000`)
|
||||||
|
- One adds `"timeout": 5000`
|
||||||
|
- The other adds `"debug": true`
|
||||||
|
|
||||||
|
This is a recipe for a conflict!
|
||||||
|
|
||||||
|
### Part 2: Merge the First Branch (No Conflict)
|
||||||
|
|
||||||
|
Let's merge `add-timeout` first:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Make sure you're on main
|
||||||
|
git switch main
|
||||||
|
|
||||||
|
# Merge the first branch
|
||||||
|
git merge add-timeout
|
||||||
|
```
|
||||||
|
|
||||||
|
✅ **Success!** This merge works because main hasn't changed since add-timeout was created.
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# View the updated config
|
||||||
|
cat config.json
|
||||||
|
|
||||||
|
# Check the history
|
||||||
|
git log --oneline --graph --all
|
||||||
|
```
|
||||||
|
|
||||||
|
### Part 3: Try to Merge the Second Branch (Conflict!)
|
||||||
|
|
||||||
|
Now let's try to merge `add-debug`:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Still on main
|
||||||
|
git merge add-debug
|
||||||
|
```
|
||||||
|
|
||||||
|
💥 **Boom!** 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 expected. Git is asking for your help.
|
||||||
|
|
||||||
|
### Part 4: Check the Status
|
||||||
|
|
||||||
|
```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!
|
||||||
|
|
||||||
|
### Part 5: Open and Examine the Conflicted File
|
||||||
|
|
||||||
|
Open `config.json` in your text editor:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# On Windows
|
||||||
|
notepad config.json
|
||||||
|
|
||||||
|
# Or use VS Code
|
||||||
|
code config.json
|
||||||
|
```
|
||||||
|
|
||||||
|
You'll see special **conflict markers**:
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"app": {
|
||||||
|
"name": "MyApp",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"port": 3000,
|
||||||
|
<<<<<<< HEAD
|
||||||
|
"timeout": 5000
|
||||||
|
=======
|
||||||
|
"debug": true
|
||||||
|
>>>>>>> add-debug
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Part 6: Understand the Conflict Markers
|
||||||
|
|
||||||
|
Let's break down what you're seeing:
|
||||||
|
|
||||||
|
```
|
||||||
|
<<<<<<< HEAD
|
||||||
|
"timeout": 5000 ← Your current branch (main, which has add-timeout merged)
|
||||||
|
=======
|
||||||
|
"debug": true ← The branch you're merging (add-debug)
|
||||||
|
>>>>>>> add-debug
|
||||||
|
```
|
||||||
|
|
||||||
|
**What each marker means:**
|
||||||
|
- `<<<<<<< HEAD` - Start of your changes (current branch)
|
||||||
|
- `=======` - Separator between the two versions
|
||||||
|
- `>>>>>>> add-debug` - End of their changes (branch being merged)
|
||||||
|
|
||||||
|
### Part 7: Resolve the Conflict
|
||||||
|
|
||||||
|
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** ← **Do this!**
|
||||||
|
```json
|
||||||
|
"timeout": 5000,
|
||||||
|
"debug": true
|
||||||
|
```
|
||||||
|
|
||||||
|
### Part 8: Edit the File
|
||||||
|
|
||||||
|
For this challenge, we want **both settings**, so:
|
||||||
|
|
||||||
|
1. Delete ALL the conflict markers:
|
||||||
|
- Remove `<<<<<<< HEAD`
|
||||||
|
- Remove `=======`
|
||||||
|
- Remove `>>>>>>> add-debug`
|
||||||
|
|
||||||
|
2. Keep both settings:
|
||||||
|
|
||||||
|
**Before (with conflict markers):**
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"app": {
|
||||||
|
"name": "MyApp",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"port": 3000,
|
||||||
|
<<<<<<< HEAD
|
||||||
|
"timeout": 5000
|
||||||
|
=======
|
||||||
|
"debug": true
|
||||||
|
>>>>>>> add-debug
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**After (resolved):**
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"app": {
|
||||||
|
"name": "MyApp",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"port": 3000,
|
||||||
|
"timeout": 5000,
|
||||||
|
"debug": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**Important:**
|
||||||
|
- Remove ALL markers
|
||||||
|
- Add a comma after `"timeout": 5000` (for valid JSON)
|
||||||
|
- Ensure the file is valid JSON
|
||||||
|
|
||||||
|
3. Save the file
|
||||||
|
|
||||||
|
### Part 9: Mark the Conflict as Resolved
|
||||||
|
|
||||||
|
Tell Git you've resolved the conflict:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Stage the resolved file
|
||||||
|
git add config.json
|
||||||
|
|
||||||
|
# Check status
|
||||||
|
git status
|
||||||
|
```
|
||||||
|
|
||||||
|
You should 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.
|
||||||
|
|
||||||
|
### Part 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, then save and close.
|
||||||
|
|
||||||
|
**Done!** Your merge is complete!
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# View the final result
|
||||||
|
cat config.json
|
||||||
|
|
||||||
|
# View the history
|
||||||
|
git log --oneline --graph --all
|
||||||
|
```
|
||||||
|
|
||||||
|
You should see both `timeout` and `debug` in the config!
|
||||||
|
|
||||||
|
### Part 11: Verify Your Solution
|
||||||
|
|
||||||
|
From the module directory (not inside challenge/):
|
||||||
|
|
||||||
|
```bash
|
||||||
|
.\verify.ps1
|
||||||
|
```
|
||||||
|
|
||||||
|
## Understanding Conflict Markers
|
||||||
|
|
||||||
|
### Anatomy of a Conflict
|
||||||
|
|
||||||
|
```
|
||||||
|
<<<<<<< HEAD ← Marker: Start of your version
|
||||||
|
Your changes here
|
||||||
|
======= ← Marker: Separator
|
||||||
|
Their changes here
|
||||||
|
>>>>>>> branch-name ← Marker: End of their version
|
||||||
|
```
|
||||||
|
|
||||||
|
### Common Conflict Patterns
|
||||||
|
|
||||||
|
**Simple conflict:**
|
||||||
|
```
|
||||||
|
<<<<<<< HEAD
|
||||||
|
print("Hello")
|
||||||
|
=======
|
||||||
|
print("Hi")
|
||||||
|
>>>>>>> feature
|
||||||
|
```
|
||||||
|
Decision: Which greeting do you want?
|
||||||
|
|
||||||
|
**Both are needed:**
|
||||||
|
```
|
||||||
|
<<<<<<< HEAD
|
||||||
|
timeout: 5000
|
||||||
|
=======
|
||||||
|
debug: true
|
||||||
|
>>>>>>> feature
|
||||||
|
```
|
||||||
|
Decision: Keep both (add comma)!
|
||||||
|
|
||||||
|
**Deletion conflict:**
|
||||||
|
```
|
||||||
|
<<<<<<< HEAD
|
||||||
|
# Function deleted on your branch
|
||||||
|
=======
|
||||||
|
def old_function():
|
||||||
|
pass
|
||||||
|
>>>>>>> feature
|
||||||
|
```
|
||||||
|
Decision: Delete or keep the function?
|
||||||
|
|
||||||
|
## Common Mistakes to Avoid
|
||||||
|
|
||||||
|
❌ **Forgetting to remove conflict markers**
|
||||||
|
```json
|
||||||
|
<<<<<<< HEAD ← Don't leave these in!
|
||||||
|
"timeout": 5000,
|
||||||
|
"debug": true
|
||||||
|
>>>>>>> add-debug ← 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!
|
||||||
|
|
||||||
|
❌ **Breaking syntax**
|
||||||
|
```json
|
||||||
|
"timeout": 5000 ← Missing comma!
|
||||||
|
"debug": true
|
||||||
|
```
|
||||||
|
Always verify your file is valid after resolving!
|
||||||
|
|
||||||
|
❌ **Not testing the result**
|
||||||
|
Always check that your resolved code works!
|
||||||
|
|
||||||
|
## Aborting a Merge
|
||||||
|
|
||||||
|
Changed your mind? You can abort the merge anytime before committing:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
git merge --abort
|
||||||
|
```
|
||||||
|
|
||||||
|
This returns your repository to the state before you started the merge. No harm done!
|
||||||
|
|
||||||
|
## Key Commands
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Discover changes before merging
|
||||||
|
git diff branch1 branch2
|
||||||
|
|
||||||
|
# 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
|
||||||
|
|
||||||
|
💡 **Use `git diff` first**
|
||||||
|
Always compare branches before merging:
|
||||||
|
```bash
|
||||||
|
git diff main..feature-branch
|
||||||
|
```
|
||||||
|
|
||||||
|
💡 **Prevent conflicts**
|
||||||
|
- Pull changes frequently
|
||||||
|
- 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
|
||||||
|
- Make small, focused commits
|
||||||
|
- If editing the same file, coordinate with teammates
|
||||||
|
|
||||||
|
💡 **When stuck**
|
||||||
|
- Read the conflict markers carefully
|
||||||
|
- Look at `git log` to understand what each side changed
|
||||||
|
- Use `git diff` to see the changes
|
||||||
|
- Ask a teammate to review your resolution
|
||||||
|
- Use a merge tool: `git mergetool`
|
||||||
|
|
||||||
|
## Merge Tools
|
||||||
|
|
||||||
|
Git supports visual merge tools that make resolving conflicts easier:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Configure a merge tool (one-time setup)
|
||||||
|
git config --global merge.tool vscode # or meld, kdiff3, etc.
|
||||||
|
|
||||||
|
# Use the merge tool during a conflict
|
||||||
|
git mergetool
|
||||||
|
```
|
||||||
|
|
||||||
|
This opens a visual interface showing both versions side-by-side.
|
||||||
|
|
||||||
|
## Real-World Scenario
|
||||||
|
|
||||||
|
This exercise simulates a common real-world situation:
|
||||||
|
|
||||||
|
**Scenario:** Two developers working on the same file
|
||||||
|
- Alice adds a timeout configuration
|
||||||
|
- Bob adds debug mode configuration
|
||||||
|
- Both push their changes
|
||||||
|
- When Bob tries to merge, he gets a conflict
|
||||||
|
- Bob resolves it by keeping both changes
|
||||||
|
- Everyone's work is preserved!
|
||||||
|
|
||||||
|
This happens all the time in team development. Conflicts are normal!
|
||||||
|
|
||||||
|
## What You've Learned
|
||||||
|
|
||||||
|
After completing this module, you understand:
|
||||||
|
|
||||||
|
- ✅ Merge conflicts happen when the same lines are changed differently
|
||||||
|
- ✅ `git diff` helps you discover changes before merging
|
||||||
|
- ✅ Conflict markers show both versions
|
||||||
|
- ✅ You decide what the final code should look like
|
||||||
|
- ✅ Remove all markers before committing
|
||||||
|
- ✅ Test your resolution to ensure it works
|
||||||
|
- ✅ Conflicts are normal and easy to resolve with practice
|
||||||
|
|
||||||
|
## Next Steps
|
||||||
|
|
||||||
|
Ready to continue? The next module covers **cherry-picking** - selectively applying specific commits from one branch to another.
|
||||||
|
|
||||||
|
To start over:
|
||||||
|
```bash
|
||||||
|
.\reset.ps1
|
||||||
|
.\setup.ps1
|
||||||
|
```
|
||||||
|
|
||||||
|
**Need help?** Review the steps above, or run `git status` to see what Git suggests!
|
||||||
1
01-essentials/04-merge-conflict/challenge
Submodule
1
01-essentials/04-merge-conflict/challenge
Submodule
Submodule 01-essentials/04-merge-conflict/challenge added at 676b08e650
23
01-essentials/04-merge-conflict/reset.ps1
Normal file
23
01-essentials/04-merge-conflict/reset.ps1
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
#!/usr/bin/env pwsh
|
||||||
|
<#
|
||||||
|
.SYNOPSIS
|
||||||
|
Resets the Module 04 challenge environment.
|
||||||
|
|
||||||
|
.DESCRIPTION
|
||||||
|
This script removes the challenge directory, allowing you to start fresh.
|
||||||
|
Run setup.ps1 again after resetting to recreate the environment.
|
||||||
|
#>
|
||||||
|
|
||||||
|
Write-Host "`n=== Resetting Module 04 Challenge ===" -ForegroundColor Cyan
|
||||||
|
|
||||||
|
if (Test-Path "challenge") {
|
||||||
|
Write-Host "Removing challenge directory..." -ForegroundColor Yellow
|
||||||
|
Remove-Item -Recurse -Force "challenge"
|
||||||
|
Write-Host "`n[SUCCESS] Challenge environment reset complete!" -ForegroundColor Green
|
||||||
|
Write-Host "`nRun .\setup.ps1 to create a fresh challenge environment." -ForegroundColor Cyan
|
||||||
|
Write-Host ""
|
||||||
|
} else {
|
||||||
|
Write-Host "`n[INFO] No challenge directory found. Nothing to reset." -ForegroundColor Yellow
|
||||||
|
Write-Host "Run .\setup.ps1 to create the challenge environment." -ForegroundColor Cyan
|
||||||
|
Write-Host ""
|
||||||
|
}
|
||||||
125
01-essentials/04-merge-conflict/setup.ps1
Normal file
125
01-essentials/04-merge-conflict/setup.ps1
Normal file
@@ -0,0 +1,125 @@
|
|||||||
|
#!/usr/bin/env pwsh
|
||||||
|
<#
|
||||||
|
.SYNOPSIS
|
||||||
|
Sets up the Module 04 challenge environment for merge conflicts.
|
||||||
|
|
||||||
|
.DESCRIPTION
|
||||||
|
This script creates a challenge directory with a Git repository containing
|
||||||
|
two feature branches that have conflicting changes to the same file.
|
||||||
|
Students will learn to identify, understand, and resolve merge conflicts.
|
||||||
|
#>
|
||||||
|
|
||||||
|
Write-Host "`n=== Setting up Module 04: Merge Conflicts ===" -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 base project
|
||||||
|
# ============================================================================
|
||||||
|
Write-Host "Creating base project..." -ForegroundColor Cyan
|
||||||
|
|
||||||
|
# Initial commit with config file
|
||||||
|
$configContent = @"
|
||||||
|
{
|
||||||
|
"app": {
|
||||||
|
"name": "MyApp",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"port": 3000
|
||||||
|
}
|
||||||
|
}
|
||||||
|
"@
|
||||||
|
Set-Content -Path "config.json" -Value $configContent
|
||||||
|
git add .
|
||||||
|
git commit -m "Initial commit with config" | Out-Null
|
||||||
|
|
||||||
|
# Add README
|
||||||
|
$readmeContent = @"
|
||||||
|
# My Application
|
||||||
|
|
||||||
|
A simple application for learning merge conflicts.
|
||||||
|
|
||||||
|
## Configuration
|
||||||
|
|
||||||
|
Edit `config.json` to configure the application.
|
||||||
|
"@
|
||||||
|
Set-Content -Path "README.md" -Value $readmeContent
|
||||||
|
git add .
|
||||||
|
git commit -m "Add README" | Out-Null
|
||||||
|
|
||||||
|
# ============================================================================
|
||||||
|
# Branch 1: add-timeout (adds timeout setting)
|
||||||
|
# ============================================================================
|
||||||
|
Write-Host "Creating add-timeout branch..." -ForegroundColor Cyan
|
||||||
|
git switch -c add-timeout | Out-Null
|
||||||
|
|
||||||
|
$timeoutConfig = @"
|
||||||
|
{
|
||||||
|
"app": {
|
||||||
|
"name": "MyApp",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"port": 3000,
|
||||||
|
"timeout": 5000
|
||||||
|
}
|
||||||
|
}
|
||||||
|
"@
|
||||||
|
Set-Content -Path "config.json" -Value $timeoutConfig
|
||||||
|
git add .
|
||||||
|
git commit -m "Add timeout configuration" | Out-Null
|
||||||
|
|
||||||
|
# ============================================================================
|
||||||
|
# Branch 2: add-debug (adds debug setting - CONFLICTS with timeout!)
|
||||||
|
# ============================================================================
|
||||||
|
Write-Host "Creating add-debug branch..." -ForegroundColor Cyan
|
||||||
|
git switch main | Out-Null
|
||||||
|
git switch -c add-debug | Out-Null
|
||||||
|
|
||||||
|
$debugConfig = @"
|
||||||
|
{
|
||||||
|
"app": {
|
||||||
|
"name": "MyApp",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"port": 3000,
|
||||||
|
"debug": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
"@
|
||||||
|
Set-Content -Path "config.json" -Value $debugConfig
|
||||||
|
git add .
|
||||||
|
git commit -m "Add debug mode configuration" | Out-Null
|
||||||
|
|
||||||
|
# Switch back to main
|
||||||
|
git switch main | 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 repository contains:" -ForegroundColor Yellow
|
||||||
|
Write-Host " - main branch: base configuration" -ForegroundColor White
|
||||||
|
Write-Host " - add-timeout branch: adds timeout setting" -ForegroundColor White
|
||||||
|
Write-Host " - add-debug branch: adds debug setting" -ForegroundColor White
|
||||||
|
Write-Host "`nBoth branches modify the same part of config.json!" -ForegroundColor Red
|
||||||
|
Write-Host "This will cause a merge conflict when you try to merge both." -ForegroundColor Red
|
||||||
|
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. Follow the guide to discover and resolve the conflict" -ForegroundColor White
|
||||||
|
Write-Host ""
|
||||||
208
01-essentials/04-merge-conflict/verify.ps1
Normal file
208
01-essentials/04-merge-conflict/verify.ps1
Normal file
@@ -0,0 +1,208 @@
|
|||||||
|
#!/usr/bin/env pwsh
|
||||||
|
<#
|
||||||
|
.SYNOPSIS
|
||||||
|
Verifies the Module 04 challenge solution.
|
||||||
|
|
||||||
|
.DESCRIPTION
|
||||||
|
This script checks that you've successfully resolved the merge conflict by:
|
||||||
|
- Merging both branches into main
|
||||||
|
- Resolving the conflict in config.json
|
||||||
|
- Keeping both timeout and debug settings
|
||||||
|
- Ensuring valid JSON syntax
|
||||||
|
#>
|
||||||
|
|
||||||
|
$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
|
||||||
|
}
|
||||||
|
|
||||||
|
function Write-Info {
|
||||||
|
param([string]$Message)
|
||||||
|
Write-Host "[INFO] $Message" -ForegroundColor Cyan
|
||||||
|
}
|
||||||
|
|
||||||
|
# ============================================================================
|
||||||
|
# Check 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"
|
||||||
|
|
||||||
|
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
|
||||||
|
}
|
||||||
|
|
||||||
|
Write-Host "`n=== Verifying Module 04: Merge Conflicts ===" -ForegroundColor Cyan
|
||||||
|
|
||||||
|
# ============================================================================
|
||||||
|
# Check current branch
|
||||||
|
# ============================================================================
|
||||||
|
$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"
|
||||||
|
Pop-Location
|
||||||
|
exit 1
|
||||||
|
} else {
|
||||||
|
Write-Pass "No merge in progress (conflicts resolved)"
|
||||||
|
}
|
||||||
|
|
||||||
|
# ============================================================================
|
||||||
|
# Check if config.json exists
|
||||||
|
# ============================================================================
|
||||||
|
if (-not (Test-Path "config.json")) {
|
||||||
|
Write-Fail "File 'config.json' not found"
|
||||||
|
Write-Hint "The config.json file should exist"
|
||||||
|
Pop-Location
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
|
||||||
|
# ============================================================================
|
||||||
|
# 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 (<<<<<<<, =======, >>>>>>>)"
|
||||||
|
Write-Hint "Check for missing commas or brackets"
|
||||||
|
Pop-Location
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
|
||||||
|
# ============================================================================
|
||||||
|
# Check for conflict markers
|
||||||
|
# ============================================================================
|
||||||
|
if ($configContent -match '<<<<<<<|=======|>>>>>>>') {
|
||||||
|
Write-Fail "Conflict markers still present in config.json"
|
||||||
|
Write-Hint "Remove all conflict markers (<<<<<<<, =======, >>>>>>>)"
|
||||||
|
Pop-Location
|
||||||
|
exit 1
|
||||||
|
} 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 add-timeout 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 add-debug branch"
|
||||||
|
}
|
||||||
|
|
||||||
|
# ============================================================================
|
||||||
|
# Verify both branches were merged
|
||||||
|
# ============================================================================
|
||||||
|
$addTimeoutMerged = git log --oneline --grep="add-timeout" 2>$null | Select-String "Merge"
|
||||||
|
$addDebugMerged = git log --oneline --grep="add-debug" 2>$null | Select-String "Merge"
|
||||||
|
|
||||||
|
if ($addTimeoutMerged) {
|
||||||
|
Write-Pass "add-timeout branch has been merged"
|
||||||
|
} else {
|
||||||
|
# Check if it was a fast-forward merge (commits exist but no merge commit)
|
||||||
|
$timeoutCommit = git log --oneline --grep="Add timeout configuration" 2>$null
|
||||||
|
if ($timeoutCommit) {
|
||||||
|
Write-Pass "add-timeout branch changes are in main"
|
||||||
|
} else {
|
||||||
|
Write-Fail "add-timeout branch not merged"
|
||||||
|
Write-Hint "Merge with: git merge add-timeout"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($addDebugMerged) {
|
||||||
|
Write-Pass "add-debug branch has been merged"
|
||||||
|
} else {
|
||||||
|
Write-Fail "add-debug branch not merged"
|
||||||
|
Write-Hint "Merge with: git merge add-debug"
|
||||||
|
}
|
||||||
|
|
||||||
|
# ============================================================================
|
||||||
|
# Check commit count (should have both merges)
|
||||||
|
# ============================================================================
|
||||||
|
$totalCommits = [int](git rev-list --count HEAD 2>$null)
|
||||||
|
if ($totalCommits -ge 5) {
|
||||||
|
Write-Pass "Repository has $totalCommits commits (all merges complete)"
|
||||||
|
} else {
|
||||||
|
Write-Info "Repository has $totalCommits commits"
|
||||||
|
Write-Hint "Make sure both branches are merged"
|
||||||
|
}
|
||||||
|
|
||||||
|
Pop-Location
|
||||||
|
|
||||||
|
# ============================================================================
|
||||||
|
# Final summary
|
||||||
|
# ============================================================================
|
||||||
|
Write-Host ""
|
||||||
|
if ($script:allChecksPassed) {
|
||||||
|
Write-Host "=========================================" -ForegroundColor Green
|
||||||
|
Write-Host " CONGRATULATIONS! CHALLENGE PASSED!" -ForegroundColor Green
|
||||||
|
Write-Host "=========================================" -ForegroundColor Green
|
||||||
|
Write-Host "`nYou've successfully:" -ForegroundColor Cyan
|
||||||
|
Write-Host " ✓ Discovered changes using git diff" -ForegroundColor White
|
||||||
|
Write-Host " ✓ Merged the first branch" -ForegroundColor White
|
||||||
|
Write-Host " ✓ Encountered a merge conflict" -ForegroundColor White
|
||||||
|
Write-Host " ✓ Resolved the conflict by keeping both changes" -ForegroundColor White
|
||||||
|
Write-Host " ✓ Completed the merge" -ForegroundColor White
|
||||||
|
Write-Host "`nYou're now ready to handle merge conflicts in real projects!" -ForegroundColor Green
|
||||||
|
Write-Host ""
|
||||||
|
exit 0
|
||||||
|
} else {
|
||||||
|
Write-Host "[SUMMARY] Some checks failed. Review the hints above." -ForegroundColor Red
|
||||||
|
Write-Host ""
|
||||||
|
Write-Host "Quick guide:" -ForegroundColor Cyan
|
||||||
|
Write-Host " 1. Make sure you're on main: git switch main" -ForegroundColor White
|
||||||
|
Write-Host " 2. Merge first branch: git merge add-timeout" -ForegroundColor White
|
||||||
|
Write-Host " 3. Merge second branch: git merge add-debug" -ForegroundColor White
|
||||||
|
Write-Host " 4. Resolve conflict: edit config.json, remove markers, keep both settings" -ForegroundColor White
|
||||||
|
Write-Host " 5. Stage resolved file: git add config.json" -ForegroundColor White
|
||||||
|
Write-Host " 6. Complete merge: git commit" -ForegroundColor White
|
||||||
|
Write-Host " 7. Run this verify script again" -ForegroundColor White
|
||||||
|
Write-Host ""
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user