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:
- Simple code: Implementing
print("B", end=" ")is easy. The hard part is Git, not Python. - Clear success: You can visually verify your letters appear in the output.
- Guaranteed conflicts: You'll deliberately create merge conflicts to practice resolving them.
- Team integration: Your work depends on others, just like real software projects.
- 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:
git config --global user.name
git config --global user.email
If these are empty, set them now:
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)
- Log in to https://git.frod.dk/multiplayer
- Go to Settings → Applications → Tokens
- Generate a new token with
repopermissions - Save the token securely (you'll use it as your password when pushing/pulling)
Method B: SSH Key
- Generate SSH key (if you don't have one):
ssh-keygen -t ed25519 -C "your.email@example.com" - Copy your public key:
cat ~/.ssh/id_ed25519.pub - Add it to Gitea: Settings → SSH Keys → Add Key
- Test connection:
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()inletters.py - Pair 2: Functions
print_e(),print_f(),print_g()inletters.py - Pair 9: Functions
print_z()inletters.py,print_0(),print_1()innumbers.py - Pair 12: Functions
print_8(),print_9()innumbers.py
Step 3: Clone the Repository
Using HTTPS (recommended):
git clone https://git.frod.dk/multiplayer/great-print-project.git
cd great-print-project
Using SSH:
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:
# 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:
# 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:
git switch -c pair-1-bcd
Expected output:
Switched to a new branch 'pair-1-bcd'
Verify you're on the right branch:
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:
def print_b():
# TODO: Pair 1 - implement this function
pass
Change it to:
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
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
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:
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:
# 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:
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:
def print_c():
"""Print letter C"""
print("C", end=" ")
Test, commit, and push:
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:
git pull origin pair-1-bcd
Verify you have both functions:
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:
- Implement the function
- Test with
python main.py - Commit and push
- Other partner pulls
When you're done, all three assigned functions should be complete!
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:
- Partner A and Partner B will BOTH edit the same function
- Partner A pushes first (succeeds)
- Partner B tries to push (gets rejected!)
- Partner B pulls (sees conflict markers)
- You resolve the conflict together
- 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:
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():
def print_d():
"""Print letter D"""
print("D", end=" ") # Partner A's version
Commit and push IMMEDIATELY:
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:
def print_d():
"""Print letter D"""
print("D ", end="") # Partner B's version (extra space, different quote style)
Commit (but don't push yet):
git add letters.py
git commit -m "Partner B: Add print_d()"
Step 4: Partner B - Try to Push (This Will Fail!)
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
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
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 <file>..." 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
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():
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
<<<<<<< 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:
<<<<<<< HEADto=======: Your current changes (what you committed locally)=======to>>>>>>>: Their changes (what Partner A pushed to the server)- 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
def print_d():
"""Print letter D"""
print("D", end=" ")
Option 2: Keep Partner B's version
def print_d():
"""Print letter D"""
print("D ", end="")
Option 3: Agree on a third option
def print_d():
"""Print letter D"""
print("D", end=" ") # Agreed version after discussion
Edit the file to:
- Remove ALL conflict markers (
<<<<<<<,=======,>>>>>>>) - Keep the agreed-upon code
- Make sure the syntax is valid Python
Example resolved version:
def print_d():
"""Print letter D"""
print("D", end=" ") # Resolved: using Partner A's version
Save the file!
Step 9: Test the Resolution
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:
git add letters.py
This stages the resolved file.
Now commit the resolution:
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
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:
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:
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
-
Open browser: Navigate to https://git.frod.dk/multiplayer/great-print-project
-
Go to Pull Requests tab: Click "Pull Requests" in the top navigation
-
Click "New Pull Request"
-
Set the branches:
- Base branch:
main(where your code will be merged) - Compare branch:
pair-1-bcd(your feature branch)
- Base branch:
-
Fill in the pull request form:
Title: Clear, concise description
Implement functions for Pair 1 (B, C, D)
Description: Use this template:
## 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.
- 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:
- Go to "Pull Requests" tab
- Look for PRs from other pairs
- Click on one that interests you
Review the code:
- Click "Files Changed" tab
- Look at the code they wrote
- 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?
- Do the functions follow the pattern (
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:
- Go to "Pull Requests" → Your PR
- Read any comments left by reviewers
- 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)
- Click "Merge Pull Request"
- Confirm the merge
- Optionally delete your branch (server will prompt)
After merge:
Your code is now in main! Run this to see it:
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
# 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
# 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.
# 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:
- Open the file
- Find conflict markers
- Discuss with partner which version to keep
- Remove markers
- Test the code
git addthe resolved filegit committhe mergegit pushthe resolution
Viewing What Changed
Before merging, see what's new in main:
# 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:
git clone <url> # 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:
git switch -c <branch-name> # Create and switch to new branch
git switch <branch-name> # Switch to existing branch
git branch # List local branches (* = current)
git branch -a # List all branches (local + remote)
git branch -d <branch-name> # Delete branch (safe - prevents data loss)
Making Changes:
git status # See current state and changed files
git add <file> # 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:
git pull origin <branch> # Fetch and merge from remote branch
git push origin <branch> # Push commits to remote branch
git push -u origin <branch> # Push and set upstream tracking
git fetch origin # Download changes without merging
git remote -v # Show configured remotes
Conflict Resolution:
git status # See which files have conflicts
# Edit files to remove <<<<<<, =======, >>>>>>> markers
git add <resolved-file> # 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:
git merge <branch-name> # Merge branch into current branch
git merge main # Common: merge main into feature branch
git log --oneline --graph --all # Visualize branch history
Viewing Changes:
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:
# 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:
- Don't panic - this is normal!
- Run
git statusto see which files have conflicts - Open the conflicted file(s) in your editor
- Find the conflict markers:
<<<<<<<,=======,>>>>>>> - Talk with your partner - decide which version to keep
- Remove ALL markers and keep the agreed code
- Test:
python main.py(make sure it works!) - Stage:
git add letters.py - Commit:
git commit -m "Resolve conflict in letters.py" - Push:
git push origin pair-1-bcd
"My partner pushed, how do I get their changes?"
Solution:
# 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:
# 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:
- Partner who tries to push second gets rejection
- They pull (sees conflict)
- Both partners look at the conflict markers together
- Decide which version to keep (or create new version)
- 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):
# 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:
git diff # See unstaged changes
git diff --staged # See staged changes (after git add)
After committing:
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:
# 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:
# 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:
# 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):
- Make sure you're using your access token as the password, not your account password
- Check token has
repopermissions in Gitea settings - Try cloning with token in URL (not recommended for security, but useful for debugging):
git clone https://username:TOKEN@git.frod.dk/multiplayer/great-print-project.git
Solution (SSH):
- Verify your SSH key is added to Gitea: Settings → SSH Keys
- Test SSH connection:
ssh -T git@git.frod.dk - 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:
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:
# Find the commit before deletion
git log --oneline
# Example: abc1234 was the last good commit
git reset --hard abc1234
If already pushed:
# 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:
# 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:
- Don't panic - your Git skills are still valid!
- Check with facilitator about your correct assignment
- 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
- 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.pyon themainbranch, 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
mainafter 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!