feat: split out git blame

This commit is contained in:
Bjarke Sporring
2026-01-07 21:12:31 +01:00
parent 30b878fc67
commit 6b0e84934a
7 changed files with 633 additions and 92 deletions

View File

@@ -8,7 +8,6 @@ In this module, you will:
- Use `git show` to view specific commit details
- Use `git diff` to compare changes between commits
- Use `git diff --staged` to view changes ready to be committed
- Use `git blame` to find who made specific changes
- Understand commit hashes and references
- Discover how `git diff` reveals changes not visible in current files
@@ -31,7 +30,6 @@ You'll explore an existing Git repository that contains multiple commits. Your g
- Examining changes between specific commits
- Understanding staged changes
- **Finding a secret code hidden in the commit history!** (Only discoverable by using `git diff`)
- **Tracking down who made a suspicious code change** (Using `git blame`)
The setup script will create an `answers.md` file in the challenge directory with questions for you to answer. Fill in your answers directly in that file.
@@ -45,8 +43,7 @@ The setup script will create an `answers.md` file in the challenge directory wit
6. Try different log formats: `git log --stat`, `git log --graph`
7. View specific commits: `git show <commit-hash>`
8. Compare specific commits: `git diff <commit1> <commit2> <file>`
9. Use `git blame` to find who wrote specific lines: `git blame -e <file>`
10. Fill in your answers in `answers.md`
9. Fill in your answers in `answers.md`
> **Important Notes:**
> - You can use any Git commands you like to explore the repository
@@ -207,19 +204,6 @@ git diff HEAD # Show all changes (staged + unstaged) vs last c
- `git diff HEAD` - See all your changes since the last commit
- `git diff <commit1> <commit2>` - Compare any two points in history
### Finding Who Changed What with git blame
```bash
git blame <file> # Show who last modified each line
git blame -e <file> # Show with email addresses
git blame -L 10,20 <file> # Blame specific line range (lines 10-20)
```
**When to use `git blame`:**
- Find who wrote a specific line of code
- Identify when a bug was introduced
- Understand the context/reason for a change by finding the author
## Verification
Once you've filled in your answers in `answers.md`, verify your solution:

View File

@@ -200,39 +200,6 @@ Set-Content -Path "app.py" -Value $appContent
git add .
git commit -m "Add user profile feature" | Out-Null
# Commit 6: Add a suspicious change (for git blame challenge)
Write-Host "Adding configuration change..." -ForegroundColor Green
# Temporarily change git user for this commit
git config user.name "Suspicious Developer"
git config user.email "guilty@email.com"
$appContent = @"
# app.py - Main application file
from auth import login, logout
from database import connect, disconnect
from profile import get_profile
def main():
print("Welcome to My App!")
connect()
# Application initialization code here
if login("admin", "admin123"): # TODO: Change default credentials!
profile = get_profile("admin")
print(f"User profile: {profile}")
pass
if __name__ == "__main__":
main()
"@
Set-Content -Path "app.py" -Value $appContent
git add .
git commit -m "Update default login credentials" | Out-Null
# Reset git config back to original
git config user.name "Workshop Student"
git config user.email "student@example.com"
# Create a staged change scenario
Write-Host "Creating staged changes for exploration..." -ForegroundColor Green
$configContent = @"
@@ -342,29 +309,6 @@ git diff <commit3-hash> <commit4-hash> database.py
---
## Question 6: Who changed the login credentials to hardcoded values? 🔍
**The Challenge:**
Someone on the team added hardcoded login credentials to `app.py` (username: "admin", password: "admin123"). This is a security issue! Use `git blame` to find out who made this change.
**Your task:** Find the email address of the person who wrote the line containing `login("admin", "admin123")`.
**Suggested commands:**
``````bash
# View who changed each line in app.py
git blame app.py
# For a more readable format
git blame -e app.py # Shows email addresses
# Look for the line with login("admin", "admin123")
# The format is: commit_hash (Author Name <email> date time line_number) line_content
``````
**Your Answer (provide the email address):**
<!-- Write your answer here -->
---
## Quick Reference - Useful Commands
@@ -394,14 +338,6 @@ git diff # Show unstaged changes
git diff HEAD # Show all changes since last commit
``````
**Finding Who Changed What:**
``````bash
git blame <file> # Show who last modified each line
git blame -e <file> # Show with email addresses
git blame -L 10,20 <file> # Blame specific line range
git blame <file> | grep "pattern" # Find who changed lines matching pattern
``````
**Repository Status:**
``````bash
git status # Show working tree status

