Compare commits
4 Commits
f48eefee10
...
7f34cf2d08
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
7f34cf2d08 | ||
|
|
eb63970b7a | ||
|
|
dff82c847c | ||
|
|
c057fd617b |
@@ -76,10 +76,10 @@ Write-Host "`n=== Setup Complete! ===" -ForegroundColor Green
|
||||
Write-Host "`nYour challenge environment is ready in the 'challenge/' directory." -ForegroundColor Cyan
|
||||
Write-Host "`nNext steps:" -ForegroundColor Cyan
|
||||
Write-Host " 1. cd challenge" -ForegroundColor White
|
||||
Write-Host " 2. Create a new branch: git checkout -b feature-login" -ForegroundColor White
|
||||
Write-Host " 2. Create a new branch: git switch -c feature-login" -ForegroundColor White
|
||||
Write-Host " 3. Create login.py and commit it" -ForegroundColor White
|
||||
Write-Host " 4. Make another commit on the feature branch" -ForegroundColor White
|
||||
Write-Host " 5. Switch back to main: git checkout main" -ForegroundColor White
|
||||
Write-Host " 5. Switch back to main: git switch main" -ForegroundColor White
|
||||
Write-Host " 6. Observe that login.py doesn't exist on main!" -ForegroundColor White
|
||||
Write-Host " 7. Run '..\verify.ps1' to check your solution" -ForegroundColor White
|
||||
Write-Host ""
|
||||
|
||||
@@ -57,11 +57,45 @@ Set-Content -Path "app.py" -Value $appContent
|
||||
git add .
|
||||
git commit -m "Initial project structure" | Out-Null
|
||||
|
||||
# Commit 2: Add configuration file on main
|
||||
Write-Host "Adding configuration..." -ForegroundColor Green
|
||||
$configContent = @"
|
||||
# config.py - Configuration settings
|
||||
|
||||
APP_NAME = "My Project"
|
||||
VERSION = "1.0.0"
|
||||
DEBUG = False
|
||||
"@
|
||||
Set-Content -Path "config.py" -Value $configContent
|
||||
|
||||
git add .
|
||||
git commit -m "Add basic configuration" | Out-Null
|
||||
|
||||
# Commit 3: Add database utilities on main
|
||||
Write-Host "Adding database utilities..." -ForegroundColor Green
|
||||
$dbContent = @"
|
||||
# database.py - Database utilities
|
||||
|
||||
def connect():
|
||||
"""Connect to database."""
|
||||
print("Connecting to database...")
|
||||
return True
|
||||
|
||||
def disconnect():
|
||||
"""Disconnect from database."""
|
||||
print("Disconnecting...")
|
||||
return True
|
||||
"@
|
||||
Set-Content -Path "database.py" -Value $dbContent
|
||||
|
||||
git add .
|
||||
git commit -m "Add database utilities" | Out-Null
|
||||
|
||||
# Create feature-login branch
|
||||
Write-Host "Creating feature-login branch..." -ForegroundColor Green
|
||||
git switch -c feature-login | Out-Null
|
||||
|
||||
# Commit on feature-login: Add login module
|
||||
# Commit 4: Add login module on feature-login
|
||||
Write-Host "Adding login functionality on feature-login..." -ForegroundColor Green
|
||||
$loginContent = @"
|
||||
# login.py - User login module
|
||||
@@ -82,7 +116,36 @@ Set-Content -Path "login.py" -Value $loginContent
|
||||
git add .
|
||||
git commit -m "Add login module" | Out-Null
|
||||
|
||||
# Second commit on feature-login: Integrate login with app
|
||||
# Commit 5: Add password validation on feature-login
|
||||
$loginContent = @"
|
||||
# login.py - User login module
|
||||
|
||||
def validate_password(password):
|
||||
"""Validate password strength."""
|
||||
if len(password) < 8:
|
||||
return False
|
||||
return True
|
||||
|
||||
def login(username, password):
|
||||
"""Authenticate a user."""
|
||||
if not validate_password(password):
|
||||
print("Password too weak!")
|
||||
return False
|
||||
print(f"Authenticating user: {username}")
|
||||
# TODO: Add actual authentication logic
|
||||
return True
|
||||
|
||||
def logout(username):
|
||||
"""Log out a user."""
|
||||
print(f"Logging out user: {username}")
|
||||
return True
|
||||
"@
|
||||
Set-Content -Path "login.py" -Value $loginContent
|
||||
|
||||
git add .
|
||||
git commit -m "Add password validation" | Out-Null
|
||||
|
||||
# Commit 6: Integrate login with app on feature-login
|
||||
$appContent = @"
|
||||
# app.py - Main application file
|
||||
from login import login, logout
|
||||
@@ -90,7 +153,7 @@ from login import login, logout
|
||||
def main():
|
||||
print("Welcome to My App!")
|
||||
# Add login integration
|
||||
if login("testuser", "password"):
|
||||
if login("testuser", "password123"):
|
||||
print("Login successful!")
|
||||
pass
|
||||
|
||||
@@ -102,11 +165,30 @@ Set-Content -Path "app.py" -Value $appContent
|
||||
git add .
|
||||
git commit -m "Integrate login with main app" | Out-Null
|
||||
|
||||
# Commit 7: Add session management on feature-login
|
||||
$sessionContent = @"
|
||||
# session.py - Session management
|
||||
|
||||
class Session:
|
||||
def __init__(self, username):
|
||||
self.username = username
|
||||
self.active = True
|
||||
|
||||
def end(self):
|
||||
"""End the session."""
|
||||
self.active = False
|
||||
print(f"Session ended for {self.username}")
|
||||
"@
|
||||
Set-Content -Path "session.py" -Value $sessionContent
|
||||
|
||||
git add .
|
||||
git commit -m "Add session management" | Out-Null
|
||||
|
||||
# Switch back to main branch
|
||||
Write-Host "Switching back to main branch..." -ForegroundColor Green
|
||||
git switch main | Out-Null
|
||||
|
||||
# Make a commit on main (creates divergence)
|
||||
# Commit 8: Update README on main (creates divergence)
|
||||
Write-Host "Adding documentation on main (creates divergence)..." -ForegroundColor Green
|
||||
$readmeContent = @"
|
||||
# My Project
|
||||
@@ -132,14 +214,29 @@ Set-Content -Path "README.md" -Value $readmeContent
|
||||
git add .
|
||||
git commit -m "Update README with setup instructions" | Out-Null
|
||||
|
||||
# Commit 9: Update configuration on main
|
||||
$configContent = @"
|
||||
# config.py - Configuration settings
|
||||
|
||||
APP_NAME = "My Project"
|
||||
VERSION = "1.0.0"
|
||||
DEBUG = False
|
||||
DATABASE_PATH = "./data/app.db"
|
||||
LOG_LEVEL = "INFO"
|
||||
"@
|
||||
Set-Content -Path "config.py" -Value $configContent
|
||||
|
||||
git add .
|
||||
git commit -m "Add database path to config" | 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 "`nScenario: You have two divergent branches!" -ForegroundColor Yellow
|
||||
Write-Host " - main: Has updated documentation" -ForegroundColor White
|
||||
Write-Host " - feature-login: Has new login functionality" -ForegroundColor White
|
||||
Write-Host " - main: Has 5 commits (config, database utils, README updates)" -ForegroundColor White
|
||||
Write-Host " - feature-login: Has 4 commits (login, validation, session)" -ForegroundColor White
|
||||
Write-Host "`nNext steps:" -ForegroundColor Cyan
|
||||
Write-Host " 1. cd challenge" -ForegroundColor White
|
||||
Write-Host " 2. View the branch structure: git log --oneline --graph --all" -ForegroundColor White
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
# Module 06: Merge Conflicts
|
||||
# Module 05: Merge Conflicts
|
||||
|
||||
## Learning Objectives
|
||||
|
||||
@@ -6,101 +6,476 @@ By the end of this module, you will:
|
||||
- Understand what merge conflicts are and why they occur
|
||||
- Identify merge conflicts in your repository
|
||||
- Read and interpret conflict markers
|
||||
- Resolve merge conflicts manually
|
||||
- Resolve merge conflicts manually step-by-step
|
||||
- Complete a merge after resolving conflicts
|
||||
|
||||
## Challenge Description
|
||||
## Challenge
|
||||
|
||||
### Setup
|
||||
|
||||
Run the setup script to create your challenge environment:
|
||||
|
||||
```powershell
|
||||
.\setup.ps1
|
||||
```
|
||||
|
||||
This will create a `challenge/` directory with a repository that has a merge conflict waiting to happen!
|
||||
|
||||
### Your Task
|
||||
|
||||
You have a repository with a main branch and a feature branch called `update-config`. Both branches have modified the same configuration file in different ways, creating a merge conflict.
|
||||
|
||||
Your task is to:
|
||||
**Your mission:**
|
||||
1. Attempt to merge the `update-config` branch into `main`
|
||||
2. Identify and understand the merge conflict
|
||||
3. Resolve the conflict by keeping both the timeout setting from `main` AND the debug setting from `update-config`
|
||||
4. Complete the merge with an appropriate commit message
|
||||
2. Git will tell you there's a conflict - don't panic!
|
||||
3. Resolve the conflict by keeping BOTH settings (timeout AND debug)
|
||||
4. Complete the merge
|
||||
|
||||
## Key Concepts
|
||||
**Steps to follow:**
|
||||
|
||||
### What Are Merge Conflicts?
|
||||
1. Navigate to the challenge directory: `cd challenge`
|
||||
2. Make sure you're on main: `git branch`
|
||||
3. Try to merge: `git merge update-config`
|
||||
4. Git will report a conflict!
|
||||
5. Open `config.py` in your text editor
|
||||
6. Follow the step-by-step guide below to resolve it
|
||||
7. Save the file, stage it, and commit
|
||||
|
||||
A merge conflict occurs when Git cannot automatically combine changes from two branches because they modify the same part of the same file in different ways. When this happens, Git pauses the merge and asks you to manually resolve the conflict.
|
||||
## What Are Merge Conflicts?
|
||||
|
||||
### Conflict Markers
|
||||
|
||||
When a conflict occurs, Git adds special markers to the affected files:
|
||||
A **merge conflict** occurs when Git cannot automatically combine changes because both branches modified the same lines in the same file.
|
||||
|
||||
**Example scenario:**
|
||||
```
|
||||
<<<<<<< HEAD
|
||||
Your current branch's changes
|
||||
=======
|
||||
The incoming branch's changes
|
||||
>>>>>>> branch-name
|
||||
main branch changes line 5: TIMEOUT = 30
|
||||
feature branch changes line 5: DEBUG = True
|
||||
```
|
||||
|
||||
- `<<<<<<< HEAD`: Marks the beginning of your current branch's version
|
||||
- `=======`: Separates the two versions
|
||||
- `>>>>>>> branch-name`: Marks the end of the incoming branch's version
|
||||
Git doesn't know which one you want! So it asks you to decide.
|
||||
|
||||
### Resolving Conflicts
|
||||
**When do conflicts happen?**
|
||||
- ✅ Two branches modify the same line(s)
|
||||
- ✅ One branch deletes a file that another branch modifies
|
||||
- ❌ Different files are changed (no conflict!)
|
||||
- ❌ Different lines in the same file are changed (no conflict!)
|
||||
|
||||
To resolve a conflict:
|
||||
1. Open the conflicted file in your editor
|
||||
2. Look for the conflict markers
|
||||
3. Decide which changes to keep (you can keep one side, the other, or combine both)
|
||||
4. Remove the conflict markers
|
||||
5. Stage the resolved file with `git add`
|
||||
6. Complete the merge with `git commit`
|
||||
## Step-by-Step: Resolving Your First Conflict
|
||||
|
||||
## Useful Commands
|
||||
### Step 1: Attempt the Merge
|
||||
|
||||
```bash
|
||||
# Merge a branch (may result in conflicts)
|
||||
git merge <branch-name>
|
||||
|
||||
# Check the status during a conflict
|
||||
git status
|
||||
|
||||
# See which files have conflicts
|
||||
git diff --name-only --diff-filter=U
|
||||
|
||||
# View the conflict in detail
|
||||
git diff
|
||||
|
||||
# After resolving, stage the file
|
||||
git add <file>
|
||||
|
||||
# Complete the merge
|
||||
git commit
|
||||
|
||||
# If you want to abort the merge
|
||||
git merge --abort
|
||||
|
||||
# Visualize the branch history
|
||||
git log --oneline --graph --all
|
||||
cd challenge
|
||||
git merge update-config
|
||||
```
|
||||
|
||||
**You'll see:**
|
||||
```
|
||||
Auto-merging config.py
|
||||
CONFLICT (content): Merge conflict in config.py
|
||||
Automatic merge failed; fix conflicts and then commit the result.
|
||||
```
|
||||
|
||||
**Don't panic!** This is normal. Git is just asking for your help.
|
||||
|
||||
---
|
||||
|
||||
### Step 2: Check What Happened
|
||||
|
||||
```bash
|
||||
git status
|
||||
```
|
||||
|
||||
**You'll see:**
|
||||
```
|
||||
On branch main
|
||||
You have unmerged paths.
|
||||
(fix conflicts and run "git commit")
|
||||
(use "git merge --abort" to abort the merge)
|
||||
|
||||
Unmerged paths:
|
||||
(use "git add <file>..." to mark resolution)
|
||||
both modified: config.py
|
||||
```
|
||||
|
||||
This tells you that `config.py` needs your attention!
|
||||
|
||||
---
|
||||
|
||||
### Step 3: Open the Conflicted File
|
||||
|
||||
Open `config.py` in your text editor. You'll see something like this:
|
||||
|
||||
```python
|
||||
# config.py - Application configuration
|
||||
|
||||
APP_NAME = "My Application"
|
||||
VERSION = "1.0.0"
|
||||
<<<<<<< HEAD
|
||||
TIMEOUT = 30
|
||||
=======
|
||||
DEBUG = True
|
||||
>>>>>>> update-config
|
||||
```
|
||||
|
||||
**Let's break down what you're seeing:**
|
||||
|
||||
---
|
||||
|
||||
## Understanding Conflict Markers
|
||||
|
||||
Git has added special markers to show you both versions:
|
||||
|
||||
```python
|
||||
<<<<<<< HEAD ← Start of YOUR version (current branch)
|
||||
TIMEOUT = 30 ← What YOU have on main
|
||||
======= ← Divider between versions
|
||||
DEBUG = True ← What THEY have on update-config
|
||||
>>>>>>> update-config ← End of THEIR version
|
||||
```
|
||||
|
||||
**The three parts:**
|
||||
|
||||
1. **`<<<<<<< HEAD`** - Everything between here and `=======` is YOUR current branch's version
|
||||
2. **`=======`** - This separates the two versions
|
||||
3. **`>>>>>>> update-config`** - Everything between `=======` and here is the INCOMING branch's version
|
||||
|
||||
---
|
||||
|
||||
## Step 4: Decide What to Keep
|
||||
|
||||
You have three options:
|
||||
|
||||
**Option A: Keep YOUR version (main)**
|
||||
```python
|
||||
# config.py - Application configuration
|
||||
|
||||
APP_NAME = "My Application"
|
||||
VERSION = "1.0.0"
|
||||
TIMEOUT = 30
|
||||
```
|
||||
|
||||
**Option B: Keep THEIR version (update-config)**
|
||||
```python
|
||||
# config.py - Application configuration
|
||||
|
||||
APP_NAME = "My Application"
|
||||
VERSION = "1.0.0"
|
||||
DEBUG = True
|
||||
```
|
||||
|
||||
**Option C: Keep BOTH (this is what we want!)**
|
||||
```python
|
||||
# config.py - Application configuration
|
||||
|
||||
APP_NAME = "My Application"
|
||||
VERSION = "1.0.0"
|
||||
TIMEOUT = 30
|
||||
DEBUG = True
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Step 5: Edit the File to Resolve the Conflict
|
||||
|
||||
**What the file looks like NOW (with conflict markers):**
|
||||
```python
|
||||
# config.py - Application configuration
|
||||
|
||||
APP_NAME = "My Application"
|
||||
VERSION = "1.0.0"
|
||||
<<<<<<< HEAD
|
||||
TIMEOUT = 30
|
||||
=======
|
||||
DEBUG = True
|
||||
>>>>>>> update-config
|
||||
```
|
||||
|
||||
**What you need to do:**
|
||||
|
||||
1. **Delete** the line `<<<<<<< HEAD`
|
||||
2. **Keep** the line `TIMEOUT = 30`
|
||||
3. **Delete** the line `=======`
|
||||
4. **Keep** the line `DEBUG = True`
|
||||
5. **Delete** the line `>>>>>>> update-config`
|
||||
|
||||
**What the file should look like AFTER (conflict resolved):**
|
||||
```python
|
||||
# config.py - Application configuration
|
||||
|
||||
APP_NAME = "My Application"
|
||||
VERSION = "1.0.0"
|
||||
TIMEOUT = 30
|
||||
DEBUG = True
|
||||
```
|
||||
|
||||
**Save the file!**
|
||||
|
||||
---
|
||||
|
||||
## Step 6: Mark the Conflict as Resolved
|
||||
|
||||
Tell Git you've fixed the conflict by staging the file:
|
||||
|
||||
```bash
|
||||
git add config.py
|
||||
```
|
||||
|
||||
This tells Git: "I've resolved the conflict in this file, it's ready to be committed."
|
||||
|
||||
---
|
||||
|
||||
## Step 7: Check Your Status
|
||||
|
||||
```bash
|
||||
git status
|
||||
```
|
||||
|
||||
**You should see:**
|
||||
```
|
||||
On branch main
|
||||
All conflicts fixed but you are still merging.
|
||||
(use "git commit" to conclude merge)
|
||||
|
||||
Changes to be committed:
|
||||
modified: config.py
|
||||
```
|
||||
|
||||
Great! Git knows the conflict is resolved and is ready for you to complete the merge.
|
||||
|
||||
---
|
||||
|
||||
## Step 8: Complete the Merge
|
||||
|
||||
```bash
|
||||
git commit
|
||||
```
|
||||
|
||||
Git will open your editor with a default merge message:
|
||||
```
|
||||
Merge branch 'update-config'
|
||||
|
||||
# Conflicts:
|
||||
# config.py
|
||||
```
|
||||
|
||||
You can keep this message or customize it. Save and close the editor.
|
||||
|
||||
**Or use a one-liner:**
|
||||
```bash
|
||||
git commit -m "Merge update-config: resolve config conflict"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Step 9: Verify the Merge
|
||||
|
||||
```bash
|
||||
git log --oneline --graph
|
||||
```
|
||||
|
||||
You should see your merge commit!
|
||||
|
||||
```bash
|
||||
cat config.py
|
||||
```
|
||||
|
||||
Verify the file has BOTH settings and NO conflict markers!
|
||||
|
||||
---
|
||||
|
||||
## Visual Summary: Before and After
|
||||
|
||||
### Before Resolution (WRONG ❌)
|
||||
```python
|
||||
# config.py
|
||||
APP_NAME = "My Application"
|
||||
VERSION = "1.0.0"
|
||||
<<<<<<< HEAD
|
||||
TIMEOUT = 30
|
||||
=======
|
||||
DEBUG = True
|
||||
>>>>>>> update-config
|
||||
```
|
||||
**This will NOT run! Conflict markers are syntax errors!**
|
||||
|
||||
### After Resolution (CORRECT ✅)
|
||||
```python
|
||||
# config.py
|
||||
APP_NAME = "My Application"
|
||||
VERSION = "1.0.0"
|
||||
TIMEOUT = 30
|
||||
DEBUG = True
|
||||
```
|
||||
**Clean code, no markers, both settings preserved!**
|
||||
|
||||
---
|
||||
|
||||
## Common Mistakes to Avoid
|
||||
|
||||
### ❌ Mistake 1: Forgetting to Remove Conflict Markers
|
||||
```python
|
||||
TIMEOUT = 30
|
||||
======= ← Still has conflict marker!
|
||||
DEBUG = True
|
||||
```
|
||||
**This is invalid Python code and will crash!**
|
||||
|
||||
### ❌ Mistake 2: Committing Without Staging
|
||||
```bash
|
||||
# Wrong order:
|
||||
git commit # Error! File not staged
|
||||
|
||||
# Correct order:
|
||||
git add config.py # Stage first
|
||||
git commit # Then commit
|
||||
```
|
||||
|
||||
### ❌ Mistake 3: Only Keeping One Side When You Need Both
|
||||
```python
|
||||
# If the task asks for BOTH settings, this is wrong:
|
||||
TIMEOUT = 30
|
||||
# Missing DEBUG = True
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Useful Commands Reference
|
||||
|
||||
```bash
|
||||
# During a conflict
|
||||
git status # See which files have conflicts
|
||||
git diff # See the conflict in detail
|
||||
|
||||
# Resolving
|
||||
git add <file> # Mark file as resolved
|
||||
git commit # Complete the merge
|
||||
|
||||
# If you want to start over
|
||||
git merge --abort # Cancel the merge, go back to before
|
||||
|
||||
# After resolving
|
||||
git log --oneline --graph # See the merge commit
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Real-World Conflict Resolution Workflow
|
||||
|
||||
**Here's what you'll do every time you have a conflict:**
|
||||
|
||||
```bash
|
||||
# 1. Attempt the merge
|
||||
git merge feature-branch
|
||||
# → Git says: "CONFLICT! Fix it!"
|
||||
|
||||
# 2. Check what's wrong
|
||||
git status
|
||||
# → Shows which files have conflicts
|
||||
|
||||
# 3. Open the file, find the markers
|
||||
# <<<<<<< HEAD
|
||||
# your version
|
||||
# =======
|
||||
# their version
|
||||
# >>>>>>> branch
|
||||
|
||||
# 4. Edit the file to resolve
|
||||
# Remove the markers, keep what you need
|
||||
|
||||
# 5. Stage the resolved file
|
||||
git add config.py
|
||||
|
||||
# 6. Complete the merge
|
||||
git commit -m "Resolve conflict in config.py"
|
||||
|
||||
# 7. Celebrate! 🎉
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## What If You Get Stuck?
|
||||
|
||||
### Option 1: Abort the Merge
|
||||
```bash
|
||||
git merge --abort
|
||||
```
|
||||
This puts everything back to how it was before the merge. You can try again!
|
||||
|
||||
### Option 2: Ask for Help
|
||||
```bash
|
||||
git status # See what's going on
|
||||
git diff # See the conflict details
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Pro Tips
|
||||
|
||||
✅ **Use `git status` constantly** - It tells you exactly what to do next
|
||||
|
||||
✅ **Search for `<<<<<<<`** - Your editor's search function can find all conflicts quickly
|
||||
|
||||
✅ **Test after resolving** - Make sure your code still works!
|
||||
|
||||
✅ **Read both sides carefully** - Sometimes you need parts from each version
|
||||
|
||||
✅ **Take your time** - Conflicts are not a race. Understand what changed and why.
|
||||
|
||||
---
|
||||
|
||||
## Verification
|
||||
|
||||
Run the verification script to check your solution:
|
||||
Once you've resolved the conflict and completed the merge, verify your solution:
|
||||
|
||||
```bash
|
||||
```powershell
|
||||
.\verify.ps1
|
||||
```
|
||||
|
||||
The verification will check that:
|
||||
- The merge conflict was resolved
|
||||
- The merge was completed successfully
|
||||
- Both configuration settings were preserved correctly
|
||||
- The commit history shows the merge
|
||||
- ✅ The merge conflict was resolved
|
||||
- ✅ The merge was completed successfully
|
||||
- ✅ BOTH settings are in the config file (TIMEOUT and DEBUG)
|
||||
- ✅ NO conflict markers remain
|
||||
- ✅ The merge commit exists in history
|
||||
|
||||
## Tips
|
||||
---
|
||||
|
||||
- Don't panic when you see a conflict - it's a normal part of working with Git
|
||||
- Read the conflict markers carefully to understand both versions
|
||||
- You can use `git status` to see which files have conflicts
|
||||
- Always test your code after resolving conflicts to ensure it still works
|
||||
- The conflict markers (`<<<<<<<`, `=======`, `>>>>>>>`) must be completely removed from the final file
|
||||
## Need to Start Over?
|
||||
|
||||
## What You'll Learn
|
||||
If you want to reset the challenge and start fresh:
|
||||
|
||||
Merge conflicts are inevitable when working on a team or even when working alone across multiple branches. Learning to resolve them confidently is an essential Git skill. This module teaches you the fundamentals of conflict resolution that you'll use throughout your development career.
|
||||
```powershell
|
||||
.\reset.ps1
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## What You've Learned
|
||||
|
||||
🎉 **Congratulations!** You can now:
|
||||
- Recognize when a merge conflict occurs
|
||||
- Read and understand conflict markers
|
||||
- Edit files to resolve conflicts
|
||||
- Stage resolved files with `git add`
|
||||
- Complete a merge with `git commit`
|
||||
|
||||
**This is a critical skill!** Every developer encounters merge conflicts. Now you know exactly what to do when they happen.
|
||||
|
||||
---
|
||||
|
||||
## Quick Reference Card
|
||||
|
||||
**When you see a conflict:**
|
||||
|
||||
1. **Don't panic** ✅
|
||||
2. **Run `git status`** to see which files
|
||||
3. **Open the file** in your editor
|
||||
4. **Find the markers** (`<<<<<<<`, `=======`, `>>>>>>>`)
|
||||
5. **Decide what to keep** (one side, other side, or both)
|
||||
6. **Remove ALL markers** (the `<<<<<<<`, `=======`, `>>>>>>>` lines)
|
||||
7. **Save the file**
|
||||
8. **Stage it** (`git add filename`)
|
||||
9. **Commit** (`git commit`)
|
||||
10. **Verify** (`git status`, `git log --oneline --graph`)
|
||||
|
||||
**Remember:** The conflict markers are NOT valid code - they MUST be removed!
|
||||
|
||||
@@ -60,7 +60,7 @@ git add config.json
|
||||
git commit -m "Add timeout configuration" | Out-Null
|
||||
|
||||
# Switch to feature branch: Add debug setting (conflicting change)
|
||||
git checkout update-config | Out-Null
|
||||
git switch update-config | Out-Null
|
||||
|
||||
$featureConfig = @"
|
||||
{
|
||||
@@ -78,7 +78,7 @@ git add config.json
|
||||
git commit -m "Add debug mode configuration" | Out-Null
|
||||
|
||||
# Switch back to main branch
|
||||
git checkout main | Out-Null
|
||||
git switch main | Out-Null
|
||||
|
||||
# Return to module directory
|
||||
Set-Location ..
|
||||
|
||||
@@ -128,7 +128,8 @@ if ($parentCount -ne 2) {
|
||||
}
|
||||
|
||||
# Check that both branches are merged
|
||||
$branches = git branch --merged 2>$null
|
||||
$branches = git branch --merged update-config 2>$null
|
||||
Write-Host "$branches $($branches -notmatch 'update-config')"
|
||||
if ($branches -notmatch "update-config") {
|
||||
Write-Host "[FAIL] The 'update-config' branch was not merged." -ForegroundColor Red
|
||||
Set-Location ..
|
||||
|
||||
904
01_essentials/09-multiplayer/FACILITATOR-SETUP.md
Normal file
904
01_essentials/09-multiplayer/FACILITATOR-SETUP.md
Normal file
@@ -0,0 +1,904 @@
|
||||
# Facilitator Setup Guide - The Great Print Project
|
||||
|
||||
This guide helps workshop facilitators set up the cloud-based multiplayer Git module.
|
||||
|
||||
## Overview
|
||||
|
||||
The Great Print Project is a collaborative Git exercise where pairs of students work together on a shared repository hosted on your Gitea server at **https://git.frod.dk/multiplayer**.
|
||||
|
||||
**What participants will do:**
|
||||
- Clone a real repository from your server
|
||||
- Collaborate with partners on shared branches
|
||||
- Deliberately create and resolve merge conflicts
|
||||
- Create pull requests and review code
|
||||
- Experience the full collaborative Git workflow
|
||||
|
||||
---
|
||||
|
||||
## Prerequisites
|
||||
|
||||
### Gitea Server Setup
|
||||
|
||||
You should have:
|
||||
- Gitea running at https://git.frod.dk/multiplayer
|
||||
- Admin access to create repositories and users
|
||||
- HTTPS or SSH access enabled for Git operations
|
||||
|
||||
**Need to set up Gitea?** See the main workshop's `GITEA-SETUP.md` for Docker + Cloudflare Tunnel instructions.
|
||||
|
||||
### Workshop Materials
|
||||
|
||||
Participants need:
|
||||
- Access to the module README in `01_essentials/09-multiplayer/README.md`
|
||||
- Git installed (version 2.23+)
|
||||
- Python 3.6+ (to run the print project)
|
||||
- Text editor
|
||||
|
||||
---
|
||||
|
||||
## Pre-Workshop Setup
|
||||
|
||||
### Step 1: Create User Accounts
|
||||
|
||||
Create individual Gitea accounts for each participant.
|
||||
|
||||
**Recommended naming:**
|
||||
- `student01`, `student02`, `student03`, etc.
|
||||
- Or use their real names/emails if preferred
|
||||
|
||||
**Two approaches:**
|
||||
|
||||
**Option A: Manual account creation**
|
||||
1. Go to Gitea admin panel
|
||||
2. Create users one by one
|
||||
3. Set initial passwords (students can change later)
|
||||
4. Provide credentials to students
|
||||
|
||||
**Option B: Self-registration** (if you trust your network)
|
||||
1. Enable self-registration in Gitea settings
|
||||
2. Provide registration URL to students
|
||||
3. They create their own accounts
|
||||
4. You verify and approve accounts
|
||||
|
||||
**Access tokens (recommended for HTTPS):**
|
||||
- Have students create personal access tokens after logging in
|
||||
- Settings → Applications → Generate New Token
|
||||
- Token needs `repo` scope
|
||||
- Students use token as password when pushing/pulling
|
||||
|
||||
### Step 2: Create the Repository
|
||||
|
||||
Create the shared repository: **great-print-project**
|
||||
|
||||
**Via Gitea web UI:**
|
||||
1. Log in as admin or organization account
|
||||
2. Click "+" → "New Repository"
|
||||
3. **Name:** `great-print-project`
|
||||
4. **Owner:** `multiplayer` (organization) or your admin account
|
||||
5. **Visibility:** Private (only visible to students you add)
|
||||
6. **Initialize:** Check "Initialize this repository with selected files"
|
||||
7. **README:** Yes
|
||||
8. **License:** None
|
||||
9. **.gitignore:** Python
|
||||
10. Click "Create Repository"
|
||||
|
||||
**Via command line (alternative):**
|
||||
```bash
|
||||
# Create local directory
|
||||
mkdir great-print-project
|
||||
cd great-print-project
|
||||
|
||||
# Initialize git
|
||||
git init
|
||||
|
||||
# Add files (see Step 3)
|
||||
git add .
|
||||
git commit -m "Initial commit: The Great Print Project"
|
||||
|
||||
# Create bare repo on server
|
||||
ssh user@git.frod.dk
|
||||
cd /path/to/gitea/repositories/multiplayer
|
||||
git init --bare great-print-project.git
|
||||
exit
|
||||
|
||||
# Push to server
|
||||
git remote add origin git@git.frod.dk:multiplayer/great-print-project.git
|
||||
git push -u origin main
|
||||
```
|
||||
|
||||
### Step 3: Add Starter Code to Repository
|
||||
|
||||
Commit these four files to the repository:
|
||||
|
||||
#### File 1: main.py
|
||||
|
||||
```python
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
The Great Print Project
|
||||
A collaborative Git exercise
|
||||
|
||||
When everyone completes their assigned functions,
|
||||
this program will print the complete alphabet and numbers!
|
||||
"""
|
||||
|
||||
from letters import print_letters
|
||||
from numbers import print_numbers
|
||||
|
||||
def main():
|
||||
print("=" * 50)
|
||||
print(" THE GREAT PRINT PROJECT")
|
||||
print("=" * 50)
|
||||
print("\nLetters:")
|
||||
print_letters()
|
||||
print() # New line after letters
|
||||
|
||||
print("\nNumbers:")
|
||||
print_numbers()
|
||||
print() # New line after numbers
|
||||
|
||||
print("\n" + "=" * 50)
|
||||
print(" PROJECT COMPLETE!")
|
||||
print("=" * 50)
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
```
|
||||
|
||||
#### File 2: letters.py
|
||||
|
||||
```python
|
||||
"""
|
||||
Letter Printing Functions
|
||||
Each pair completes their assigned functions.
|
||||
|
||||
Expected output: A B C D E F G H I J K L M N O P Q R S T U V W X Y Z
|
||||
"""
|
||||
|
||||
def print_a():
|
||||
"""Print letter A - EXAMPLE (already completed)"""
|
||||
print("A", end=" ")
|
||||
|
||||
def print_b():
|
||||
# TODO: Pair 1 - implement this function
|
||||
pass
|
||||
|
||||
def print_c():
|
||||
# TODO: Pair 1 - implement this function
|
||||
pass
|
||||
|
||||
def print_d():
|
||||
# TODO: Pair 1 - implement this function
|
||||
pass
|
||||
|
||||
def print_e():
|
||||
# TODO: Pair 2 - implement this function
|
||||
pass
|
||||
|
||||
def print_f():
|
||||
# TODO: Pair 2 - implement this function
|
||||
pass
|
||||
|
||||
def print_g():
|
||||
# TODO: Pair 2 - implement this function
|
||||
pass
|
||||
|
||||
def print_h():
|
||||
# TODO: Pair 3 - implement this function
|
||||
pass
|
||||
|
||||
def print_i():
|
||||
# TODO: Pair 3 - implement this function
|
||||
pass
|
||||
|
||||
def print_j():
|
||||
# TODO: Pair 3 - implement this function
|
||||
pass
|
||||
|
||||
def print_k():
|
||||
# TODO: Pair 4 - implement this function
|
||||
pass
|
||||
|
||||
def print_l():
|
||||
# TODO: Pair 4 - implement this function
|
||||
pass
|
||||
|
||||
def print_m():
|
||||
# TODO: Pair 4 - implement this function
|
||||
pass
|
||||
|
||||
def print_n():
|
||||
# TODO: Pair 5 - implement this function
|
||||
pass
|
||||
|
||||
def print_o():
|
||||
# TODO: Pair 5 - implement this function
|
||||
pass
|
||||
|
||||
def print_p():
|
||||
# TODO: Pair 5 - implement this function
|
||||
pass
|
||||
|
||||
def print_q():
|
||||
# TODO: Pair 6 - implement this function
|
||||
pass
|
||||
|
||||
def print_r():
|
||||
# TODO: Pair 6 - implement this function
|
||||
pass
|
||||
|
||||
def print_s():
|
||||
# TODO: Pair 6 - implement this function
|
||||
pass
|
||||
|
||||
def print_t():
|
||||
# TODO: Pair 7 - implement this function
|
||||
pass
|
||||
|
||||
def print_u():
|
||||
# TODO: Pair 7 - implement this function
|
||||
pass
|
||||
|
||||
def print_v():
|
||||
# TODO: Pair 7 - implement this function
|
||||
pass
|
||||
|
||||
def print_w():
|
||||
# TODO: Pair 8 - implement this function
|
||||
pass
|
||||
|
||||
def print_x():
|
||||
# TODO: Pair 8 - implement this function
|
||||
pass
|
||||
|
||||
def print_y():
|
||||
# TODO: Pair 8 - implement this function
|
||||
pass
|
||||
|
||||
def print_z():
|
||||
# TODO: Pair 9 - implement this function
|
||||
pass
|
||||
|
||||
|
||||
def print_letters():
|
||||
"""Print all letters A-Z"""
|
||||
print_a()
|
||||
print_b()
|
||||
print_c()
|
||||
print_d()
|
||||
print_e()
|
||||
print_f()
|
||||
print_g()
|
||||
print_h()
|
||||
print_i()
|
||||
print_j()
|
||||
print_k()
|
||||
print_l()
|
||||
print_m()
|
||||
print_n()
|
||||
print_o()
|
||||
print_p()
|
||||
print_q()
|
||||
print_r()
|
||||
print_s()
|
||||
print_t()
|
||||
print_u()
|
||||
print_v()
|
||||
print_w()
|
||||
print_x()
|
||||
print_y()
|
||||
print_z()
|
||||
```
|
||||
|
||||
#### File 3: numbers.py
|
||||
|
||||
```python
|
||||
"""
|
||||
Number Printing Functions
|
||||
Each pair completes their assigned functions.
|
||||
|
||||
Expected output: 0 1 2 3 4 5 6 7 8 9
|
||||
"""
|
||||
|
||||
def print_0():
|
||||
# TODO: Pair 9 - implement this function
|
||||
pass
|
||||
|
||||
def print_1():
|
||||
# TODO: Pair 10 - implement this function
|
||||
pass
|
||||
|
||||
def print_2():
|
||||
# TODO: Pair 10 - implement this function
|
||||
pass
|
||||
|
||||
def print_3():
|
||||
# TODO: Pair 10 - implement this function
|
||||
pass
|
||||
|
||||
def print_4():
|
||||
# TODO: Pair 11 - implement this function
|
||||
pass
|
||||
|
||||
def print_5():
|
||||
# TODO: Pair 11 - implement this function
|
||||
pass
|
||||
|
||||
def print_6():
|
||||
# TODO: Pair 11 - implement this function
|
||||
pass
|
||||
|
||||
def print_7():
|
||||
# TODO: Pair 12 - implement this function
|
||||
pass
|
||||
|
||||
def print_8():
|
||||
# TODO: Pair 12 - implement this function
|
||||
pass
|
||||
|
||||
def print_9():
|
||||
# TODO: Pair 12 - implement this function
|
||||
pass
|
||||
|
||||
|
||||
def print_numbers():
|
||||
"""Print all numbers 0-9"""
|
||||
print_0()
|
||||
print_1()
|
||||
print_2()
|
||||
print_3()
|
||||
print_4()
|
||||
print_5()
|
||||
print_6()
|
||||
print_7()
|
||||
print_8()
|
||||
print_9()
|
||||
```
|
||||
|
||||
#### File 4: assignments.md
|
||||
|
||||
```markdown
|
||||
# Pair Assignments
|
||||
|
||||
## How This Works
|
||||
|
||||
Each pair is assigned 3 functions to implement. You'll work together on a shared branch.
|
||||
|
||||
**Important:** Check with your facilitator for your pair number and assignment!
|
||||
|
||||
---
|
||||
|
||||
## Assignments
|
||||
|
||||
### Pair 1
|
||||
- **Functions:** `print_b()`, `print_c()`, `print_d()`
|
||||
- **File:** `letters.py`
|
||||
- **Branch:** `pair-1-bcd`
|
||||
|
||||
### Pair 2
|
||||
- **Functions:** `print_e()`, `print_f()`, `print_g()`
|
||||
- **File:** `letters.py`
|
||||
- **Branch:** `pair-2-efg`
|
||||
|
||||
### Pair 3
|
||||
- **Functions:** `print_h()`, `print_i()`, `print_j()`
|
||||
- **File:** `letters.py`
|
||||
- **Branch:** `pair-3-hij`
|
||||
|
||||
### Pair 4
|
||||
- **Functions:** `print_k()`, `print_l()`, `print_m()`
|
||||
- **File:** `letters.py`
|
||||
- **Branch:** `pair-4-klm`
|
||||
|
||||
### Pair 5
|
||||
- **Functions:** `print_n()`, `print_o()`, `print_p()`
|
||||
- **File:** `letters.py`
|
||||
- **Branch:** `pair-5-nop`
|
||||
|
||||
### Pair 6
|
||||
- **Functions:** `print_q()`, `print_r()`, `print_s()`
|
||||
- **File:** `letters.py`
|
||||
- **Branch:** `pair-6-qrs`
|
||||
|
||||
### Pair 7
|
||||
- **Functions:** `print_t()`, `print_u()`, `print_v()`
|
||||
- **File:** `letters.py`
|
||||
- **Branch:** `pair-7-tuv`
|
||||
|
||||
### Pair 8
|
||||
- **Functions:** `print_w()`, `print_x()`, `print_y()`
|
||||
- **File:** `letters.py`
|
||||
- **Branch:** `pair-8-wxy`
|
||||
|
||||
### Pair 9
|
||||
- **Functions:** `print_z()`, `print_0()`, `print_1()`
|
||||
- **Files:** `letters.py`, `numbers.py`
|
||||
- **Branch:** `pair-9-z01`
|
||||
|
||||
### Pair 10
|
||||
- **Functions:** `print_2()`, `print_3()`, `print_4()`
|
||||
- **File:** `numbers.py`
|
||||
- **Branch:** `pair-10-234`
|
||||
|
||||
### Pair 11
|
||||
- **Functions:** `print_5()`, `print_6()`, `print_7()`
|
||||
- **File:** `numbers.py`
|
||||
- **Branch:** `pair-11-567`
|
||||
|
||||
### Pair 12
|
||||
- **Functions:** `print_8()`, `print_9()`
|
||||
- **File:** `numbers.py`
|
||||
- **Branch:** `pair-12-89`
|
||||
|
||||
---
|
||||
|
||||
## Example Implementation
|
||||
|
||||
```python
|
||||
def print_a():
|
||||
"""Print letter A - EXAMPLE (already completed)"""
|
||||
print("A", end=" ")
|
||||
```
|
||||
|
||||
**Your functions should follow the same pattern:**
|
||||
|
||||
```python
|
||||
def print_x():
|
||||
"""Print letter/number X"""
|
||||
print("X", end=" ")
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Testing
|
||||
|
||||
After implementing your functions, test with:
|
||||
|
||||
```bash
|
||||
python main.py
|
||||
```
|
||||
|
||||
You should see your letters/numbers in the output!
|
||||
|
||||
---
|
||||
|
||||
## Questions?
|
||||
|
||||
Ask your facilitator for:
|
||||
- Your pair number
|
||||
- Your Gitea credentials
|
||||
- Help with authentication setup
|
||||
- Any Git or Python issues
|
||||
```
|
||||
|
||||
#### File 5: README.md (in repository)
|
||||
|
||||
```markdown
|
||||
# The Great Print Project 🎯
|
||||
|
||||
A collaborative Git exercise for learning teamwork with version control!
|
||||
|
||||
## Goal
|
||||
|
||||
When everyone completes their assigned functions, running `python main.py` will print:
|
||||
|
||||
```
|
||||
==================================================
|
||||
THE GREAT PRINT PROJECT
|
||||
==================================================
|
||||
|
||||
Letters:
|
||||
A B C D E F G H I J K L M N O P Q R S T U V W X Y Z
|
||||
|
||||
Numbers:
|
||||
0 1 2 3 4 5 6 7 8 9
|
||||
|
||||
==================================================
|
||||
PROJECT COMPLETE!
|
||||
==================================================
|
||||
```
|
||||
|
||||
## Your Mission
|
||||
|
||||
1. Find your pair assignment in `assignments.md`
|
||||
2. Clone this repository
|
||||
3. Create your feature branch
|
||||
4. Implement your assigned functions
|
||||
5. Practice collaboration: push, pull, resolve conflicts
|
||||
6. Create a pull request
|
||||
7. Celebrate when your code is merged!
|
||||
|
||||
## Quick Start
|
||||
|
||||
```bash
|
||||
# Clone the repository
|
||||
git clone https://git.frod.dk/multiplayer/great-print-project.git
|
||||
cd great-print-project
|
||||
|
||||
# Check your assignment
|
||||
cat assignments.md
|
||||
|
||||
# Create your branch (replace X with your pair number)
|
||||
git switch -c pair-X-feature
|
||||
|
||||
# Edit your file (letters.py or numbers.py)
|
||||
# Implement your functions
|
||||
|
||||
# Test it
|
||||
python main.py
|
||||
|
||||
# Commit and push
|
||||
git add .
|
||||
git commit -m "Implement print_x() functions"
|
||||
git push -u origin pair-X-feature
|
||||
```
|
||||
|
||||
## Files
|
||||
|
||||
- **main.py** - Orchestrator (runs the whole program)
|
||||
- **letters.py** - Functions for printing A-Z
|
||||
- **numbers.py** - Functions for printing 0-9
|
||||
- **assignments.md** - See which functions your pair should implement
|
||||
|
||||
## Need Help?
|
||||
|
||||
See the module README in the workshop repository for detailed step-by-step instructions!
|
||||
|
||||
**Happy Collaborating! 🚀**
|
||||
```
|
||||
|
||||
**Commit these files:**
|
||||
|
||||
```bash
|
||||
git add main.py letters.py numbers.py assignments.md README.md
|
||||
git commit -m "Add Great Print Project starter code"
|
||||
git push origin main
|
||||
```
|
||||
|
||||
### Step 4: Grant Student Access
|
||||
|
||||
Add students as collaborators with write access:
|
||||
|
||||
**Via Gitea web UI:**
|
||||
1. Go to repository → Settings → Collaborators
|
||||
2. Add each student account
|
||||
3. Set permission level: **Write** (allows push, pull, branch creation)
|
||||
|
||||
**Important:** Students need **Write** access to:
|
||||
- Create branches
|
||||
- Push commits
|
||||
- Create pull requests
|
||||
|
||||
### Step 5: Configure Branch Protection (Optional)
|
||||
|
||||
To prevent accidental pushes to main:
|
||||
|
||||
1. Repository → Settings → Branches
|
||||
2. Add protection rule for `main` branch
|
||||
3. Settings:
|
||||
- **Block direct pushes:** Yes (requires pull requests)
|
||||
- **Require PR reviews:** Optional (you can review PRs yourself)
|
||||
- **Auto-merge:** Disabled (you merge manually or students do)
|
||||
|
||||
This ensures students:
|
||||
- MUST use feature branches
|
||||
- MUST create pull requests
|
||||
- Can't accidentally break main
|
||||
|
||||
**For beginners:** Consider allowing students to merge their own PRs after approval to complete the full workflow.
|
||||
|
||||
### Step 6: Test the Setup
|
||||
|
||||
Before the workshop, test as a student would:
|
||||
|
||||
```bash
|
||||
# Clone as a test student
|
||||
git clone https://git.frod.dk/multiplayer/great-print-project.git
|
||||
cd great-print-project
|
||||
|
||||
# Run the program
|
||||
python main.py
|
||||
# Should show only "A" with missing letters/numbers
|
||||
|
||||
# Create test branch
|
||||
git switch -c test-branch
|
||||
|
||||
# Edit letters.py, add print_b()
|
||||
def print_b():
|
||||
print("B", end=" ")
|
||||
|
||||
# Commit and push
|
||||
git add letters.py
|
||||
git commit -m "Test commit"
|
||||
git push -u origin test-branch
|
||||
|
||||
# Create test pull request
|
||||
# (Do this via web UI)
|
||||
|
||||
# Clean up test branch after
|
||||
git push origin --delete test-branch
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## During the Workshop
|
||||
|
||||
### Pairing Students
|
||||
|
||||
**Strategies for assigning pairs:**
|
||||
|
||||
**Option 1: Random pairing**
|
||||
- Use a random number generator
|
||||
- Pair students as they arrive
|
||||
|
||||
**Option 2: Skill-based pairing**
|
||||
- Mix experienced and beginner students
|
||||
- Balance pair capabilities
|
||||
|
||||
**Option 3: Let them choose**
|
||||
- Students pick their own partners
|
||||
- Good for building team dynamics
|
||||
|
||||
**Announce pairs clearly:**
|
||||
- Write on board/screen: "Pair 1: Alice & Bob"
|
||||
- Provide printed assignment sheet
|
||||
- Update `assignments.md` in repo if needed
|
||||
|
||||
### Timeline
|
||||
|
||||
**Suggested schedule for 2-hour session:**
|
||||
|
||||
- **0:00-0:10** (10 min): Introduction, distribute credentials
|
||||
- **0:10-0:20** (10 min): Students clone repo, verify access
|
||||
- **0:20-0:35** (15 min): Part 1 - Getting Started
|
||||
- **0:35-0:55** (20 min): Part 2 - First Contribution
|
||||
- **0:55-1:25** (30 min): Part 3 - Conflict Exercise (key learning!)
|
||||
- **1:25-1:45** (20 min): Part 4 - Pull Requests
|
||||
- **1:45-2:00** (15 min): Part 5 - Syncing, Q&A, wrap-up
|
||||
|
||||
### Monitoring Progress
|
||||
|
||||
**Use Gitea to track:**
|
||||
|
||||
1. **Branches created:** Repository → Branches
|
||||
- Should see `pair-1-bcd`, `pair-2-efg`, etc.
|
||||
|
||||
2. **Commits:** Repository → Commits
|
||||
- Each pair should have multiple commits
|
||||
|
||||
3. **Pull requests:** Repository → Pull Requests
|
||||
- Should see one PR per pair
|
||||
|
||||
**Walk around the room:**
|
||||
- Check screens for conflict markers
|
||||
- Ask pairs how they're resolving conflicts
|
||||
- Ensure both partners are engaged
|
||||
|
||||
**Common issues to watch for:**
|
||||
- Partners not using the same branch name
|
||||
- Forgetting to pull before pushing
|
||||
- Not removing conflict markers completely
|
||||
- Committing to main instead of feature branch
|
||||
|
||||
### Managing Pull Requests
|
||||
|
||||
**Your role:**
|
||||
|
||||
**Option A: Review and merge yourself**
|
||||
- Teaches students what good reviews look like
|
||||
- Ensures quality before merging
|
||||
- More facilitator work
|
||||
|
||||
**Option B: Students merge their own**
|
||||
- More autonomous learning
|
||||
- Students experience complete workflow
|
||||
- Risk of messy main branch
|
||||
|
||||
**Recommended approach:**
|
||||
1. First 2-3 PRs: You review and merge (demonstrate good practices)
|
||||
2. Remaining PRs: Students review each other, you approve
|
||||
3. Students can merge after approval
|
||||
|
||||
**What to check in PR reviews:**
|
||||
- Functions implemented correctly
|
||||
- No conflict markers in code
|
||||
- Code follows pattern (e.g., `print("X", end=" ")`)
|
||||
- Meaningful commit messages
|
||||
|
||||
### Handling Problems
|
||||
|
||||
**Common issues and solutions:**
|
||||
|
||||
**Problem: "I can't push!"**
|
||||
- Check they're authenticated (token or SSH key)
|
||||
- Check they pulled latest changes first
|
||||
- Check branch name matches their partner's
|
||||
|
||||
**Problem: "Merge conflict won't resolve!"**
|
||||
- Walk through Part 3 step-by-step with them
|
||||
- Show them the conflict markers
|
||||
- Verify they removed ALL markers
|
||||
- Run `python main.py` together to test
|
||||
|
||||
**Problem: "We both committed to main!"**
|
||||
- Have them create proper feature branch
|
||||
- Use `git cherry-pick` to move commits
|
||||
- Reset main to origin/main
|
||||
|
||||
**Problem: "GitHub Desktop / GUI tool shows something different"**
|
||||
- Recommend command line for this exercise
|
||||
- GUIs can hide important details during conflicts
|
||||
|
||||
### Celebrating Success
|
||||
|
||||
When all pairs have merged:
|
||||
|
||||
```bash
|
||||
git pull origin main
|
||||
python main.py
|
||||
```
|
||||
|
||||
**Everyone should see:**
|
||||
```
|
||||
==================================================
|
||||
THE GREAT PRINT PROJECT
|
||||
==================================================
|
||||
|
||||
Letters:
|
||||
A B C D E F G H I J K L M N O P Q R S T U V W X Y Z
|
||||
|
||||
Numbers:
|
||||
0 1 2 3 4 5 6 7 8 9
|
||||
|
||||
==================================================
|
||||
PROJECT COMPLETE!
|
||||
==================================================
|
||||
```
|
||||
|
||||
**Take a screenshot!** Share it with the class. This is a genuine collaborative achievement.
|
||||
|
||||
---
|
||||
|
||||
## Post-Workshop
|
||||
|
||||
### Cleanup (Optional)
|
||||
|
||||
**Keep the repository for future workshops:**
|
||||
- Delete all feature branches: `git push origin --delete pair-1-bcd` (etc.)
|
||||
- Reset main to initial state
|
||||
- Reuse for next cohort
|
||||
|
||||
**Archive the session:**
|
||||
- Export final repository state
|
||||
- Take screenshots of successful PRs
|
||||
- Save for portfolio/examples
|
||||
|
||||
### Student Takeaways
|
||||
|
||||
Provide students:
|
||||
- Link to repository (they can clone for reference)
|
||||
- Completion certificate (if applicable)
|
||||
- Next steps: contributing to open source, Git resources
|
||||
|
||||
---
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### Gitea Server Issues
|
||||
|
||||
**Problem: Server unreachable**
|
||||
- Check Cloudflare Tunnel is running: `cloudflared tunnel info`
|
||||
- Verify Gitea container is up: `docker ps`
|
||||
- Check firewall rules
|
||||
|
||||
**Problem: SSH not working**
|
||||
- Verify SSH port is exposed in docker-compose.yml
|
||||
- Check Cloudflare Tunnel config includes SSH
|
||||
- Test: `ssh -T git@git.frod.dk`
|
||||
|
||||
**Problem: HTTPS clone fails**
|
||||
- Check certificate validity
|
||||
- Try `GIT_SSL_NO_VERIFY=true git clone ...` (temporary workaround)
|
||||
- Configure Gitea to use proper HTTPS certificates
|
||||
|
||||
### Authentication Issues
|
||||
|
||||
**Problem: Students can't log in**
|
||||
- Verify accounts created and active
|
||||
- Reset passwords if needed
|
||||
- Check email verification isn't blocking (disable for workshop)
|
||||
|
||||
**Problem: Push fails with authentication error**
|
||||
- HTTPS: Ensure students use access token, not password
|
||||
- SSH: Verify keys added to Gitea account
|
||||
- Check repo permissions (must be Write, not Read)
|
||||
|
||||
### Git Workflow Issues
|
||||
|
||||
**Problem: Students create PR but can't merge**
|
||||
- Check branch protection rules
|
||||
- Verify they have Write access
|
||||
- Ensure PR doesn't have conflicts
|
||||
|
||||
**Problem: Main branch gets messy**
|
||||
- Reset to last good commit: `git reset --hard <commit>`
|
||||
- Force push: `git push --force origin main` (CAREFUL!)
|
||||
- Or start fresh: delete repo, recreate with starter code
|
||||
|
||||
---
|
||||
|
||||
## Tips for Success
|
||||
|
||||
### Before Workshop
|
||||
|
||||
- Test the entire flow yourself as a student
|
||||
- Prepare credential sheets for each student
|
||||
- Have backup plan if server goes down (local git exercise)
|
||||
- Prepare slides explaining merge conflicts visually
|
||||
|
||||
### During Workshop
|
||||
|
||||
- **Start on time** - respect everyone's schedule
|
||||
- **Pair programming** - ensure both partners engage
|
||||
- **Encourage talking** - best conflicts are resolved by discussion
|
||||
- **Celebrate small wins** - first push, first conflict resolution
|
||||
- **Walk the room** - see screens, answer questions live
|
||||
|
||||
### After Workshop
|
||||
|
||||
- Gather feedback - what worked, what didn't
|
||||
- Note timing - were parts too rushed or too slow?
|
||||
- Archive successful PRs as examples
|
||||
- Plan improvements for next session
|
||||
|
||||
---
|
||||
|
||||
## Scaling Considerations
|
||||
|
||||
### Small Groups (4-8 students, 2-4 pairs)
|
||||
|
||||
- More hands-on facilitator time
|
||||
- Can review all PRs in detail
|
||||
- Easier to monitor progress
|
||||
|
||||
### Medium Groups (10-20 students, 5-10 pairs)
|
||||
|
||||
- Recommended size
|
||||
- Good mix of collaboration and individual attention
|
||||
- Helps if you have a teaching assistant
|
||||
|
||||
### Large Groups (20+ students, 10+ pairs)
|
||||
|
||||
- Consider multiple repositories (split into groups of 12 pairs max)
|
||||
- Recruit teaching assistants to help monitor
|
||||
- Use breakout rooms (if online)
|
||||
- Automate more (less PR review, more self-merging)
|
||||
|
||||
---
|
||||
|
||||
## Additional Resources
|
||||
|
||||
### For You (Facilitator)
|
||||
|
||||
- Gitea documentation: https://docs.gitea.io/
|
||||
- Pro Git book (free): https://git-scm.com/book/en/v2
|
||||
- Teaching Git: https://git-scm.com/doc
|
||||
|
||||
### For Students
|
||||
|
||||
- Git cheatsheet (included in workshop repo)
|
||||
- Interactive Git tutorial: https://learngitbranching.js.org/
|
||||
- Oh Shit Git: https://ohshitgit.com/ (recovering from mistakes)
|
||||
|
||||
---
|
||||
|
||||
## Questions or Issues?
|
||||
|
||||
This guide should cover most scenarios. If you encounter issues not listed here:
|
||||
|
||||
1. Check Gitea logs: `docker logs gitea-container-name`
|
||||
2. Test with minimal setup (single test student)
|
||||
3. Consult Gitea documentation
|
||||
4. Reach out to workshop repository maintainers
|
||||
|
||||
**Good luck with your workshop! The multiplayer module is where Git skills really come alive.**
|
||||
1408
01_essentials/09-multiplayer/README.md
Normal file
1408
01_essentials/09-multiplayer/README.md
Normal file
File diff suppressed because it is too large
Load Diff
@@ -1,252 +0,0 @@
|
||||
# Module 12: Working with Remotes
|
||||
|
||||
## Learning Objectives
|
||||
|
||||
By the end of this module, you will:
|
||||
- Understand what remote repositories are
|
||||
- Clone a repository from a remote source
|
||||
- Push local commits to a remote repository
|
||||
- Pull changes from a remote repository
|
||||
- Understand the difference between fetch and pull
|
||||
- Manage remote branches
|
||||
- Work with remote tracking branches
|
||||
|
||||
## Challenge Description
|
||||
|
||||
You're joining a team project that's already hosted on a remote server. You need to clone the repository, make changes, and synchronize your work with the remote.
|
||||
|
||||
Your task is to:
|
||||
1. Clone the remote repository
|
||||
2. Create a new branch for your feature
|
||||
3. Make changes and commit them locally
|
||||
4. Push your branch to the remote
|
||||
5. Fetch updates that were made by teammates
|
||||
6. Merge remote changes into your branch
|
||||
|
||||
## Key Concepts
|
||||
|
||||
### What is a Remote Repository?
|
||||
|
||||
A remote repository is a version of your project hosted on a server (like GitHub, GitLab, or Bitbucket) or another location. It allows teams to collaborate by sharing code.
|
||||
|
||||
### Common Remote Operations
|
||||
|
||||
**Clone**: Create a local copy of a remote repository
|
||||
```
|
||||
Remote Server Your Computer
|
||||
[repo] -----------------> [local copy of repo]
|
||||
```
|
||||
|
||||
**Push**: Send your local commits to the remote
|
||||
```
|
||||
Your Computer Remote Server
|
||||
[commits] -----------------> [repo updated]
|
||||
```
|
||||
|
||||
**Pull**: Get changes from remote and merge into your branch
|
||||
```
|
||||
Remote Server Your Computer
|
||||
[commits] ---------------> [branch updated]
|
||||
```
|
||||
|
||||
**Fetch**: Get changes from remote but don't merge yet
|
||||
```
|
||||
Remote Server Your Computer
|
||||
[commits] ---------------> [stored locally, not merged]
|
||||
```
|
||||
|
||||
### Origin vs Upstream
|
||||
|
||||
- **origin**: The default name for the remote you cloned from
|
||||
- **upstream**: Often used for the original repository when you've forked it
|
||||
- You can have multiple remotes with different names
|
||||
|
||||
### Remote Tracking Branches
|
||||
|
||||
When you clone a repository, Git creates remote tracking branches:
|
||||
- `origin/main` - tracks the main branch on origin
|
||||
- `origin/feature` - tracks the feature branch on origin
|
||||
|
||||
These are read-only local copies that show the state of remote branches.
|
||||
|
||||
## Useful Commands
|
||||
|
||||
```bash
|
||||
# Clone a repository
|
||||
git clone <url>
|
||||
git clone <url> <directory-name>
|
||||
|
||||
# View remotes
|
||||
git remote
|
||||
git remote -v # Show URLs
|
||||
|
||||
# Add a remote
|
||||
git remote add <name> <url>
|
||||
|
||||
# Remove a remote
|
||||
git remote remove <name>
|
||||
|
||||
# Rename a remote
|
||||
git remote rename <old-name> <new-name>
|
||||
|
||||
# Push to remote
|
||||
git push origin <branch-name>
|
||||
git push -u origin <branch-name> # Set upstream tracking
|
||||
|
||||
# Pull from remote (fetch + merge)
|
||||
git pull
|
||||
git pull origin <branch-name>
|
||||
|
||||
# Fetch from remote (no merge)
|
||||
git fetch
|
||||
git fetch origin
|
||||
|
||||
# See remote branches
|
||||
git branch -r
|
||||
git branch -a # All branches (local and remote)
|
||||
|
||||
# Delete remote branch
|
||||
git push origin --delete <branch-name>
|
||||
|
||||
# Update remote tracking information
|
||||
git remote update
|
||||
git remote prune origin # Remove stale remote tracking branches
|
||||
```
|
||||
|
||||
## Verification
|
||||
|
||||
Run the verification script to check your solution:
|
||||
|
||||
```bash
|
||||
.\verify.ps1
|
||||
```
|
||||
|
||||
The verification will check that:
|
||||
- You cloned the repository correctly
|
||||
- Your feature branch exists and has commits
|
||||
- Changes were pushed to the remote
|
||||
- You fetched and merged remote updates
|
||||
- Your branch is up to date
|
||||
|
||||
## Challenge Steps
|
||||
|
||||
1. Navigate to the challenge directory
|
||||
2. You'll find a simulated "remote" repository
|
||||
3. Clone it: `git clone remote-repo local-repo`
|
||||
4. Navigate into your clone: `cd local-repo`
|
||||
5. Create and switch to a feature branch: `git switch -c add-feature`
|
||||
6. Make changes to the project (add a new feature to app.js)
|
||||
7. Commit your changes
|
||||
8. Push to remote: `git push -u origin add-feature`
|
||||
9. Simulate teammate changes (run the provided update script)
|
||||
10. Fetch updates: `git fetch origin`
|
||||
11. View remote changes: `git log origin/main`
|
||||
12. Merge remote main into your branch: `git merge origin/main`
|
||||
13. Run verification
|
||||
|
||||
## Tips
|
||||
|
||||
- `git clone` automatically sets up the remote as "origin"
|
||||
- `git push -u` sets up tracking so future pushes can just use `git push`
|
||||
- Use `git fetch` to see what's changed before merging
|
||||
- `git pull` = `git fetch` + `git merge`
|
||||
- Always pull before pushing to avoid conflicts
|
||||
- Use `git branch -a` to see all local and remote branches
|
||||
- Remote branches are read-only; you work on local branches
|
||||
- `origin/main` is a remote tracking branch, `main` is your local branch
|
||||
|
||||
## Push vs Pull vs Fetch
|
||||
|
||||
### Git Push
|
||||
Uploads your local commits to the remote:
|
||||
```bash
|
||||
git push origin main
|
||||
```
|
||||
Use when: You have local commits ready to share with the team
|
||||
|
||||
### Git Pull
|
||||
Downloads and merges remote changes:
|
||||
```bash
|
||||
git pull origin main
|
||||
```
|
||||
Use when: You want to update your branch with remote changes
|
||||
Equivalent to: `git fetch origin` + `git merge origin/main`
|
||||
|
||||
### Git Fetch
|
||||
Downloads remote changes without merging:
|
||||
```bash
|
||||
git fetch origin
|
||||
```
|
||||
Use when: You want to see what's changed before merging
|
||||
Safer than pull because it doesn't automatically merge
|
||||
|
||||
## Common Remote Workflows
|
||||
|
||||
### Daily Work Flow
|
||||
```bash
|
||||
# Start of day: get latest changes
|
||||
git switch main
|
||||
git pull origin main
|
||||
|
||||
# Create feature branch
|
||||
git switch -c my-feature
|
||||
|
||||
# Do work, make commits
|
||||
git add .
|
||||
git commit -m "Add feature"
|
||||
|
||||
# Before pushing, update with latest main
|
||||
git switch main
|
||||
git pull origin main
|
||||
git switch my-feature
|
||||
git merge main
|
||||
|
||||
# Push your feature
|
||||
git push -u origin my-feature
|
||||
```
|
||||
|
||||
### Collaboration Workflow
|
||||
```bash
|
||||
# Teammate pushed changes to main
|
||||
git fetch origin
|
||||
git log origin/main # Review changes
|
||||
git merge origin/main # Merge into current branch
|
||||
|
||||
# Or use pull (fetch + merge in one step)
|
||||
git pull origin main
|
||||
```
|
||||
|
||||
### Syncing Fork (with upstream)
|
||||
```bash
|
||||
# Add original repo as upstream
|
||||
git remote add upstream <original-repo-url>
|
||||
|
||||
# Get latest from upstream
|
||||
git fetch upstream
|
||||
git switch main
|
||||
git merge upstream/main
|
||||
|
||||
# Push to your fork
|
||||
git push origin main
|
||||
```
|
||||
|
||||
## Handling Push Rejection
|
||||
|
||||
If push is rejected because remote has changes:
|
||||
```bash
|
||||
# Remote has commits you don't have
|
||||
git push origin main
|
||||
# Error: Updates were rejected
|
||||
|
||||
# Solution 1: Pull first (creates merge commit)
|
||||
git pull origin main
|
||||
git push origin main
|
||||
|
||||
# Solution 2: Pull with rebase (cleaner history)
|
||||
git pull --rebase origin main
|
||||
git push origin main
|
||||
```
|
||||
|
||||
## What You'll Learn
|
||||
|
||||
Working with remotes is fundamental to team collaboration. Understanding the difference between local and remote branches, knowing when to push/pull/fetch, and managing synchronization are core skills for any developer. While this module uses a local "remote" for learning, the concepts apply directly to GitHub, GitLab, and other hosting services. Mastering remotes enables you to work effectively in distributed teams and contribute to open source projects.
|
||||
@@ -1,22 +0,0 @@
|
||||
#!/usr/bin/env pwsh
|
||||
|
||||
<#
|
||||
.SYNOPSIS
|
||||
Resets the remotes challenge environment.
|
||||
|
||||
.DESCRIPTION
|
||||
Removes the existing challenge directory and runs setup.ps1
|
||||
to create a fresh challenge environment.
|
||||
#>
|
||||
|
||||
Write-Host "Resetting challenge environment..." -ForegroundColor Yellow
|
||||
|
||||
# Remove existing challenge directory if present
|
||||
if (Test-Path "challenge") {
|
||||
Remove-Item -Path "challenge" -Recurse -Force
|
||||
Write-Host "Removed existing challenge directory." -ForegroundColor Cyan
|
||||
}
|
||||
|
||||
# Run setup script
|
||||
Write-Host "Running setup script...`n" -ForegroundColor Cyan
|
||||
& ".\setup.ps1"
|
||||
@@ -1,147 +0,0 @@
|
||||
#!/usr/bin/env pwsh
|
||||
|
||||
<#
|
||||
.SYNOPSIS
|
||||
Sets up the remotes challenge environment.
|
||||
|
||||
.DESCRIPTION
|
||||
Creates a simulated remote repository and working environment
|
||||
for learning Git remote operations.
|
||||
#>
|
||||
|
||||
# Remove existing challenge directory if present
|
||||
if (Test-Path "challenge") {
|
||||
Write-Host "Removing existing challenge directory..." -ForegroundColor Yellow
|
||||
Remove-Item -Path "challenge" -Recurse -Force
|
||||
}
|
||||
|
||||
# Create challenge directory structure
|
||||
Write-Host "Creating challenge environment..." -ForegroundColor Cyan
|
||||
New-Item -ItemType Directory -Path "challenge" | Out-Null
|
||||
Set-Location "challenge"
|
||||
|
||||
# Create a temporary workspace to build the initial repository
|
||||
New-Item -ItemType Directory -Path "temp-workspace" | Out-Null
|
||||
Set-Location "temp-workspace"
|
||||
|
||||
# Initialize and create initial commits
|
||||
git init | Out-Null
|
||||
git config user.name "Workshop User" | Out-Null
|
||||
git config user.email "user@workshop.local" | Out-Null
|
||||
|
||||
# Create initial project files
|
||||
$app = @"
|
||||
class Application:
|
||||
def __init__(self):
|
||||
self.name = 'TeamProject'
|
||||
self.version = '1.0.0'
|
||||
|
||||
def start(self):
|
||||
print('Application started')
|
||||
"@
|
||||
|
||||
Set-Content -Path "app.py" -Value $app
|
||||
git add app.py
|
||||
git commit -m "Initial application" | Out-Null
|
||||
|
||||
$readme = @"
|
||||
# Team Project
|
||||
|
||||
A collaborative project for learning Git remotes.
|
||||
|
||||
## Features
|
||||
- Basic application structure
|
||||
"@
|
||||
|
||||
Set-Content -Path "README.md" -Value $readme
|
||||
git add README.md
|
||||
git commit -m "Add README" | Out-Null
|
||||
|
||||
$package = @"
|
||||
from setuptools import setup
|
||||
|
||||
setup(
|
||||
name='team-project',
|
||||
version='1.0.0',
|
||||
description='Learning Git remotes',
|
||||
py_modules=['app'],
|
||||
)
|
||||
"@
|
||||
|
||||
Set-Content -Path "setup.py" -Value $package
|
||||
git add setup.py
|
||||
git commit -m "Add setup.py" | Out-Null
|
||||
|
||||
# Create the "remote" repository (bare repository)
|
||||
Set-Location ..
|
||||
git clone --bare temp-workspace remote-repo 2>$null | Out-Null
|
||||
|
||||
# Clean up temp workspace
|
||||
Remove-Item -Path "temp-workspace" -Recurse -Force
|
||||
|
||||
# Create a helper script to simulate teammate changes
|
||||
$simulateTeammateScript = @"
|
||||
#!/usr/bin/env pwsh
|
||||
|
||||
# This script simulates a teammate making changes to the remote repository
|
||||
|
||||
Write-Host "Simulating teammate changes..." -ForegroundColor Cyan
|
||||
|
||||
# Create a temporary clone
|
||||
if (Test-Path "temp-teammate") {
|
||||
Remove-Item -Path "temp-teammate" -Recurse -Force
|
||||
}
|
||||
|
||||
git clone remote-repo temp-teammate 2>>`$null | Out-Null
|
||||
Set-Location temp-teammate
|
||||
|
||||
git config user.name "Teammate" 2>>`$null | Out-Null
|
||||
git config user.email "teammate@workshop.local" 2>>`$null | Out-Null
|
||||
|
||||
# Make changes to main branch
|
||||
`$appContent = Get-Content "app.py" -Raw
|
||||
`$updatedApp = `$appContent -replace "def start\(self\):", @"
|
||||
def start(self):
|
||||
print('Starting application...')
|
||||
self.initialize()
|
||||
|
||||
def initialize(self):
|
||||
"@
|
||||
|
||||
Set-Content -Path "app.py" -Value `$updatedApp
|
||||
git add app.py 2>>`$null
|
||||
git commit -m "Add initialization method" 2>>`$null | Out-Null
|
||||
git push origin main 2>>`$null | Out-Null
|
||||
|
||||
Set-Location ..
|
||||
Remove-Item -Path "temp-teammate" -Recurse -Force
|
||||
|
||||
Write-Host "Teammate pushed changes to remote repository!" -ForegroundColor Green
|
||||
Write-Host "Use 'git fetch origin' to see the changes" -ForegroundColor Cyan
|
||||
"@
|
||||
|
||||
Set-Content -Path "simulate-teammate.ps1" -Value $simulateTeammateScript
|
||||
|
||||
# Return to module directory
|
||||
Set-Location ..
|
||||
|
||||
Write-Host "`n========================================" -ForegroundColor Green
|
||||
Write-Host "Challenge environment created!" -ForegroundColor Green
|
||||
Write-Host "========================================" -ForegroundColor Green
|
||||
Write-Host "`nSetup complete! You have:" -ForegroundColor Cyan
|
||||
Write-Host "- remote-repo/ - A 'remote' repository (simulates GitHub/GitLab)" -ForegroundColor White
|
||||
Write-Host "- simulate-teammate.ps1 - Script to simulate teammate changes" -ForegroundColor White
|
||||
Write-Host "`nYour task:" -ForegroundColor Yellow
|
||||
Write-Host "1. Navigate to the challenge directory: cd challenge" -ForegroundColor White
|
||||
Write-Host "2. Clone the remote: git clone remote-repo local-repo" -ForegroundColor White
|
||||
Write-Host "3. Navigate to your clone: cd local-repo" -ForegroundColor White
|
||||
Write-Host "4. Create a feature branch: git checkout -b add-feature" -ForegroundColor White
|
||||
Write-Host "5. Add a new method to app.py (e.g., stop method)" -ForegroundColor White
|
||||
Write-Host "6. Commit your changes" -ForegroundColor White
|
||||
Write-Host "7. Push your branch: git push -u origin add-feature" -ForegroundColor White
|
||||
Write-Host "8. Go back to challenge directory: cd .." -ForegroundColor White
|
||||
Write-Host "9. Simulate teammate changes: pwsh simulate-teammate.ps1" -ForegroundColor White
|
||||
Write-Host "10. Go back to local-repo: cd local-repo" -ForegroundColor White
|
||||
Write-Host "11. Fetch updates: git fetch origin" -ForegroundColor White
|
||||
Write-Host "12. Merge remote main: git merge origin/main" -ForegroundColor White
|
||||
Write-Host "`nRun '../verify.ps1' from the challenge directory to check your solution.`n" -ForegroundColor Cyan
|
||||
@@ -1,174 +0,0 @@
|
||||
#!/usr/bin/env pwsh
|
||||
|
||||
<#
|
||||
.SYNOPSIS
|
||||
Verifies the remotes challenge solution.
|
||||
|
||||
.DESCRIPTION
|
||||
Checks that the user successfully cloned the repository, worked with
|
||||
remotes, pushed branches, and synchronized changes.
|
||||
#>
|
||||
|
||||
Set-Location "challenge" -ErrorAction SilentlyContinue
|
||||
|
||||
# Check if challenge directory exists
|
||||
if (-not (Test-Path "../verify.ps1")) {
|
||||
Write-Host "Error: Please run this script from the module directory" -ForegroundColor Red
|
||||
exit 1
|
||||
}
|
||||
|
||||
if (-not (Test-Path ".")) {
|
||||
Write-Host "Error: Challenge directory not found. Run setup.ps1 first." -ForegroundColor Red
|
||||
Set-Location ..
|
||||
exit 1
|
||||
}
|
||||
|
||||
Write-Host "Verifying your solution..." -ForegroundColor Cyan
|
||||
|
||||
# Check if local-repo exists
|
||||
if (-not (Test-Path "local-repo")) {
|
||||
Write-Host "[FAIL] local-repo directory not found." -ForegroundColor Red
|
||||
Write-Host "Hint: Clone the remote repository with: git clone remote-repo local-repo" -ForegroundColor Yellow
|
||||
Set-Location ..
|
||||
exit 1
|
||||
}
|
||||
|
||||
Set-Location "local-repo"
|
||||
|
||||
# Check if it's a git repository
|
||||
if (-not (Test-Path ".git")) {
|
||||
Write-Host "[FAIL] local-repo is not a git repository." -ForegroundColor Red
|
||||
Set-Location ../..
|
||||
exit 1
|
||||
}
|
||||
|
||||
# Check if remote 'origin' is configured
|
||||
$remotes = git remote 2>$null
|
||||
if ($remotes -notcontains "origin") {
|
||||
Write-Host "[FAIL] No remote named 'origin' found." -ForegroundColor Red
|
||||
Write-Host "Hint: Cloning should automatically set up 'origin' as the remote" -ForegroundColor Yellow
|
||||
Set-Location ../..
|
||||
exit 1
|
||||
}
|
||||
|
||||
# Check if origin points to the remote-repo
|
||||
$originUrl = git remote get-url origin 2>$null
|
||||
if ($originUrl -notmatch "remote-repo") {
|
||||
Write-Host "[FAIL] Origin remote does not point to remote-repo." -ForegroundColor Red
|
||||
Write-Host "Origin URL: $originUrl" -ForegroundColor Yellow
|
||||
Set-Location ../..
|
||||
exit 1
|
||||
}
|
||||
|
||||
Write-Host "[PASS] Repository cloned correctly with origin remote!" -ForegroundColor Green
|
||||
|
||||
# Check if add-feature branch exists locally
|
||||
$branches = git branch 2>$null
|
||||
if ($branches -notmatch "add-feature") {
|
||||
Write-Host "[FAIL] add-feature branch not found locally." -ForegroundColor Red
|
||||
Write-Host "Hint: Create the branch with: git checkout -b add-feature" -ForegroundColor Yellow
|
||||
Set-Location ../..
|
||||
exit 1
|
||||
}
|
||||
|
||||
# Switch to add-feature branch
|
||||
git checkout add-feature 2>$null | Out-Null
|
||||
|
||||
# Check if there are commits on add-feature beyond the initial commits
|
||||
$featureCommitCount = (git rev-list --count add-feature 2>$null)
|
||||
$mainCommitCount = (git rev-list --count main 2>$null)
|
||||
|
||||
if ($featureCommitCount -le $mainCommitCount) {
|
||||
Write-Host "[FAIL] add-feature branch has no new commits." -ForegroundColor Red
|
||||
Write-Host "Hint: Make changes to app.py and commit them on the add-feature branch" -ForegroundColor Yellow
|
||||
Set-Location ../..
|
||||
exit 1
|
||||
}
|
||||
|
||||
Write-Host "[PASS] Feature branch created with commits!" -ForegroundColor Green
|
||||
|
||||
# Check if add-feature branch was pushed to remote
|
||||
Set-Location ..
|
||||
Set-Location remote-repo
|
||||
|
||||
$remoteBranches = git branch 2>$null
|
||||
if ($remoteBranches -notmatch "add-feature") {
|
||||
Write-Host "[FAIL] add-feature branch not found on remote." -ForegroundColor Red
|
||||
Write-Host "Hint: Push your branch with: git push -u origin add-feature" -ForegroundColor Yellow
|
||||
Set-Location ../..
|
||||
exit 1
|
||||
}
|
||||
|
||||
Write-Host "[PASS] Feature branch pushed to remote!" -ForegroundColor Green
|
||||
|
||||
Set-Location ../local-repo
|
||||
|
||||
# Check if app.py has been modified
|
||||
if (-not (Test-Path "app.py")) {
|
||||
Write-Host "[FAIL] app.py not found." -ForegroundColor Red
|
||||
Set-Location ../..
|
||||
exit 1
|
||||
}
|
||||
|
||||
$appContent = Get-Content "app.py" -Raw
|
||||
|
||||
# Check for user's changes (should have added something)
|
||||
$featureCommits = git log --pretty=format:"%s" add-feature 2>$null
|
||||
if (-not ($featureCommits -match "stop|feature|add" -or $appContent -match "stop")) {
|
||||
Write-Host "[FAIL] No new feature detected in app.py." -ForegroundColor Red
|
||||
Write-Host "Hint: Add a new method (like 'stop') to app.py and commit it" -ForegroundColor Yellow
|
||||
Set-Location ../..
|
||||
exit 1
|
||||
}
|
||||
|
||||
# Check if teammate changes were fetched and merged
|
||||
# The teammate's change adds an 'initialize' method
|
||||
if ($appContent -notmatch "initialize") {
|
||||
Write-Host "[FAIL] Teammate's changes not merged into your branch." -ForegroundColor Red
|
||||
Write-Host "Hint: Did you run the simulate-teammate.ps1 script?" -ForegroundColor Yellow
|
||||
Write-Host " Then: git fetch origin" -ForegroundColor Yellow
|
||||
Write-Host " git merge origin/main" -ForegroundColor Yellow
|
||||
Set-Location ../..
|
||||
exit 1
|
||||
}
|
||||
|
||||
Write-Host "[PASS] Remote changes fetched and merged!" -ForegroundColor Green
|
||||
|
||||
# Check that the branch has both sets of changes
|
||||
$allCommits = git log --all --pretty=format:"%s" 2>$null
|
||||
$hasUserCommit = $allCommits -match "stop|feature|add"
|
||||
$hasTeammateCommit = $allCommits -match "initialization|initialize"
|
||||
|
||||
if (-not $hasTeammateCommit) {
|
||||
Write-Host "[WARNING] Teammate commit not found in history." -ForegroundColor Yellow
|
||||
Write-Host "Make sure you ran simulate-teammate.ps1 and fetched the changes" -ForegroundColor Yellow
|
||||
}
|
||||
|
||||
# Check for remote tracking
|
||||
$tracking = git branch -vv 2>$null
|
||||
if ($tracking -notmatch "origin/add-feature") {
|
||||
Write-Host "[WARNING] add-feature branch may not be tracking origin/add-feature" -ForegroundColor Yellow
|
||||
Write-Host "Hint: Use 'git push -u origin add-feature' to set up tracking" -ForegroundColor Yellow
|
||||
}
|
||||
|
||||
# Success!
|
||||
Write-Host "`n========================================" -ForegroundColor Green
|
||||
Write-Host "SUCCESS! Challenge completed!" -ForegroundColor Green
|
||||
Write-Host "========================================" -ForegroundColor Green
|
||||
Write-Host "`nYou have successfully:" -ForegroundColor Cyan
|
||||
Write-Host "- Cloned the remote repository" -ForegroundColor White
|
||||
Write-Host "- Created a feature branch" -ForegroundColor White
|
||||
Write-Host "- Made commits to your branch" -ForegroundColor White
|
||||
Write-Host "- Pushed your branch to the remote" -ForegroundColor White
|
||||
Write-Host "- Fetched changes from the remote" -ForegroundColor White
|
||||
Write-Host "- Merged remote changes into your branch" -ForegroundColor White
|
||||
Write-Host "`nYou now understand how to work with Git remotes!" -ForegroundColor Green
|
||||
Write-Host "`nKey takeaways:" -ForegroundColor Yellow
|
||||
Write-Host "- Clone creates a local copy linked to the remote" -ForegroundColor White
|
||||
Write-Host "- Push uploads your commits to the remote" -ForegroundColor White
|
||||
Write-Host "- Fetch downloads remote changes without merging" -ForegroundColor White
|
||||
Write-Host "- Pull = Fetch + Merge" -ForegroundColor White
|
||||
Write-Host "`nThese skills are essential for team collaboration!`n" -ForegroundColor Green
|
||||
|
||||
Set-Location ../..
|
||||
exit 0
|
||||
Reference in New Issue
Block a user