From 7f34cf2d080bdb40262d0652051bf279f0d3e1f5 Mon Sep 17 00:00:00 2001 From: Bjarke Sporring Date: Wed, 7 Jan 2026 23:46:32 +0100 Subject: [PATCH] feat: add multiplayer guidelines --- .../09-multiplayer/FACILITATOR-SETUP.md | 904 +++++++++++ 01_essentials/09-multiplayer/README.md | 1408 +++++++++++++++++ .../01-rebasing/README.md | 0 .../01-rebasing/reset.ps1 | 0 .../01-rebasing/setup.ps1 | 0 .../01-rebasing/verify.ps1 | 0 .../02-interactive-rebase/README.md | 0 .../02-interactive-rebase/reset.ps1 | 0 .../02-interactive-rebase/setup.ps1 | 0 .../02-interactive-rebase/verify.ps1 | 0 .../03-worktrees/README.md | 0 .../03-worktrees/reset.ps1 | 0 .../03-worktrees/setup.ps1 | 0 .../03-worktrees/verify.ps1 | 0 .../04-bisect/README.md | 0 .../04-bisect/reset.ps1 | 0 .../04-bisect/setup.ps1 | 0 .../04-bisect/verify.ps1 | 0 .../05-blame/README.md | 0 .../05-blame/reset.ps1 | 0 .../05-blame/setup.ps1 | 0 .../05-blame/verify.ps1 | 0 .../06-merge-strategies/README.md | 0 .../06-merge-strategies/reset.ps1 | 0 .../06-merge-strategies/setup.ps1 | 0 .../06-merge-strategies/verify.ps1 | 0 02_multiplayer/01-remotes/README.md | 252 --- 02_multiplayer/01-remotes/reset.ps1 | 22 - 02_multiplayer/01-remotes/setup.ps1 | 147 -- 02_multiplayer/01-remotes/verify.ps1 | 174 -- 30 files changed, 2312 insertions(+), 595 deletions(-) create mode 100644 01_essentials/09-multiplayer/FACILITATOR-SETUP.md create mode 100644 01_essentials/09-multiplayer/README.md rename {03_advanced => 02_advanced}/01-rebasing/README.md (100%) rename {03_advanced => 02_advanced}/01-rebasing/reset.ps1 (100%) rename {03_advanced => 02_advanced}/01-rebasing/setup.ps1 (100%) rename {03_advanced => 02_advanced}/01-rebasing/verify.ps1 (100%) rename {03_advanced => 02_advanced}/02-interactive-rebase/README.md (100%) rename {03_advanced => 02_advanced}/02-interactive-rebase/reset.ps1 (100%) rename {03_advanced => 02_advanced}/02-interactive-rebase/setup.ps1 (100%) rename {03_advanced => 02_advanced}/02-interactive-rebase/verify.ps1 (100%) rename {03_advanced => 02_advanced}/03-worktrees/README.md (100%) rename {03_advanced => 02_advanced}/03-worktrees/reset.ps1 (100%) rename {03_advanced => 02_advanced}/03-worktrees/setup.ps1 (100%) rename {03_advanced => 02_advanced}/03-worktrees/verify.ps1 (100%) rename {03_advanced => 02_advanced}/04-bisect/README.md (100%) rename {03_advanced => 02_advanced}/04-bisect/reset.ps1 (100%) rename {03_advanced => 02_advanced}/04-bisect/setup.ps1 (100%) rename {03_advanced => 02_advanced}/04-bisect/verify.ps1 (100%) rename {03_advanced => 02_advanced}/05-blame/README.md (100%) rename {03_advanced => 02_advanced}/05-blame/reset.ps1 (100%) rename {03_advanced => 02_advanced}/05-blame/setup.ps1 (100%) rename {03_advanced => 02_advanced}/05-blame/verify.ps1 (100%) rename {03_advanced => 02_advanced}/06-merge-strategies/README.md (100%) rename {03_advanced => 02_advanced}/06-merge-strategies/reset.ps1 (100%) rename {03_advanced => 02_advanced}/06-merge-strategies/setup.ps1 (100%) rename {03_advanced => 02_advanced}/06-merge-strategies/verify.ps1 (100%) delete mode 100644 02_multiplayer/01-remotes/README.md delete mode 100644 02_multiplayer/01-remotes/reset.ps1 delete mode 100644 02_multiplayer/01-remotes/setup.ps1 delete mode 100644 02_multiplayer/01-remotes/verify.ps1 diff --git a/01_essentials/09-multiplayer/FACILITATOR-SETUP.md b/01_essentials/09-multiplayer/FACILITATOR-SETUP.md new file mode 100644 index 0000000..21117c0 --- /dev/null +++ b/01_essentials/09-multiplayer/FACILITATOR-SETUP.md @@ -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 ` +- 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.** diff --git a/01_essentials/09-multiplayer/README.md b/01_essentials/09-multiplayer/README.md new file mode 100644 index 0000000..bd1cad7 --- /dev/null +++ b/01_essentials/09-multiplayer/README.md @@ -0,0 +1,1408 @@ +# Module 09: Multiplayer Git - The Great Print Project + +## Learning Objectives + +By the end of this module, you will: +- Clone and work with remote repositories on a cloud server +- Collaborate with a partner using shared branches +- Resolve merge conflicts in a real team environment +- Create and review pull requests on Gitea +- Synchronize your work with teammates +- Apply all the Git skills you've learned in a collaborative setting + +## Welcome to Real Collaboration! + +Congratulations on making it this far! You've learned Git basics: committing, branching, merging, and even resolving conflicts solo. But here's where it gets real - **working with actual teammates on a shared codebase**. + +This module is different from all the others. There's no `setup.ps1` script creating a simulated environment. Instead, you'll work with: +- A real Git server: **https://git.frod.dk/multiplayer** +- Real teammates (your pair partner) +- Real branches on a shared repository +- Real merge conflicts when you both push to the same branch +- Real pull requests that others will review + +**This is exactly how professional developers collaborate every day on GitHub, GitLab, Bitbucket, and company Git servers.** + +Ready? Let's build something together! + +--- + +## The Great Print Project + +### What You'll Build + +You and your partner are joining a team project to build a Python program that prints the complete alphabet (A-Z) and numbers (0-9). When finished and all pairs have completed their work, running `python main.py` will output: + +``` +================================================== + 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 role:** Each pair implements 3 functions (e.g., `print_b()`, `print_c()`, `print_d()`). + +**The challenge:** You'll need to collaborate with your partner, handle merge conflicts when you both edit the same code, and integrate your work with other pairs through pull requests. + +### Why This Project? + +This project teaches collaboration in a safe, structured way: + +1. **Simple code:** Implementing `print("B", end=" ")` is easy. The hard part is Git, not Python. +2. **Clear success:** You can visually verify your letters appear in the output. +3. **Guaranteed conflicts:** You'll deliberately create merge conflicts to practice resolving them. +4. **Team integration:** Your work depends on others, just like real software projects. +5. **Safe experimentation:** It's okay to make mistakes - you can always pull a fresh copy! + +### Repository Structure + +``` +great-print-project/ +├── main.py # Orchestrator - runs the complete program +├── letters.py # Functions for A-Z (pairs 1-9 work here) +├── numbers.py # Functions for 0-9 (pairs 9-12 work here) +├── assignments.md # See which functions your pair should implement +└── README.md # Quick reference for the project +``` + +**Note:** The repository is already set up on the server with starter code. You'll clone it and add your parts! + +--- + +## Prerequisites + +Before starting, ensure you have: + +### 1. Your Gitea Account + +Your facilitator will provide: +- **Username:** (e.g., `student01`, `student02`) +- **Password or Access Token:** For HTTPS authentication +- OR **SSH Key Setup:** If using SSH + +**First-time setup:** Visit https://git.frod.dk/multiplayer and log in to verify your account works. + +### 2. Git Configuration + +Verify your Git identity is configured: + +```bash +git config --global user.name +git config --global user.email +``` + +If these are empty, set them now: + +```bash +git config --global user.name "Your Name" +git config --global user.email "your.email@example.com" +``` + +**Why this matters:** Every commit you make will be tagged with this information. + +### 3. Authentication Setup + +Choose ONE method for authenticating with the Git server: + +**Method A: HTTPS with Access Token (Recommended)** + +1. Log in to https://git.frod.dk/multiplayer +2. Go to Settings → Applications → Tokens +3. Generate a new token with `repo` permissions +4. Save the token securely (you'll use it as your password when pushing/pulling) + +**Method B: SSH Key** + +1. Generate SSH key (if you don't have one): + ```bash + ssh-keygen -t ed25519 -C "your.email@example.com" + ``` +2. Copy your public key: + ```bash + cat ~/.ssh/id_ed25519.pub + ``` +3. Add it to Gitea: Settings → SSH Keys → Add Key +4. Test connection: + ```bash + ssh -T git@git.frod.dk + ``` + +--- + +## Part 1: Getting Started (15 minutes) + +### Step 1: Find Your Pair Partner + +Your facilitator will assign pairs. Find your partner and sit together (or connect on chat if remote). + +**Important:** Both of you will work on the **same branch**. This simulates real team development where multiple developers collaborate on a feature branch. + +### Step 2: Check Your Assignment + +Your facilitator will tell you your pair number (1-12). Remember this number! + +**Example assignments:** +- **Pair 1:** Functions `print_b()`, `print_c()`, `print_d()` in `letters.py` +- **Pair 2:** Functions `print_e()`, `print_f()`, `print_g()` in `letters.py` +- **Pair 9:** Functions `print_z()` in `letters.py`, `print_0()`, `print_1()` in `numbers.py` +- **Pair 12:** Functions `print_8()`, `print_9()` in `numbers.py` + +### Step 3: Clone the Repository + +**Using HTTPS (recommended):** + +```bash +git clone https://git.frod.dk/multiplayer/great-print-project.git +cd great-print-project +``` + +**Using SSH:** + +```bash +git clone git@git.frod.dk:multiplayer/great-print-project.git +cd great-print-project +``` + +**Expected output:** + +``` +Cloning into 'great-print-project'... +remote: Enumerating objects: 10, done. +remote: Counting objects: 100% (10/10), done. +remote: Compressing objects: 100% (7/7), done. +remote: Total 10 (delta 2), reused 0 (delta 0), pack-reused 0 +Receiving objects: 100% (10/10), done. +Resolving deltas: 100% (2/2), done. +``` + +Success! You now have a local copy of the shared repository. + +### Step 4: Explore the Code + +Let's see what we're working with: + +```bash +# List files +ls -la + +# Run the program in its current state +python main.py + +# View your pair's assignment +cat assignments.md +``` + +**What you'll see when running `python main.py`:** + +``` +================================================== + THE GREAT PRINT PROJECT +================================================== + +Letters: +A + +Numbers: + + +================================================== + PROJECT COMPLETE! +================================================== +``` + +Most letters and numbers are missing! Only `print_a()` is implemented as an example. Your job is to add your assigned functions. + +### Step 5: Create Your Feature Branch + +**Both partners should create the SAME branch name:** + +```bash +# Replace X with your pair number (1-12) +# Example: pair-1-bcd, pair-2-efg, pair-3-hij +git switch -c pair-X-feature +``` + +**Example for Pair 1:** + +```bash +git switch -c pair-1-bcd +``` + +**Expected output:** + +``` +Switched to a new branch 'pair-1-bcd' +``` + +**Verify you're on the right branch:** + +```bash +git branch +``` + +You should see `* pair-1-bcd` (or your pair's branch name) with an asterisk. + +> **Important:** Both partners MUST use the exact same branch name! This allows you to push and pull each other's work. + +--- + +## Part 2: Your First Contribution (20 minutes) + +Now you'll practice the basic collaborative workflow: one partner pushes, the other pulls, then you switch roles. + +### Step 1: Decide Who Goes First + +Choose one partner to be **Partner A** (goes first) and one to be **Partner B** (goes second). + +- **Partner A:** Will implement the first function and push to the server +- **Partner B:** Will pull Partner A's work, then implement the second function + +Later you'll switch roles for the third function. + +### Step 2: Partner A - Complete ONE Function + +**Partner A:** Open the appropriate file (`letters.py` or `numbers.py`) in your text editor. + +**Example for Pair 1 (editing `letters.py`):** + +Find this: + +```python +def print_b(): + # TODO: Pair 1 - implement this function + pass +``` + +Change it to: + +```python +def print_b(): + """Print letter B""" + print("B", end=" ") +``` + +**Key points:** +- Use `end=" "` to add a space after the letter/number +- Follow the pattern from `print_a()` (already implemented as an example) +- Keep it simple! + +### Step 3: Test Your Change + +```bash +python main.py +``` + +**Expected output:** + +``` +Letters: +A B +``` + +Great! The B now appears. (C and D still missing because you haven't implemented them yet.) + +### Step 4: Commit Your Work + +```bash +git status +# You should see: modified: letters.py + +git add letters.py +git commit -m "Add print_b() implementation" +``` + +**Expected output:** + +``` +[pair-1-bcd abc1234] Add print_b() implementation + 1 file changed, 2 insertions(+), 2 deletions(-) +``` + +### Step 5: Push to Remote + +This uploads your commit to the shared server: + +```bash +git push -u origin pair-1-bcd +``` + +**The `-u` flag:** Sets up tracking so future pushes can just use `git push`. + +**Expected output:** + +``` +Enumerating objects: 5, done. +Counting objects: 100% (5/5), done. +Delta compression using up to 8 threads +Compressing objects: 100% (3/3), done. +Writing objects: 100% (3/3), 345 bytes | 345.00 KiB/s, done. +Total 3 (delta 1), reused 0 (delta 0), pack-reused 0 +remote: . Processing 1 references +remote: Processed 1 references in total +To https://git.frod.dk/multiplayer/great-print-project.git + * [new branch] pair-1-bcd -> pair-1-bcd +``` + +Success! Your code is now on the server. + +### Step 6: Partner B - Pull Partner A's Work + +**Partner B:** Make sure you're on the same branch, then pull: + +```bash +# Verify branch (should match Partner A's) +git branch + +# Pull Partner A's changes from the server +git pull origin pair-1-bcd +``` + +**Expected output:** + +``` +From https://git.frod.dk/multiplayer/great-print-project + * branch pair-1-bcd -> FETCH_HEAD +Updating 123abc..456def +Fast-forward + letters.py | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) +``` + +**Verify you have Partner A's code:** + +```bash +cat letters.py | grep -A 2 "def print_b" +# Should show Partner A's implementation + +python main.py +# Should show "A B" in the output +``` + +You now have Partner A's work! + +### Step 7: Partner B - Add Your Function + +**Partner B:** Now it's your turn! Implement the SECOND assigned function. + +**Example for Pair 1:** + +```python +def print_c(): + """Print letter C""" + print("C", end=" ") +``` + +**Test, commit, and push:** + +```bash +python main.py +# Should show: A B C + +git add letters.py +git commit -m "Add print_c() implementation" +git push origin pair-1-bcd +``` + +### Step 8: Partner A - Pull Partner B's Work + +**Partner A:** Pull the latest changes: + +```bash +git pull origin pair-1-bcd +``` + +**Verify you have both functions:** + +```bash +python main.py +# Should show: A B C +``` + +### Step 9: Complete Your Third Function Together + +For your third and final function, EITHER partner can implement it. Follow the same cycle: +1. Implement the function +2. Test with `python main.py` +3. Commit and push +4. Other partner pulls + +**When you're done, all three assigned functions should be complete!** + +```bash +python main.py +# Pair 1 should see: A B C D +``` + +**Congratulations! You've completed your first collaborative Git workflow!** You've learned the core cycle: pull → work → commit → push → pull. This is what professional developers do hundreds of times per day. + +--- + +## Part 3: Deliberate Conflict Exercise (30 minutes) + +Now for the **real** learning: merge conflicts! You'll deliberately create a conflict with your partner, then resolve it together. + +### The Scenario + +Merge conflicts happen when two people edit the same lines in the same file. Git can't automatically decide which version to keep, so it asks you to resolve it manually. + +**What you'll do:** +1. Partner A and Partner B will BOTH edit the same function +2. Partner A pushes first (succeeds) +3. Partner B tries to push (gets rejected!) +4. Partner B pulls (sees conflict markers) +5. You resolve the conflict together +6. Partner B pushes the resolution + +This is a **deliberate practice** scenario. In real projects, conflicts happen by accident - now you'll know how to handle them! + +### Setup: Choose a Conflict Function + +Look at your three assigned functions. Pick the **LAST** one for this exercise. + +- **Pair 1:** Use `print_d()` +- **Pair 2:** Use `print_g()` +- **Pair 9:** Use `print_1()` (in numbers.py) + +### Step 1: Both Partners Start Fresh + +Make sure you both have the latest code: + +```bash +git switch pair-1-bcd +git pull origin pair-1-bcd + +# Check status - should be clean +git status +``` + +Both partners should see: "Your branch is up to date" and "nothing to commit, working tree clean" + +### Step 2: Partner A - Make Your Change First + +**Partner A:** Edit the chosen function with a SPECIFIC implementation. + +**Example for `print_d()`:** + +```python +def print_d(): + """Print letter D""" + print("D", end=" ") # Partner A's version +``` + +**Commit and push IMMEDIATELY:** + +```bash +git add letters.py +git commit -m "Partner A: Add print_d()" +git push origin pair-1-bcd +``` + +Partner A should see: "Everything up-to-date" or the commit being pushed successfully. + +### Step 3: Partner B - Make DIFFERENT Change (DON'T PULL YET!) + +**Partner B:** This is critical - do NOT pull Partner A's changes yet! + +Instead, edit the SAME function with a DIFFERENT implementation: + +```python +def print_d(): + """Print letter D""" + print("D ", end="") # Partner B's version (extra space, different quote style) +``` + +**Commit (but don't push yet):** + +```bash +git add letters.py +git commit -m "Partner B: Add print_d()" +``` + +### Step 4: Partner B - Try to Push (This Will Fail!) + +```bash +git push origin pair-1-bcd +``` + +**You'll see an error like this:** + +``` +To https://git.frod.dk/multiplayer/great-print-project.git + ! [rejected] pair-1-bcd -> pair-1-bcd (fetch first) +error: failed to push some refs to 'https://git.frod.dk/multiplayer/great-print-project.git' +hint: Updates were rejected because the remote contains work that you do +hint: not have locally. This is usually caused by another repository pushing +hint: to the same ref. You may want to first integrate the remote changes +hint: (e.g., 'git pull ...') before pushing again. +hint: See the 'Note about fast-forwards' in 'git push --help' for details. +``` + +**Don't panic!** This is completely normal and expected. Git is protecting you from overwriting Partner A's work. + +**What happened:** Partner A pushed commits that you don't have. Git requires you to pull first and integrate their changes before you can push yours. + +### Step 5: Partner B - Pull and See the Conflict + +```bash +git pull origin pair-1-bcd +``` + +**You'll see:** + +``` +From https://git.frod.dk/multiplayer/great-print-project + * branch pair-1-bcd -> FETCH_HEAD +Auto-merging letters.py +CONFLICT (content): Merge conflict in letters.py +Automatic merge failed; fix conflicts and then commit the result. +``` + +**This is a merge conflict!** Git tried to merge Partner A's changes with yours, but couldn't automatically combine them because you both edited the same lines. + +### Step 6: Check Git Status + +```bash +git status +``` + +**Output:** + +``` +On branch pair-1-bcd +You have unmerged paths. + (fix conflicts and run "git commit") + (use "git merge --abort" to abort the merge) + +Unmerged paths: + (use "git add ..." to mark resolution) + both modified: letters.py + +no changes added to commit (use "git add" and/or "git commit -a") +``` + +Git is telling you: "The file `letters.py` has conflicts. Both of you modified it. Please resolve and commit." + +### Step 7: Open the Conflicted File + +```bash +cat letters.py +# Or open in your text editor: code letters.py, vim letters.py, nano letters.py +``` + +**Find the conflict markers around `print_d()`:** + +```python +def print_d(): + """Print letter D""" +<<<<<<< HEAD + print("D ", end="") # Partner B's version +======= + print("D", end=" ") # Partner A's version +>>>>>>> abc1234567890abcdef1234567890abcdef12 +``` + +### Understanding Conflict Markers + +```python +<<<<<<< HEAD # Start marker + print("D ", end="") # YOUR version (Partner B's code) +======= # Divider + print("D", end=" ") # THEIR version (Partner A's code from remote) +>>>>>>> abc1234... # End marker (shows commit hash) +``` + +**The three sections:** +1. `<<<<<<< HEAD` to `=======`: Your current changes (what you committed locally) +2. `=======` to `>>>>>>>`: Their changes (what Partner A pushed to the server) +3. You must choose one, combine them, or write something new + +### Step 8: Resolve the Conflict TOGETHER + +**Talk with your partner!** Look at both versions and decide: + +**Option 1: Keep Partner A's version** +```python +def print_d(): + """Print letter D""" + print("D", end=" ") +``` + +**Option 2: Keep Partner B's version** +```python +def print_d(): + """Print letter D""" + print("D ", end="") +``` + +**Option 3: Agree on a third option** +```python +def print_d(): + """Print letter D""" + print("D", end=" ") # Agreed version after discussion +``` + +**Edit the file to:** +1. Remove ALL conflict markers (`<<<<<<<`, `=======`, `>>>>>>>`) +2. Keep the agreed-upon code +3. Make sure the syntax is valid Python + +**Example resolved version:** + +```python +def print_d(): + """Print letter D""" + print("D", end=" ") # Resolved: using Partner A's version +``` + +**Save the file!** + +### Step 9: Test the Resolution + +```bash +python main.py +``` + +Make sure the program runs without errors and shows the expected output. If you see syntax errors, you probably left conflict markers in the file - open it again and remove them. + +### Step 10: Mark as Resolved and Commit + +Tell Git you've resolved the conflict: + +```bash +git add letters.py +``` + +This stages the resolved file. + +Now commit the resolution: + +```bash +git commit -m "Resolve conflict in print_d() - used Partner A's version" +``` + +**Note:** Git may open an editor with a default merge commit message. You can keep it or customize it. + +**Expected output:** + +``` +[pair-1-bcd def5678] Resolve conflict in print_d() - used Partner A's version +``` + +### Step 11: Partner B - Push the Resolution + +```bash +git push origin pair-1-bcd +``` + +This time it should succeed! The conflict is resolved and your unified code is on the server. + +### Step 12: Partner A - Pull the Resolved Version + +**Partner A:** Get the resolved code: + +```bash +git pull origin pair-1-bcd +``` + +Check the file - you should see the agreed-upon resolution. + +**You've successfully resolved your first merge conflict together!** In real projects, this is a daily occurrence. You now know exactly what to do when you see those conflict markers. + +--- + +## Part 4: Pull Requests (20 minutes) + +Now that your functions are complete and tested, it's time to integrate your work into the main branch through a **Pull Request (PR)**. + +Pull requests are how professional teams review code before merging it. Someone proposes changes, others review and comment, and when approved, the changes are merged. + +### Step 1: Push All Your Work + +Make sure everything is committed and pushed: + +```bash +git status +# Should show: "Your branch is up to date" and "nothing to commit" + +# If you have uncommitted changes, commit them now +git add . +git commit -m "Complete all assigned functions" + +# Push to make sure server has latest +git push origin pair-1-bcd +``` + +### Step 2: Create Pull Request on Gitea + +1. **Open browser:** Navigate to https://git.frod.dk/multiplayer/great-print-project + +2. **Go to Pull Requests tab:** Click "Pull Requests" in the top navigation + +3. **Click "New Pull Request"** + +4. **Set the branches:** + - **Base branch:** `main` (where your code will be merged) + - **Compare branch:** `pair-1-bcd` (your feature branch) + +5. **Fill in the pull request form:** + +**Title:** Clear, concise description +``` +Implement functions for Pair 1 (B, C, D) +``` + +**Description:** Use this template: + +```markdown +## What This PR Does + +Implements the following functions for Pair 1: +- `print_b()` - prints letter B +- `print_c()` - prints letter C +- `print_d()` - prints letter D + +## Testing + +- [x] Ran `python main.py` locally +- [x] All assigned letters print correctly (A B C D) +- [x] No Python syntax errors +- [x] No conflict markers left in code + +## Pair Members + +- Partner A: [Your Name Here] +- Partner B: [Partner's Name Here] + +## Notes + +Resolved a merge conflict in `print_d()` during development. Both partners agreed on the final implementation. +``` + +6. **Click "Create Pull Request"** + +Your PR is now created! Others can see it, comment on your code, and approve it. + +### Step 3: Review Another Pair's PR + +Learning to review code is just as important as writing it! + +**Find a PR to review:** + +1. Go to "Pull Requests" tab +2. Look for PRs from other pairs +3. Click on one that interests you + +**Review the code:** + +1. Click "Files Changed" tab +2. Look at the code they wrote +3. Check for: + - Do the functions follow the pattern (`print("X", end=" ")`)? + - Are there any syntax errors? + - Did they implement their assigned functions? + - Is the code clean and readable? + +**Leave comments:** + +**Positive feedback:** +``` +✅ Looks good! LGTM (Looks Good To Me) +Great work on the implementation! +``` + +**Suggestions:** +``` +💡 Suggestion: Consider adding a docstring to this function for clarity +``` + +**Questions:** +``` +❓ Question: Why did you use double quotes instead of single quotes? +(Either is fine in Python, just curious about your choice!) +``` + +**Approve the PR (if allowed):** +- Click "Approve" or "LGTM" (Looks Good To Me) + +### Step 4: Address Feedback on Your PR + +Check your own PR for comments: + +1. Go to "Pull Requests" → Your PR +2. Read any comments left by reviewers +3. If changes requested: + - Make edits locally + - Commit and push (PR updates automatically!) + - Reply to comments + +### Step 5: Merge Your PR (When Approved) + +Depending on your facilitator's setup: + +**Option A: Wait for facilitator to merge** +- Facilitator reviews all PRs +- Merges them in order +- You'll get a notification when merged + +**Option B: Merge yourself (if you have permissions)** +1. Click "Merge Pull Request" +2. Confirm the merge +3. Optionally delete your branch (server will prompt) + +**After merge:** + +Your code is now in `main`! Run this to see it: + +```bash +git switch main +git pull origin main +python main.py +``` + +You should see your letters in the final output along with letters from other pairs who have merged! + +--- + +## Part 5: Staying in Sync (15 minutes) + +As other pairs merge their PRs, the `main` branch updates. You need to stay synchronized to avoid conflicts later. + +### When to Sync + +Sync your branch with `main` when: +- You see other pairs' PRs getting merged +- Before starting new work +- When you get push rejections + +### How to Sync + +**Step 1: Update your local `main` branch** + +```bash +# Switch to main +git switch main + +# Pull latest changes +git pull origin main +``` + +You should see new commits from other pairs! + +**Step 2: Update your feature branch** + +```bash +# Switch back to your branch +git switch pair-1-bcd + +# Merge main into your branch +git merge main +``` + +**If there are NO conflicts:** + +``` +Updating abc1234..def5678 +Fast-forward + letters.py | 15 +++++++++++++++ + 2 files changed, 15 insertions(+) +``` + +Great! Your branch now has all the latest changes. + +```bash +# Push the updated branch +git push origin pair-1-bcd +``` + +**If there ARE conflicts:** + +``` +Auto-merging letters.py +CONFLICT (content): Merge conflict in letters.py +Automatic merge failed; fix conflicts and then commit the result. +``` + +Follow the conflict resolution steps from Part 3: +1. Open the file +2. Find conflict markers +3. Discuss with partner which version to keep +4. Remove markers +5. Test the code +6. `git add` the resolved file +7. `git commit` the merge +8. `git push` the resolution + +### Viewing What Changed + +Before merging, see what's new in `main`: + +```bash +# See commits in main that you don't have +git log main..pair-1-bcd --oneline + +# See code changes +git diff main..pair-1-bcd +``` + +--- + +## Commands Reference + +### Essential Git Commands for Collaboration + +**Cloning and Setup:** +```bash +git clone # Create local copy of remote repo +git config user.name "Your Name" # Set your name (one-time setup) +git config user.email "your@email.com" # Set your email (one-time setup) +``` + +**Branching:** +```bash +git switch -c # Create and switch to new branch +git switch # Switch to existing branch +git branch # List local branches (* = current) +git branch -a # List all branches (local + remote) +git branch -d # Delete branch (safe - prevents data loss) +``` + +**Making Changes:** +```bash +git status # See current state and changed files +git add # Stage specific file +git add . # Stage all changed files +git commit -m "message" # Commit staged changes with message +git commit # Commit and open editor for message +``` + +**Synchronizing with Remote:** +```bash +git pull origin # Fetch and merge from remote branch +git push origin # Push commits to remote branch +git push -u origin # Push and set upstream tracking +git fetch origin # Download changes without merging +git remote -v # Show configured remotes +``` + +**Conflict Resolution:** +```bash +git status # See which files have conflicts +# Edit files to remove <<<<<<, =======, >>>>>>> markers +git add # Mark file as resolved +git commit -m "Resolve conflict in ..." # Commit the resolution +git merge --abort # Abort merge and go back to before +``` + +**Merging and Integration:** +```bash +git merge # Merge branch into current branch +git merge main # Common: merge main into feature branch +git log --oneline --graph --all # Visualize branch history +``` + +**Viewing Changes:** +```bash +git diff # See unstaged changes +git diff --staged # See staged changes +git show # Show last commit +git log --oneline # See commit history (concise) +git log --oneline --graph # See branch structure visually +``` + +--- + +## Common Scenarios & Solutions + +### "My push was rejected!" + +**Error:** +``` +! [rejected] pair-1-bcd -> pair-1-bcd (fetch first) +error: failed to push some refs to 'https://git.frod.dk/...' +``` + +**What it means:** Someone else (probably your partner) pushed commits to this branch since you last pulled. + +**Solution:** +```bash +# Pull their changes first +git pull origin pair-1-bcd + +# If conflicts, resolve them (see Part 3) +# If no conflicts, you can now push +git push origin pair-1-bcd +``` + +--- + +### "I have merge conflicts!" + +**What you see:** +``` +CONFLICT (content): Merge conflict in letters.py +Automatic merge failed; fix conflicts and then commit the result. +``` + +**Solution:** +1. Don't panic - this is normal! +2. Run `git status` to see which files have conflicts +3. Open the conflicted file(s) in your editor +4. Find the conflict markers: `<<<<<<<`, `=======`, `>>>>>>>` +5. **Talk with your partner** - decide which version to keep +6. Remove ALL markers and keep the agreed code +7. Test: `python main.py` (make sure it works!) +8. Stage: `git add letters.py` +9. Commit: `git commit -m "Resolve conflict in letters.py"` +10. Push: `git push origin pair-1-bcd` + +--- + +### "My partner pushed, how do I get their changes?" + +**Solution:** +```bash +# Make sure you're on the right branch +git branch +# Should show: * pair-1-bcd + +# Pull their changes +git pull origin pair-1-bcd +``` + +If you have uncommitted changes, Git might ask you to commit or stash first: +```bash +# Option 1: Commit your changes first +git add . +git commit -m "Work in progress" +git pull origin pair-1-bcd + +# Option 2: Stash your changes temporarily +git stash +git pull origin pair-1-bcd +git stash pop # Restore your changes after pull +``` + +--- + +### "We both edited the same line!" + +**This creates a conflict - which is exactly what we want to practice!** + +**Solution:** +Follow the complete conflict resolution workflow from Part 3. The key steps: +1. Partner who tries to push second gets rejection +2. They pull (sees conflict) +3. Both partners look at the conflict markers together +4. Decide which version to keep (or create new version) +5. Remove markers, test, commit, push + +--- + +### "I committed to the wrong branch!" + +**Scenario:** You meant to commit to `pair-1-bcd` but you're on `main`. + +**Solution (if you haven't pushed yet):** +```bash +# Find the commit hash +git log --oneline -n 1 +# Example output: abc1234 Add print_b() + +# Switch to correct branch +git switch pair-1-bcd + +# Cherry-pick the commit +git cherry-pick abc1234 + +# Go back to main and undo the wrong commit +git switch main +git reset --hard origin/main # Dangerous: only if you haven't pushed! +``` + +**If you already pushed:** Ask facilitator for help or create a revert commit. + +--- + +### "How do I see what changed?" + +**Before committing:** +```bash +git diff # See unstaged changes +git diff --staged # See staged changes (after git add) +``` + +**After committing:** +```bash +git show # Show last commit's changes +git log --oneline # See commit history (one line per commit) +git log --oneline --graph # See branch structure with commits +git log -p # See commits WITH their code changes +``` + +**Compare branches:** +```bash +# See what's in main that you don't have +git log pair-1-bcd..main --oneline + +# See code differences between branches +git diff pair-1-bcd..main +``` + +--- + +### "I want to start over on this file!" + +**Scenario:** You made a mess and want to restore the file to the last committed version. + +**Solution:** +```bash +# Discard all changes to the file (CAREFUL: can't undo this!) +git restore letters.py + +# Or restore to a specific commit +git restore --source=abc1234 letters.py +``` + +**If you want to keep your changes but try a different approach:** +```bash +# Save your work temporarily +git stash + +# Work is saved, file is back to clean state +# Later, restore your work: +git stash pop +``` + +--- + +## Troubleshooting + +### Authentication Issues + +**Problem:** "Authentication failed" when pushing or pulling + +**Solution (HTTPS):** +1. Make sure you're using your **access token** as the password, not your account password +2. Check token has `repo` permissions in Gitea settings +3. Try cloning with token in URL (not recommended for security, but useful for debugging): + ```bash + git clone https://username:TOKEN@git.frod.dk/multiplayer/great-print-project.git + ``` + +**Solution (SSH):** +1. Verify your SSH key is added to Gitea: Settings → SSH Keys +2. Test SSH connection: + ```bash + ssh -T git@git.frod.dk + ``` +3. Make sure you cloned with SSH URL (`git@git.frod.dk:...`) not HTTPS URL + +--- + +### Can't Pull or Push - "Unrelated Histories" + +**Problem:** +``` +fatal: refusing to merge unrelated histories +``` + +**What happened:** Your local branch and remote branch don't share a common ancestor (rare, but happens if branches were created independently). + +**Solution:** +```bash +git pull origin pair-1-bcd --allow-unrelated-histories +``` + +Then resolve any conflicts if they appear. + +--- + +### Accidentally Deleted Important Code + +**Problem:** "I deleted something important and committed it!" + +**Solution:** + +**If not pushed yet:** +```bash +# Find the commit before deletion +git log --oneline + +# Example: abc1234 was the last good commit +git reset --hard abc1234 +``` + +**If already pushed:** +```bash +# Find the commit with the deleted code +git log --oneline + +# Restore the file from that commit +git checkout abc1234 -- letters.py + +# Commit the restoration +git add letters.py +git commit -m "Restore accidentally deleted code" +git push origin pair-1-bcd +``` + +**Pro tip:** Use `git log --all --full-history -- letters.py` to see all commits that touched that file. + +--- + +### File Has Conflict Markers After "Resolving" + +**Problem:** You thought you resolved the conflict, but when you run `python main.py`: +``` + File "letters.py", line 42 + <<<<<<< HEAD + ^ +SyntaxError: invalid syntax +``` + +**What happened:** You forgot to remove the conflict markers (`<<<<<<<`, `=======`, `>>>>>>>`). + +**Solution:** +```bash +# Open the file +nano letters.py # or vim, code, etc. + +# Search for "<<<<<<<" and remove ALL markers +# Keep only the code you want + +# Test again +python main.py + +# If it works, commit the fix +git add letters.py +git commit -m "Remove remaining conflict markers" +``` + +--- + +### Wrong Pair Assignment + +**Problem:** "We implemented the wrong functions!" + +**Solution:** +1. **Don't panic** - your Git skills are still valid! +2. Check with facilitator about your correct assignment +3. Either: + - **Option A:** Keep your current work and implement correct functions in a new commit + - **Option B:** Revert your commits and start fresh with correct functions +4. Communicate with other pairs to avoid duplicate work + +--- + +## Success Criteria + +You've completed this module when you can check off ALL of these: + +**Basic Collaboration:** +- [ ] Cloned the repository from https://git.frod.dk/multiplayer +- [ ] Created a feature branch with your pair (both using same branch name) +- [ ] Completed your assigned functions (all 2-3 functions) +- [ ] Successfully pushed and pulled changes with your partner + +**Conflict Resolution:** +- [ ] Deliberately created a merge conflict with your partner +- [ ] Saw the conflict markers in the file (`<<<<<<<`, `=======`, `>>>>>>>`) +- [ ] Resolved the conflict by editing the file +- [ ] Successfully pushed the resolution + +**Pull Requests:** +- [ ] Created a pull request from your branch to `main` +- [ ] Wrote a meaningful PR description +- [ ] Reviewed at least one other pair's pull request +- [ ] Your pull request was merged (or is approved and waiting for merge) + +**Integration:** +- [ ] When you run `python main.py` on the `main` branch, your letters/numbers appear in the output +- [ ] No conflict markers remain in any files +- [ ] All tests pass (if applicable) + +**Bonus (if time permits):** +- [ ] Synced your branch with latest `main` after other pairs merged +- [ ] Helped another pair resolve a conflict +- [ ] Left constructive code review comments on 2+ pull requests + +--- + +## What You've Learned + +**Collaborative Git Skills:** +- ✅ Cloning repositories from remote Git servers +- ✅ Working with teammates on shared branches +- ✅ The push/pull cycle for synchronizing work +- ✅ Creating and resolving real merge conflicts +- ✅ Creating meaningful pull requests +- ✅ Reviewing others' code and leaving feedback +- ✅ Staying synchronized with team changes +- ✅ Using Git in a realistic team environment + +**Real-World Applications:** + +**These skills are exactly what you'll use at work:** +- This workflow works on GitHub, GitLab, Bitbucket, Azure DevOps, and any Git server +- Professional teams do this hundreds of times per day +- Open source projects use pull requests for all contributions +- Companies require code reviews before merging to production + +**You're now ready to:** +- Contribute to open source projects on GitHub +- Join a development team and collaborate effectively +- Handle merge conflicts without panic +- Review teammates' code professionally +- Work on distributed teams across time zones + +--- + +## What's Next? + +### More Advanced Git Modules + +Continue your Git journey with advanced techniques: + +- **02_advanced/01-rebasing**: Learn to rebase instead of merge for cleaner history +- **02_advanced/02-interactive-rebase**: Clean up messy commits before submitting PRs +- **02_advanced/03-worktrees**: Work on multiple branches simultaneously +- **02_advanced/04-bisect**: Find bugs using binary search through commit history +- **02_advanced/05-blame**: Investigate who changed what and when +- **02_advanced/06-merge-strategies**: Master different merge strategies and when to use them + +### Practice More + +- Try contributing to a real open source project on GitHub +- Practice more complex workflows (multiple feature branches, rebasing, etc.) +- Help teammates at work or school with Git issues + +--- + +## Congratulations! + +**You've completed the Multiplayer Git module!** + +You started this workshop learning basic Git commands like `git init` and `git commit`. Now you're collaborating with teammates, resolving conflicts, and reviewing code like a professional developer. + +**What makes you different from most beginners:** +- You've experienced REAL merge conflicts and resolved them +- You've worked on a REAL shared repository with teammates +- You've created REAL pull requests and reviewed code +- You've practiced the entire workflow professionals use daily + +**Most importantly:** You're no longer afraid of merge conflicts. You know exactly what to do when you see those `<<<<<<<` markers. + +**Keep practicing, keep collaborating, and welcome to the world of professional Git!** + +--- + +**Happy Collaborating!** diff --git a/03_advanced/01-rebasing/README.md b/02_advanced/01-rebasing/README.md similarity index 100% rename from 03_advanced/01-rebasing/README.md rename to 02_advanced/01-rebasing/README.md diff --git a/03_advanced/01-rebasing/reset.ps1 b/02_advanced/01-rebasing/reset.ps1 similarity index 100% rename from 03_advanced/01-rebasing/reset.ps1 rename to 02_advanced/01-rebasing/reset.ps1 diff --git a/03_advanced/01-rebasing/setup.ps1 b/02_advanced/01-rebasing/setup.ps1 similarity index 100% rename from 03_advanced/01-rebasing/setup.ps1 rename to 02_advanced/01-rebasing/setup.ps1 diff --git a/03_advanced/01-rebasing/verify.ps1 b/02_advanced/01-rebasing/verify.ps1 similarity index 100% rename from 03_advanced/01-rebasing/verify.ps1 rename to 02_advanced/01-rebasing/verify.ps1 diff --git a/03_advanced/02-interactive-rebase/README.md b/02_advanced/02-interactive-rebase/README.md similarity index 100% rename from 03_advanced/02-interactive-rebase/README.md rename to 02_advanced/02-interactive-rebase/README.md diff --git a/03_advanced/02-interactive-rebase/reset.ps1 b/02_advanced/02-interactive-rebase/reset.ps1 similarity index 100% rename from 03_advanced/02-interactive-rebase/reset.ps1 rename to 02_advanced/02-interactive-rebase/reset.ps1 diff --git a/03_advanced/02-interactive-rebase/setup.ps1 b/02_advanced/02-interactive-rebase/setup.ps1 similarity index 100% rename from 03_advanced/02-interactive-rebase/setup.ps1 rename to 02_advanced/02-interactive-rebase/setup.ps1 diff --git a/03_advanced/02-interactive-rebase/verify.ps1 b/02_advanced/02-interactive-rebase/verify.ps1 similarity index 100% rename from 03_advanced/02-interactive-rebase/verify.ps1 rename to 02_advanced/02-interactive-rebase/verify.ps1 diff --git a/03_advanced/03-worktrees/README.md b/02_advanced/03-worktrees/README.md similarity index 100% rename from 03_advanced/03-worktrees/README.md rename to 02_advanced/03-worktrees/README.md diff --git a/03_advanced/03-worktrees/reset.ps1 b/02_advanced/03-worktrees/reset.ps1 similarity index 100% rename from 03_advanced/03-worktrees/reset.ps1 rename to 02_advanced/03-worktrees/reset.ps1 diff --git a/03_advanced/03-worktrees/setup.ps1 b/02_advanced/03-worktrees/setup.ps1 similarity index 100% rename from 03_advanced/03-worktrees/setup.ps1 rename to 02_advanced/03-worktrees/setup.ps1 diff --git a/03_advanced/03-worktrees/verify.ps1 b/02_advanced/03-worktrees/verify.ps1 similarity index 100% rename from 03_advanced/03-worktrees/verify.ps1 rename to 02_advanced/03-worktrees/verify.ps1 diff --git a/03_advanced/04-bisect/README.md b/02_advanced/04-bisect/README.md similarity index 100% rename from 03_advanced/04-bisect/README.md rename to 02_advanced/04-bisect/README.md diff --git a/03_advanced/04-bisect/reset.ps1 b/02_advanced/04-bisect/reset.ps1 similarity index 100% rename from 03_advanced/04-bisect/reset.ps1 rename to 02_advanced/04-bisect/reset.ps1 diff --git a/03_advanced/04-bisect/setup.ps1 b/02_advanced/04-bisect/setup.ps1 similarity index 100% rename from 03_advanced/04-bisect/setup.ps1 rename to 02_advanced/04-bisect/setup.ps1 diff --git a/03_advanced/04-bisect/verify.ps1 b/02_advanced/04-bisect/verify.ps1 similarity index 100% rename from 03_advanced/04-bisect/verify.ps1 rename to 02_advanced/04-bisect/verify.ps1 diff --git a/03_advanced/05-blame/README.md b/02_advanced/05-blame/README.md similarity index 100% rename from 03_advanced/05-blame/README.md rename to 02_advanced/05-blame/README.md diff --git a/03_advanced/05-blame/reset.ps1 b/02_advanced/05-blame/reset.ps1 similarity index 100% rename from 03_advanced/05-blame/reset.ps1 rename to 02_advanced/05-blame/reset.ps1 diff --git a/03_advanced/05-blame/setup.ps1 b/02_advanced/05-blame/setup.ps1 similarity index 100% rename from 03_advanced/05-blame/setup.ps1 rename to 02_advanced/05-blame/setup.ps1 diff --git a/03_advanced/05-blame/verify.ps1 b/02_advanced/05-blame/verify.ps1 similarity index 100% rename from 03_advanced/05-blame/verify.ps1 rename to 02_advanced/05-blame/verify.ps1 diff --git a/03_advanced/06-merge-strategies/README.md b/02_advanced/06-merge-strategies/README.md similarity index 100% rename from 03_advanced/06-merge-strategies/README.md rename to 02_advanced/06-merge-strategies/README.md diff --git a/03_advanced/06-merge-strategies/reset.ps1 b/02_advanced/06-merge-strategies/reset.ps1 similarity index 100% rename from 03_advanced/06-merge-strategies/reset.ps1 rename to 02_advanced/06-merge-strategies/reset.ps1 diff --git a/03_advanced/06-merge-strategies/setup.ps1 b/02_advanced/06-merge-strategies/setup.ps1 similarity index 100% rename from 03_advanced/06-merge-strategies/setup.ps1 rename to 02_advanced/06-merge-strategies/setup.ps1 diff --git a/03_advanced/06-merge-strategies/verify.ps1 b/02_advanced/06-merge-strategies/verify.ps1 similarity index 100% rename from 03_advanced/06-merge-strategies/verify.ps1 rename to 02_advanced/06-merge-strategies/verify.ps1 diff --git a/02_multiplayer/01-remotes/README.md b/02_multiplayer/01-remotes/README.md deleted file mode 100644 index d6b3a97..0000000 --- a/02_multiplayer/01-remotes/README.md +++ /dev/null @@ -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 -git clone - -# View remotes -git remote -git remote -v # Show URLs - -# Add a remote -git remote add - -# Remove a remote -git remote remove - -# Rename a remote -git remote rename - -# Push to remote -git push origin -git push -u origin # Set upstream tracking - -# Pull from remote (fetch + merge) -git pull -git pull origin - -# 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 - -# 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 - -# 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. diff --git a/02_multiplayer/01-remotes/reset.ps1 b/02_multiplayer/01-remotes/reset.ps1 deleted file mode 100644 index ba9f391..0000000 --- a/02_multiplayer/01-remotes/reset.ps1 +++ /dev/null @@ -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" diff --git a/02_multiplayer/01-remotes/setup.ps1 b/02_multiplayer/01-remotes/setup.ps1 deleted file mode 100644 index 35f2a82..0000000 --- a/02_multiplayer/01-remotes/setup.ps1 +++ /dev/null @@ -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 diff --git a/02_multiplayer/01-remotes/verify.ps1 b/02_multiplayer/01-remotes/verify.ps1 deleted file mode 100644 index 622d135..0000000 --- a/02_multiplayer/01-remotes/verify.ps1 +++ /dev/null @@ -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