View File

@@ -41,8 +41,8 @@ if (-not (Test-Path "answers.md")) {
$answers = Get-Content "answers.md" -Raw
$answersLower = $answers.ToLower()
# Check 1: Contains "6" or "six" for commit count
if ($answersLower -match "6|six") {
# Check 1: Contains "5" or "five" for commit count
if ($answersLower -match "5|five") {
Write-Host "[PASS] Correct commit count found" -ForegroundColor Green
} else {
Write-Host "[FAIL] Commit count not found or incorrect" -ForegroundColor Red
@@ -93,14 +93,6 @@ if (-not (Test-Path "answers.md")) {
$allChecksPassed = $false
}
# Check 6: Contains "guilty@email.com" for git blame challenge
if ($answersLower -match "guilty@email\.com") {
Write-Host "[PASS] Correct email address found using git blame!" -ForegroundColor Green
} else {
Write-Host "[FAIL] Guilty developer's email not found" -ForegroundColor Red
Write-Host "[HINT] Use 'git blame -e app.py' to see who changed each line with email addresses" -ForegroundColor Yellow
$allChecksPassed = $false
}
}
Set-Location ..
@@ -118,7 +110,6 @@ if ($allChecksPassed) {
Write-Host " - See which files changed in commits" -ForegroundColor White
Write-Host " - Check staged changes with git diff --staged" -ForegroundColor White
Write-Host " - Compare changes between specific commits with git diff" -ForegroundColor White
Write-Host " - Track down who made changes with git blame" -ForegroundColor White
Write-Host "`nReady for the next module!" -ForegroundColor Green
Write-Host ""
} else {

View File

@@ -0,0 +1,169 @@
# Module 05: Git Blame - Code Archaeology
## Learning Objectives
In this module, you will:
- Use `git blame` to find who made specific changes
- Understand blame output format and information
- Track down problematic code changes
- Learn when and why to use `git blame`
- Investigate code history to understand context
## Challenge
### Setup
Run the setup script to create your challenge environment:
```powershell
.\setup.ps1
```
This will create a `challenge/` directory with a Git repository that has a security issue - someone committed hardcoded credentials!
### Your Task
Your team has discovered a security vulnerability: hardcoded credentials were added to the codebase. Your job is to investigate who made this change and document your findings.
The setup script will create an `investigation.md` file in the challenge directory with questions for you to answer. Use `git blame` and other Git commands to track down the responsible developer.
**Scenario:**
- Someone added hardcoded login credentials (`username: "admin"`, `password: "admin123"`) to `app.py`
- This is a critical security issue
- You need to identify who made this change so the team can discuss it with them
**Suggested Approach:**
1. Navigate to the challenge directory: `cd challenge`
2. Open `investigation.md` to see the questions
3. Examine `app.py` to find the suspicious line
4. Use `git blame` to find who wrote that line
5. Use `git blame -e` to see email addresses
6. Use `git show` to see the full commit details
7. Document your findings in `investigation.md`
> **Important Notes:**
> - `git blame` shows who last modified each line
> - Each line shows: commit hash, author, date, line number, and content
> - Use `-e` flag to show email addresses
> - Use `-L` to focus on specific line ranges
## Key Concepts
- **Git Blame**: Shows the revision and author who last modified each line of a file
- **Code Archaeology**: Using Git history to understand when and why code changed
- **Author Attribution**: Identifying who wrote specific code for context, not punishment
- **Commit Context**: Understanding the full story behind a change
## Understanding Git Blame Output
When you run `git blame app.py`, you'll see output like this:
```
a1b2c3d4 (John Doe 2024-01-15 10:30:45 +0000 1) # app.py - Main application
a1b2c3d4 (John Doe 2024-01-15 10:30:45 +0000 2)
e5f6g7h8 (Jane Smith 2024-01-16 14:20:10 +0000 3) from auth import login
e5f6g7h8 (Jane Smith 2024-01-16 14:20:10 +0000 4)
i9j0k1l2 (Bob Wilson 2024-01-17 09:15:30 +0000 5) def main():
i9j0k1l2 (Bob Wilson 2024-01-17 09:15:30 +0000 6) login("admin", "admin123")
```
### Breaking It Down
Each line shows:
1. **Commit Hash** (`a1b2c3d4`) - The commit that last changed this line
2. **Author Name** (`John Doe`) - Who made the change
3. **Date/Time** (`2024-01-15 10:30:45 +0000`) - When it was changed
4. **Line Number** (`1`) - The line number in the current file
5. **Line Content** (`# app.py - Main application`) - The actual code
### Useful Git Blame Options
```bash
git blame <file> # Basic blame output
git blame -e <file> # Show email addresses instead of names
git blame -L 10,20 <file> # Only show lines 10-20
git blame -L 10,+5 <file> # Show 5 lines starting from line 10
git blame -w <file> # Ignore whitespace changes
git blame <commit> <file> # Blame as of specific commit
```
### Following Up After Blame
Once you find the commit hash:
```bash
git show <commit-hash> # See the full commit details
git log -p <commit-hash> # See commit with diff
git show <commit-hash> --stat # See which files were changed
```
## When to Use Git Blame
**Good reasons to use `git blame`:**
- 🔍 Understanding why code was written a certain way
- 📚 Finding context for a piece of code
- 🐛 Identifying when a bug was introduced
- 💡 Discovering the thought process behind a decision
- 👥 Finding who to ask about specific code
**Not for blaming:**
- ❌ Finding someone to blame for mistakes
- ❌ Tracking "productivity" or code ownership
- ❌ Punishing developers for old code
**Remember:** Code archaeology is about understanding, not blaming!
## Useful Commands
### Investigation Commands
```bash
# Find who changed each line
git blame <file>
git blame -e <file> # With email addresses
# Focus on specific lines
git blame -L 10,20 <file> # Lines 10-20
git blame -L :function_name <file> # Specific function (Git 2.20+)
# See historical blame
git blame <commit>^ <file> # Blame before a specific commit
# Combine with grep
git blame <file> | grep "pattern" # Find who wrote lines matching pattern
```
### Context Commands
```bash
# See full commit details
git show <commit-hash>
git log -1 <commit-hash> # Just the commit message
# See all commits by author
git log --author="name"
# See what else changed in that commit
git show <commit-hash> --stat
```
## Verification
Once you've completed your investigation in `investigation.md`, verify your solution:
```powershell
.\verify.ps1
```
The verification script will check that you've identified the correct developer.
## Need to Start Over?
If you want to reset the challenge and start fresh:
```powershell
.\reset.ps1
```
This will remove the challenge directory and run the setup script again, giving you a clean slate.

View File

@@ -0,0 +1,24 @@
#!/usr/bin/env pwsh
<#
.SYNOPSIS
Resets the Module 05 challenge environment.
.DESCRIPTION
This script removes the challenge directory and re-runs the setup script
to give you a fresh start.
#>
Write-Host "`n=== Resetting Module 05 Challenge ===" -ForegroundColor Cyan
# Remove challenge directory if it exists
if (Test-Path "challenge") {
Write-Host "Removing existing challenge directory..." -ForegroundColor Yellow
Remove-Item -Recurse -Force "challenge"
Write-Host "Challenge directory removed." -ForegroundColor Green
} else {
Write-Host "No challenge directory found to remove." -ForegroundColor Yellow
}
# Run setup script
Write-Host "`nRunning setup script..." -ForegroundColor Cyan
& "./setup.ps1"

View File

@@ -0,0 +1,323 @@
#!/usr/bin/env pwsh
<#
.SYNOPSIS
Sets up the Module 05 challenge environment for git blame investigation.
.DESCRIPTION
This script creates a challenge directory with a Git repository that
contains a security vulnerability (hardcoded credentials) for students
to investigate using git blame.
#>
Write-Host "`n=== Setting up Module 05 Challenge ===" -ForegroundColor Cyan
# Remove existing challenge directory if it exists
if (Test-Path "challenge") {
Write-Host "Removing existing challenge directory..." -ForegroundColor Yellow
Remove-Item -Recurse -Force "challenge"
}
# Create fresh challenge directory
Write-Host "Creating challenge directory..." -ForegroundColor Green
New-Item -ItemType Directory -Path "challenge" | Out-Null
Set-Location "challenge"
# Initialize Git repository
Write-Host "Initializing Git repository..." -ForegroundColor Green
git init | Out-Null
# Commit 1: Initial project structure (by Alice)
Write-Host "Creating initial project structure..." -ForegroundColor Green
git config user.name "Alice Johnson"
git config user.email "alice@example.com"
$appContent = @"
# app.py - Main application file
def main():
print("Welcome to My App!")
# Application initialization code here
pass
if __name__ == "__main__":
main()
"@
Set-Content -Path "app.py" -Value $appContent
git add .
git commit -m "Initial project structure" | Out-Null
# Commit 2: Add authentication module (by Bob)
Write-Host "Adding authentication module..." -ForegroundColor Green
git config user.name "Bob Chen"
git config user.email "bob@example.com"
$authContent = @"
# auth.py - Authentication module
def login(username, password):
# Authenticate user
print(f"Logging in user: {username}")
return True
def logout(username):
# Log out user
print(f"Logging out user: {username}")
return True
"@
Set-Content -Path "auth.py" -Value $authContent
$appContent = @"
# app.py - Main application file
from auth import login, logout
def main():
print("Welcome to My App!")
# Application initialization code here
pass
if __name__ == "__main__":
main()
"@
Set-Content -Path "app.py" -Value $appContent
git add .
git commit -m "Add authentication module" | Out-Null
# Commit 3: Add database connection (by Carol)
Write-Host "Adding database connection..." -ForegroundColor Green
git config user.name "Carol Martinez"
git config user.email "carol@example.com"
$databaseContent = @"
# database.py - Database connection module
def connect():
# Connect to database
print("Connecting to database...")
return True
def disconnect():
# Disconnect from database
print("Disconnecting from database...")
return True
"@
Set-Content -Path "database.py" -Value $databaseContent
$appContent = @"
# app.py - Main application file
from auth import login, logout
from database import connect, disconnect
def main():
print("Welcome to My App!")
connect()
# Application initialization code here
pass
if __name__ == "__main__":
main()
"@
Set-Content -Path "app.py" -Value $appContent
git add .
git commit -m "Add database connection" | Out-Null
# Commit 4: Add hardcoded credentials (THE SECURITY ISSUE - by Suspicious Developer)
Write-Host "Adding suspicious change..." -ForegroundColor Green
git config user.name "Suspicious Developer"
git config user.email "guilty@email.com"
$appContent = @"
# app.py - Main application file
from auth import login, logout
from database import connect, disconnect
def main():
print("Welcome to My App!")
connect()
# Quick fix for testing - TODO: Remove before production!
if login("admin", "admin123"):
print("Admin logged in successfully")
pass
if __name__ == "__main__":
main()
"@
Set-Content -Path "app.py" -Value $appContent
git add .
git commit -m "Add quick test login for debugging" | Out-Null
# Commit 5: Add logging (by David - innocent commit after the security issue)
Write-Host "Adding logging module..." -ForegroundColor Green
git config user.name "David Lee"
git config user.email "david@example.com"
$loggingContent = @"
# logging_config.py - Logging configuration
import logging
def setup_logging():
logging.basicConfig(
level=logging.INFO,
format='%(asctime)s - %(name)s - %(levelname)s - %(message)s'
)
return logging.getLogger(__name__)
"@
Set-Content -Path "logging_config.py" -Value $loggingContent
git add .
git commit -m "Add logging configuration" | Out-Null
# Reset git config
git config user.name "Workshop Student"
git config user.email "student@example.com"
# Create investigation.md template
Write-Host "Creating investigation template..." -ForegroundColor Green
$investigationTemplate = @"
# Security Investigation Report
## Incident Overview
A security vulnerability has been discovered in the codebase: hardcoded credentials in `app.py`.
**Your task:** Use git blame and related Git commands to investigate this security issue and document your findings.
---
## Question 1: What line number contains the hardcoded password?
Look at `app.py` and find the line with `"admin123"`.
**Your Answer:**
<!-- Write the line number here -->
---
## Question 2: Who added the hardcoded credentials?
Use `git blame` to find the email address of the developer who wrote the line with the hardcoded credentials.
**Suggested commands:**
``````bash
# View blame with email addresses
git blame -e app.py
# Or focus on specific lines (if you know the line range)
git blame -L 8,10 app.py
# Look for the line containing login("admin", "admin123")
``````
**Your Answer (provide the email address):**
<!-- Write the email address here -->
---
## Question 3: What was the commit message for the change that introduced the hardcoded credentials?
Once you've found the commit hash from git blame, use `git show` or `git log` to see the full commit message.
**Suggested commands:**
``````bash
# After finding the commit hash from git blame
git show <commit-hash>
git log -1 <commit-hash>
``````
**Your Answer:**
<!-- Write the commit message here -->
---
## Question 4: How many files were modified in the commit that added the hardcoded credentials?
Use `git show` with the `--stat` flag to see which files were changed.
**Suggested commands:**
``````bash
git show <commit-hash> --stat
git show <commit-hash> --name-only
``````
**Your Answer:**
<!-- Write the number or list the files here -->
---
## Question 5: When was this security vulnerability introduced?
Use the timestamp from git blame to determine when the vulnerable code was committed.
**Your Answer (date and time):**
<!-- Write the date/time here -->
---
## Recommendations
Based on your investigation, what actions should the team take?
**Your Recommendations:**
<!-- Write your recommendations here, for example:
- Remove hardcoded credentials
- Implement proper environment variables
- Add pre-commit hooks to prevent secrets
- Review with the developer who made the change
-->
---
## Quick Reference - Investigation Commands
**Finding Who Changed What:**
``````bash
git blame <file> # Show who last modified each line
git blame -e <file> # Show with email addresses
git blame -L 10,20 <file> # Blame specific line range
``````
**Getting Commit Details:**
``````bash
git show <commit-hash> # See full commit details
git show <commit-hash> --stat # See files changed
git log -1 <commit-hash> # See commit message only
git log -p <commit-hash> # See commit with diff
``````
**Searching History:**
``````bash
git log --all --grep="keyword" # Search commit messages
git log --author="name" # See commits by author
git log --since="2 weeks ago" # Recent commits
``````
---
When you're done with your investigation, run ``..\verify.ps1`` to check your answers!
"@
Set-Content -Path "investigation.md" -Value $investigationTemplate
# Return to module directory
Set-Location ..
Write-Host "`n=== Setup Complete! ===" -ForegroundColor Green
Write-Host "`nYour investigation environment is ready in the 'challenge/' directory." -ForegroundColor Cyan
Write-Host "`nScenario: Someone committed hardcoded credentials to app.py!" -ForegroundColor Yellow
Write-Host "`nNext steps:" -ForegroundColor Cyan
Write-Host " 1. cd challenge" -ForegroundColor White
Write-Host " 2. Open 'investigation.md' to see the investigation questions" -ForegroundColor White
Write-Host " 3. Use 'git blame -e app.py' to start your investigation" -ForegroundColor White
Write-Host " 4. Fill in your findings in 'investigation.md'" -ForegroundColor White
Write-Host " 5. Run '..\verify.ps1' to check your investigation" -ForegroundColor White
Write-Host ""

View File

@@ -0,0 +1,114 @@
#!/usr/bin/env pwsh
<#
.SYNOPSIS
Verifies the Module 05 challenge solution.
.DESCRIPTION
This script checks that:
- The challenge directory exists
- A Git repository exists
- investigation.md exists with correct findings about the security issue
#>
Write-Host "`n=== Verifying Module 05 Solution ===" -ForegroundColor Cyan
$allChecksPassed = $true
# Check if challenge directory exists
if (-not (Test-Path "challenge")) {
Write-Host "[FAIL] Challenge directory not found. Did you run setup.ps1?" -ForegroundColor Red
exit 1
}
Set-Location "challenge"
# Check if git repository exists
if (-not (Test-Path ".git")) {
Write-Host "[FAIL] Not a git repository. Did you run setup.ps1?" -ForegroundColor Red
Set-Location ..
exit 1
}
# Check if investigation.md exists
if (-not (Test-Path "investigation.md")) {
Write-Host "[FAIL] investigation.md not found. Did you run setup.ps1?" -ForegroundColor Red
Write-Host "[HINT] The setup script should have created investigation.md for you" -ForegroundColor Yellow
$allChecksPassed = $false
} else {
Write-Host "[PASS] investigation.md exists" -ForegroundColor Green
# Read the investigation file
$investigation = Get-Content "investigation.md" -Raw
$investigationLower = $investigation.ToLower()
# Check 1: Line number (line 8 contains the hardcoded password)
if ($investigationLower -match "8") {
Write-Host "[PASS] Correct line number identified" -ForegroundColor Green
} else {
Write-Host "[FAIL] Line number not found or incorrect" -ForegroundColor Red
Write-Host "[HINT] Look at app.py to find which line contains 'admin123'" -ForegroundColor Yellow
$allChecksPassed = $false
}
# Check 2: Email address (guilty@email.com)
if ($investigationLower -match "guilty@email\.com") {
Write-Host "[PASS] Correct email address found using git blame!" -ForegroundColor Green
} else {
Write-Host "[FAIL] Developer's email address not found" -ForegroundColor Red
Write-Host "[HINT] Use 'git blame -e app.py' to see who changed each line with email addresses" -ForegroundColor Yellow
$allChecksPassed = $false
}
# Check 3: Commit message (contains "test" or "debug" or "quick")
if ($investigationLower -match "test|debug|quick") {
Write-Host "[PASS] Commit message identified" -ForegroundColor Green
} else {
Write-Host "[FAIL] Commit message not found" -ForegroundColor Red
Write-Host "[HINT] Use 'git show <commit-hash>' to see the commit message" -ForegroundColor Yellow
$allChecksPassed = $false
}
# Check 4: Number of files (1 file - only app.py)
if ($investigationLower -match "1|one|app\.py") {
Write-Host "[PASS] Number of files modified identified" -ForegroundColor Green
} else {
Write-Host "[FAIL] Number of files modified not found" -ForegroundColor Red
Write-Host "[HINT] Use 'git show <commit-hash> --stat' to see which files were changed" -ForegroundColor Yellow
$allChecksPassed = $false
}
# Check 5: Some mention of timestamp/date (flexible check)
# We're just checking they attempted to answer this
if ($investigationLower -match "202|date|time|\d{4}-\d{2}-\d{2}") {
Write-Host "[PASS] Timestamp/date documented" -ForegroundColor Green
} else {
Write-Host "[FAIL] Timestamp/date not documented" -ForegroundColor Red
Write-Host "[HINT] The git blame output shows the date and time of each change" -ForegroundColor Yellow
$allChecksPassed = $false
}
}
Set-Location ..
# Final summary
if ($allChecksPassed) {
Write-Host "`n" -NoNewline
Write-Host "=====================================" -ForegroundColor Green
Write-Host " INVESTIGATION COMPLETE!" -ForegroundColor Green
Write-Host "=====================================" -ForegroundColor Green
Write-Host "`nExcellent detective work! You've successfully used git blame to track down the security issue." -ForegroundColor Cyan
Write-Host "`nYou now know how to:" -ForegroundColor Cyan
Write-Host " - Use git blame to find who modified each line" -ForegroundColor White
Write-Host " - Read and interpret git blame output" -ForegroundColor White
Write-Host " - Use git blame with -e flag to show email addresses" -ForegroundColor White
Write-Host " - Find commit details after identifying changes with blame" -ForegroundColor White
Write-Host " - Conduct code archaeology to understand code history" -ForegroundColor White
Write-Host "`nRemember: git blame is for understanding, not blaming!" -ForegroundColor Yellow
Write-Host "`nReady for the next module!" -ForegroundColor Green
Write-Host ""
} else {
Write-Host "`n[SUMMARY] Some checks failed. Review the hints above and try again." -ForegroundColor Red
Write-Host "[INFO] You can run this verification script as many times as needed." -ForegroundColor Yellow
Write-Host ""
exit 1
}