refactor: move modules into levels

This commit is contained in:
Bjarke Sporring
2026-01-07 17:59:02 +01:00
parent d7c146975d
commit cf073d569e
52 changed files with 0 additions and 0 deletions

View File

@@ -0,0 +1,252 @@
# Module 12: Working with Remotes
## Learning Objectives
By the end of this module, you will:
- Understand what remote repositories are
- Clone a repository from a remote source
- Push local commits to a remote repository
- Pull changes from a remote repository
- Understand the difference between fetch and pull
- Manage remote branches
- Work with remote tracking branches
## Challenge Description
You're joining a team project that's already hosted on a remote server. You need to clone the repository, make changes, and synchronize your work with the remote.
Your task is to:
1. Clone the remote repository
2. Create a new branch for your feature
3. Make changes and commit them locally
4. Push your branch to the remote
5. Fetch updates that were made by teammates
6. Merge remote changes into your branch
## Key Concepts
### What is a Remote Repository?
A remote repository is a version of your project hosted on a server (like GitHub, GitLab, or Bitbucket) or another location. It allows teams to collaborate by sharing code.
### Common Remote Operations
**Clone**: Create a local copy of a remote repository
```
Remote Server Your Computer
[repo] -----------------> [local copy of repo]
```
**Push**: Send your local commits to the remote
```
Your Computer Remote Server
[commits] -----------------> [repo updated]
```
**Pull**: Get changes from remote and merge into your branch
```
Remote Server Your Computer
[commits] ---------------> [branch updated]
```
**Fetch**: Get changes from remote but don't merge yet
```
Remote Server Your Computer
[commits] ---------------> [stored locally, not merged]
```
### Origin vs Upstream
- **origin**: The default name for the remote you cloned from
- **upstream**: Often used for the original repository when you've forked it
- You can have multiple remotes with different names
### Remote Tracking Branches
When you clone a repository, Git creates remote tracking branches:
- `origin/main` - tracks the main branch on origin
- `origin/feature` - tracks the feature branch on origin
These are read-only local copies that show the state of remote branches.
## Useful Commands
```bash
# Clone a repository
git clone <url>
git clone <url> <directory-name>
# View remotes
git remote
git remote -v # Show URLs
# Add a remote
git remote add <name> <url>
# Remove a remote
git remote remove <name>
# Rename a remote
git remote rename <old-name> <new-name>
# Push to remote
git push origin <branch-name>
git push -u origin <branch-name> # Set upstream tracking
# Pull from remote (fetch + merge)
git pull
git pull origin <branch-name>
# Fetch from remote (no merge)
git fetch
git fetch origin
# See remote branches
git branch -r
git branch -a # All branches (local and remote)
# Delete remote branch
git push origin --delete <branch-name>
# Update remote tracking information
git remote update
git remote prune origin # Remove stale remote tracking branches
```
## Verification
Run the verification script to check your solution:
```bash
.\verify.ps1
```
The verification will check that:
- You cloned the repository correctly
- Your feature branch exists and has commits
- Changes were pushed to the remote
- You fetched and merged remote updates
- Your branch is up to date
## Challenge Steps
1. Navigate to the challenge directory
2. You'll find a simulated "remote" repository
3. Clone it: `git clone remote-repo local-repo`
4. Navigate into your clone: `cd local-repo`
5. Create and switch to a feature branch: `git switch -c add-feature`
6. Make changes to the project (add a new feature to app.js)
7. Commit your changes
8. Push to remote: `git push -u origin add-feature`
9. Simulate teammate changes (run the provided update script)
10. Fetch updates: `git fetch origin`
11. View remote changes: `git log origin/main`
12. Merge remote main into your branch: `git merge origin/main`
13. Run verification
## Tips
- `git clone` automatically sets up the remote as "origin"
- `git push -u` sets up tracking so future pushes can just use `git push`
- Use `git fetch` to see what's changed before merging
- `git pull` = `git fetch` + `git merge`
- Always pull before pushing to avoid conflicts
- Use `git branch -a` to see all local and remote branches
- Remote branches are read-only; you work on local branches
- `origin/main` is a remote tracking branch, `main` is your local branch
## Push vs Pull vs Fetch
### Git Push
Uploads your local commits to the remote:
```bash
git push origin main
```
Use when: You have local commits ready to share with the team
### Git Pull
Downloads and merges remote changes:
```bash
git pull origin main
```
Use when: You want to update your branch with remote changes
Equivalent to: `git fetch origin` + `git merge origin/main`
### Git Fetch
Downloads remote changes without merging:
```bash
git fetch origin
```
Use when: You want to see what's changed before merging
Safer than pull because it doesn't automatically merge
## Common Remote Workflows
### Daily Work Flow
```bash
# Start of day: get latest changes
git switch main
git pull origin main
# Create feature branch
git switch -c my-feature
# Do work, make commits
git add .
git commit -m "Add feature"
# Before pushing, update with latest main
git switch main
git pull origin main
git switch my-feature
git merge main
# Push your feature
git push -u origin my-feature
```
### Collaboration Workflow
```bash
# Teammate pushed changes to main
git fetch origin
git log origin/main # Review changes
git merge origin/main # Merge into current branch
# Or use pull (fetch + merge in one step)
git pull origin main
```
### Syncing Fork (with upstream)
```bash
# Add original repo as upstream
git remote add upstream <original-repo-url>
# Get latest from upstream
git fetch upstream
git switch main
git merge upstream/main
# Push to your fork
git push origin main
```
## Handling Push Rejection
If push is rejected because remote has changes:
```bash
# Remote has commits you don't have
git push origin main
# Error: Updates were rejected
# Solution 1: Pull first (creates merge commit)
git pull origin main
git push origin main
# Solution 2: Pull with rebase (cleaner history)
git pull --rebase origin main
git push origin main
```
## What You'll Learn
Working with remotes is fundamental to team collaboration. Understanding the difference between local and remote branches, knowing when to push/pull/fetch, and managing synchronization are core skills for any developer. While this module uses a local "remote" for learning, the concepts apply directly to GitHub, GitLab, and other hosting services. Mastering remotes enables you to work effectively in distributed teams and contribute to open source projects.

View File

@@ -0,0 +1,22 @@
#!/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"

View File

@@ -0,0 +1,147 @@
#!/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

View File

@@ -0,0 +1,174 @@
#!/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