feat: add initital bisect module
This commit is contained in:
231
module-14-bisect/README.md
Normal file
231
module-14-bisect/README.md
Normal file
@@ -0,0 +1,231 @@
|
||||
# Module 14: Bisect - Finding Bugs with Binary Search
|
||||
|
||||
## Learning Objectives
|
||||
|
||||
By the end of this module, you will:
|
||||
- Understand what git bisect is and when to use it
|
||||
- Use binary search to find the commit that introduced a bug
|
||||
- Mark commits as good or bad during bisection
|
||||
- Automate bisect with test scripts
|
||||
- Understand the efficiency of binary search for debugging
|
||||
|
||||
## Challenge Description
|
||||
|
||||
A bug has appeared in your calculator application, but you don't know which commit introduced it. The project has many commits, and manually checking each one would take too long. You'll use `git bisect` to efficiently find the culprit commit using binary search.
|
||||
|
||||
Your task is to:
|
||||
1. Start a bisect session
|
||||
2. Mark the current commit as bad (bug exists)
|
||||
3. Mark an old commit as good (bug didn't exist)
|
||||
4. Test commits and mark them good or bad
|
||||
5. Let Git find the first bad commit
|
||||
6. Identify what change introduced the bug
|
||||
|
||||
## Key Concepts
|
||||
|
||||
### What is Git Bisect?
|
||||
|
||||
Git bisect uses binary search to find the commit that introduced a bug. Instead of checking every commit linearly, it cuts the search space in half with each test, making it extremely efficient.
|
||||
|
||||
### Binary Search Efficiency
|
||||
|
||||
**Linear Search (manual checking):**
|
||||
- 100 commits = up to 100 tests
|
||||
- 1000 commits = up to 1000 tests
|
||||
|
||||
**Binary Search (bisect):**
|
||||
- 100 commits = ~7 tests
|
||||
- 1000 commits = ~10 tests
|
||||
|
||||
Formula: log₂(n) tests needed for n commits
|
||||
|
||||
### How Bisect Works
|
||||
|
||||
```
|
||||
Commits: A---B---C---D---E---F---G---H
|
||||
✓ ✓ ✓ ? ? ? ? ✗
|
||||
|
||||
1. Start: Mark H (bad) and A (good)
|
||||
2. Git checks middle: E
|
||||
3. You test E: bad ✗
|
||||
|
||||
Commits: A---B---C---D---E
|
||||
✓ ✓ ✓ ? ✗
|
||||
|
||||
4. Git checks middle: C
|
||||
5. You test C: good ✓
|
||||
|
||||
Commits: C---D---E
|
||||
✓ ? ✗
|
||||
|
||||
6. Git checks: D
|
||||
7. You test D: bad ✗
|
||||
|
||||
Result: D is the first bad commit!
|
||||
```
|
||||
|
||||
### When to Use Bisect
|
||||
|
||||
Use bisect when:
|
||||
- You know a bug exists now but didn't exist in the past
|
||||
- You have many commits to check
|
||||
- You can reliably test for the bug
|
||||
- You want to find exactly when something broke
|
||||
|
||||
## Useful Commands
|
||||
|
||||
```bash
|
||||
# Start bisect session
|
||||
git bisect start
|
||||
|
||||
# Mark current commit as bad
|
||||
git bisect bad
|
||||
|
||||
# Mark a commit as good
|
||||
git bisect good <commit-hash>
|
||||
git bisect good HEAD~10
|
||||
|
||||
# After testing current commit
|
||||
git bisect good # This commit is fine
|
||||
git bisect bad # This commit has the bug
|
||||
|
||||
# Skip a commit (if you can't test it)
|
||||
git bisect skip
|
||||
|
||||
# End bisect session and return to original state
|
||||
git bisect reset
|
||||
|
||||
# Visualize bisect process
|
||||
git bisect visualize
|
||||
git bisect view
|
||||
|
||||
# Automate with a test script
|
||||
git bisect run <test-script>
|
||||
git bisect run npm test
|
||||
git bisect run ./test.sh
|
||||
|
||||
# Show bisect log
|
||||
git bisect log
|
||||
```
|
||||
|
||||
## Verification
|
||||
|
||||
Run the verification script to check your solution:
|
||||
|
||||
```bash
|
||||
.\verify.ps1
|
||||
```
|
||||
|
||||
The verification will check that:
|
||||
- You completed a bisect session
|
||||
- You identified the correct commit that introduced the bug
|
||||
- You understand which change caused the problem
|
||||
|
||||
## Challenge Steps
|
||||
|
||||
1. Navigate to the challenge directory
|
||||
2. View the bug: run the calculator and see it fails
|
||||
3. Start bisect: `git bisect start`
|
||||
4. Mark current as bad: `git bisect bad`
|
||||
5. Mark old commit as good: `git bisect good HEAD~10`
|
||||
6. Git will checkout a middle commit
|
||||
7. Test the current commit (run the test or check manually)
|
||||
8. Mark it: `git bisect good` or `git bisect bad`
|
||||
9. Repeat testing until Git identifies the bad commit
|
||||
10. Note the commit hash and message
|
||||
11. End bisect: `git bisect reset`
|
||||
12. Check the identified commit: `git show <bad-commit-hash>`
|
||||
13. Create a file named `bug-commit.txt` with the bad commit hash
|
||||
14. Run verification
|
||||
|
||||
## Tips
|
||||
|
||||
- Always start with a known good commit (far enough back)
|
||||
- Keep a clear way to test each commit (script or manual steps)
|
||||
- Use `git bisect log` to see your progress
|
||||
- `git bisect reset` returns you to your original state
|
||||
- You can bisect on any criteria, not just bugs (performance, features, etc.)
|
||||
- Automate with `git bisect run` for faster results
|
||||
- Each bisect step cuts remaining commits in half
|
||||
- Skip commits you can't build/test with `git bisect skip`
|
||||
|
||||
## Manual vs Automated Bisect
|
||||
|
||||
### Manual Bisect
|
||||
```bash
|
||||
git bisect start
|
||||
git bisect bad
|
||||
git bisect good HEAD~20
|
||||
|
||||
# For each commit Git checks out:
|
||||
npm test
|
||||
git bisect good # or bad
|
||||
|
||||
git bisect reset
|
||||
```
|
||||
|
||||
### Automated Bisect
|
||||
```bash
|
||||
git bisect start
|
||||
git bisect bad
|
||||
git bisect good HEAD~20
|
||||
git bisect run npm test
|
||||
# Git automatically tests each commit
|
||||
git bisect reset
|
||||
```
|
||||
|
||||
The test script should exit with:
|
||||
- 0 for good (test passes)
|
||||
- 1-127 (except 125) for bad (test fails)
|
||||
- 125 for skip (can't test this commit)
|
||||
|
||||
## Bisect Workflow Example
|
||||
|
||||
### Finding a Performance Regression
|
||||
```bash
|
||||
# App is slow now, was fast 50 commits ago
|
||||
git bisect start
|
||||
git bisect bad
|
||||
git bisect good HEAD~50
|
||||
|
||||
# Create test script
|
||||
echo '#!/bin/bash\ntime npm start | grep "Started in"' > test.sh
|
||||
chmod +x test.sh
|
||||
|
||||
git bisect run ./test.sh
|
||||
# Git finds the commit that made it slow
|
||||
```
|
||||
|
||||
### Finding When a Feature Broke
|
||||
```bash
|
||||
git bisect start
|
||||
git bisect bad
|
||||
git bisect good v1.0.0 # Last known good version
|
||||
|
||||
# For each commit
|
||||
npm test -- user-login.test.js
|
||||
git bisect good # or bad
|
||||
|
||||
# Found! Commit abc123 broke login
|
||||
git show abc123
|
||||
```
|
||||
|
||||
## Common Bisect Pitfalls
|
||||
|
||||
### Pitfall 1: Testing Incorrectly
|
||||
- Make sure your test is consistent
|
||||
- Automate when possible to avoid human error
|
||||
- Use the same test for every commit
|
||||
|
||||
### Pitfall 2: Wrong Good Commit
|
||||
- If the "good" commit actually has the bug, bisect will fail
|
||||
- Choose a commit you're confident was working
|
||||
|
||||
### Pitfall 3: Multiple Bugs
|
||||
- Bisect finds one commit at a time
|
||||
- If multiple bugs exist, they might confuse the search
|
||||
- Fix found bugs and bisect again for others
|
||||
|
||||
## What You'll Learn
|
||||
|
||||
Git bisect is a powerful debugging tool that turns a tedious manual search into an efficient automated process. By leveraging binary search, you can quickly pinpoint problematic commits even in repositories with thousands of commits. This is invaluable for debugging regressions, performance issues, or any situation where something that worked before is now broken. Mastering bisect makes you a more effective debugger and shows deep Git proficiency.
|
||||
22
module-14-bisect/reset.ps1
Normal file
22
module-14-bisect/reset.ps1
Normal file
@@ -0,0 +1,22 @@
|
||||
#!/usr/bin/env pwsh
|
||||
|
||||
<#
|
||||
.SYNOPSIS
|
||||
Resets the bisect 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"
|
||||
377
module-14-bisect/setup.ps1
Normal file
377
module-14-bisect/setup.ps1
Normal file
@@ -0,0 +1,377 @@
|
||||
#!/usr/bin/env pwsh
|
||||
|
||||
<#
|
||||
.SYNOPSIS
|
||||
Sets up the bisect challenge environment.
|
||||
|
||||
.DESCRIPTION
|
||||
Creates a Git repository with multiple commits where a bug is
|
||||
introduced in one of them. Students use bisect to find it.
|
||||
#>
|
||||
|
||||
# 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
|
||||
Write-Host "Creating challenge environment..." -ForegroundColor Cyan
|
||||
New-Item -ItemType Directory -Path "challenge" | Out-Null
|
||||
Set-Location "challenge"
|
||||
|
||||
# Initialize git repository
|
||||
git init | Out-Null
|
||||
git config user.name "Workshop User" | Out-Null
|
||||
git config user.email "user@workshop.local" | Out-Null
|
||||
|
||||
# Commit 1: Initial calculator
|
||||
$calc1 = @"
|
||||
class Calculator {
|
||||
add(a, b) {
|
||||
return a + b;
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = Calculator;
|
||||
"@
|
||||
Set-Content -Path "calculator.js" -Value $calc1
|
||||
git add calculator.js
|
||||
git commit -m "Initial calculator with add function" | Out-Null
|
||||
|
||||
# Commit 2: Add subtract
|
||||
$calc2 = @"
|
||||
class Calculator {
|
||||
add(a, b) {
|
||||
return a + b;
|
||||
}
|
||||
|
||||
subtract(a, b) {
|
||||
return a - b;
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = Calculator;
|
||||
"@
|
||||
Set-Content -Path "calculator.js" -Value $calc2
|
||||
git add calculator.js
|
||||
git commit -m "Add subtract function" | Out-Null
|
||||
|
||||
# Commit 3: Add multiply
|
||||
$calc3 = @"
|
||||
class Calculator {
|
||||
add(a, b) {
|
||||
return a + b;
|
||||
}
|
||||
|
||||
subtract(a, b) {
|
||||
return a - b;
|
||||
}
|
||||
|
||||
multiply(a, b) {
|
||||
return a * b;
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = Calculator;
|
||||
"@
|
||||
Set-Content -Path "calculator.js" -Value $calc3
|
||||
git add calculator.js
|
||||
git commit -m "Add multiply function" | Out-Null
|
||||
|
||||
# Commit 4: Add divide
|
||||
$calc4 = @"
|
||||
class Calculator {
|
||||
add(a, b) {
|
||||
return a + b;
|
||||
}
|
||||
|
||||
subtract(a, b) {
|
||||
return a - b;
|
||||
}
|
||||
|
||||
multiply(a, b) {
|
||||
return a * b;
|
||||
}
|
||||
|
||||
divide(a, b) {
|
||||
if (b === 0) throw new Error('Division by zero');
|
||||
return a / b;
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = Calculator;
|
||||
"@
|
||||
Set-Content -Path "calculator.js" -Value $calc4
|
||||
git add calculator.js
|
||||
git commit -m "Add divide function" | Out-Null
|
||||
|
||||
# Commit 5: Add modulo
|
||||
$calc5 = @"
|
||||
class Calculator {
|
||||
add(a, b) {
|
||||
return a + b;
|
||||
}
|
||||
|
||||
subtract(a, b) {
|
||||
return a - b;
|
||||
}
|
||||
|
||||
multiply(a, b) {
|
||||
return a * b;
|
||||
}
|
||||
|
||||
divide(a, b) {
|
||||
if (b === 0) throw new Error('Division by zero');
|
||||
return a / b;
|
||||
}
|
||||
|
||||
modulo(a, b) {
|
||||
return a % b;
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = Calculator;
|
||||
"@
|
||||
Set-Content -Path "calculator.js" -Value $calc5
|
||||
git add calculator.js
|
||||
git commit -m "Add modulo function" | Out-Null
|
||||
|
||||
# Commit 6: BUG - Introduce error in add function
|
||||
$calc6 = @"
|
||||
class Calculator {
|
||||
add(a, b) {
|
||||
return a - b; // BUG: Should be a + b
|
||||
}
|
||||
|
||||
subtract(a, b) {
|
||||
return a - b;
|
||||
}
|
||||
|
||||
multiply(a, b) {
|
||||
return a * b;
|
||||
}
|
||||
|
||||
divide(a, b) {
|
||||
if (b === 0) throw new Error('Division by zero');
|
||||
return a / b;
|
||||
}
|
||||
|
||||
modulo(a, b) {
|
||||
return a % b;
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = Calculator;
|
||||
"@
|
||||
Set-Content -Path "calculator.js" -Value $calc6
|
||||
git add calculator.js
|
||||
git commit -m "Refactor add function for clarity" | Out-Null
|
||||
|
||||
# Commit 7: Add power function (bug still exists)
|
||||
$calc7 = @"
|
||||
class Calculator {
|
||||
add(a, b) {
|
||||
return a - b; // BUG: Should be a + b
|
||||
}
|
||||
|
||||
subtract(a, b) {
|
||||
return a - b;
|
||||
}
|
||||
|
||||
multiply(a, b) {
|
||||
return a * b;
|
||||
}
|
||||
|
||||
divide(a, b) {
|
||||
if (b === 0) throw new Error('Division by zero');
|
||||
return a / b;
|
||||
}
|
||||
|
||||
modulo(a, b) {
|
||||
return a % b;
|
||||
}
|
||||
|
||||
power(a, b) {
|
||||
return Math.pow(a, b);
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = Calculator;
|
||||
"@
|
||||
Set-Content -Path "calculator.js" -Value $calc7
|
||||
git add calculator.js
|
||||
git commit -m "Add power function" | Out-Null
|
||||
|
||||
# Commit 8: Add square root
|
||||
$calc8 = @"
|
||||
class Calculator {
|
||||
add(a, b) {
|
||||
return a - b; // BUG: Should be a + b
|
||||
}
|
||||
|
||||
subtract(a, b) {
|
||||
return a - b;
|
||||
}
|
||||
|
||||
multiply(a, b) {
|
||||
return a * b;
|
||||
}
|
||||
|
||||
divide(a, b) {
|
||||
if (b === 0) throw new Error('Division by zero');
|
||||
return a / b;
|
||||
}
|
||||
|
||||
modulo(a, b) {
|
||||
return a % b;
|
||||
}
|
||||
|
||||
power(a, b) {
|
||||
return Math.pow(a, b);
|
||||
}
|
||||
|
||||
sqrt(a) {
|
||||
return Math.sqrt(a);
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = Calculator;
|
||||
"@
|
||||
Set-Content -Path "calculator.js" -Value $calc8
|
||||
git add calculator.js
|
||||
git commit -m "Add square root function" | Out-Null
|
||||
|
||||
# Commit 9: Add absolute value
|
||||
$calc9 = @"
|
||||
class Calculator {
|
||||
add(a, b) {
|
||||
return a - b; // BUG: Should be a + b
|
||||
}
|
||||
|
||||
subtract(a, b) {
|
||||
return a - b;
|
||||
}
|
||||
|
||||
multiply(a, b) {
|
||||
return a * b;
|
||||
}
|
||||
|
||||
divide(a, b) {
|
||||
if (b === 0) throw new Error('Division by zero');
|
||||
return a / b;
|
||||
}
|
||||
|
||||
modulo(a, b) {
|
||||
return a % b;
|
||||
}
|
||||
|
||||
power(a, b) {
|
||||
return Math.pow(a, b);
|
||||
}
|
||||
|
||||
sqrt(a) {
|
||||
return Math.sqrt(a);
|
||||
}
|
||||
|
||||
abs(a) {
|
||||
return Math.abs(a);
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = Calculator;
|
||||
"@
|
||||
Set-Content -Path "calculator.js" -Value $calc9
|
||||
git add calculator.js
|
||||
git commit -m "Add absolute value function" | Out-Null
|
||||
|
||||
# Commit 10: Add max function
|
||||
$calc10 = @"
|
||||
class Calculator {
|
||||
add(a, b) {
|
||||
return a - b; // BUG: Should be a + b
|
||||
}
|
||||
|
||||
subtract(a, b) {
|
||||
return a - b;
|
||||
}
|
||||
|
||||
multiply(a, b) {
|
||||
return a * b;
|
||||
}
|
||||
|
||||
divide(a, b) {
|
||||
if (b === 0) throw new Error('Division by zero');
|
||||
return a / b;
|
||||
}
|
||||
|
||||
modulo(a, b) {
|
||||
return a % b;
|
||||
}
|
||||
|
||||
power(a, b) {
|
||||
return Math.pow(a, b);
|
||||
}
|
||||
|
||||
sqrt(a) {
|
||||
return Math.sqrt(a);
|
||||
}
|
||||
|
||||
abs(a) {
|
||||
return Math.abs(a);
|
||||
}
|
||||
|
||||
max(a, b) {
|
||||
return a > b ? a : b;
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = Calculator;
|
||||
"@
|
||||
Set-Content -Path "calculator.js" -Value $calc10
|
||||
git add calculator.js
|
||||
git commit -m "Add max function" | Out-Null
|
||||
|
||||
# Create a test file
|
||||
$test = @"
|
||||
const Calculator = require('./calculator.js');
|
||||
const calc = new Calculator();
|
||||
|
||||
// Test addition (this will fail due to bug)
|
||||
const result = calc.add(5, 3);
|
||||
if (result !== 8) {
|
||||
console.log('FAIL: add(5, 3) returned ' + result + ', expected 8');
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
console.log('PASS: All tests passed');
|
||||
process.exit(0);
|
||||
"@
|
||||
Set-Content -Path "test.js" -Value $test
|
||||
|
||||
# Return to module directory
|
||||
Set-Location ..
|
||||
|
||||
Write-Host "`n========================================" -ForegroundColor Green
|
||||
Write-Host "Challenge environment created!" -ForegroundColor Green
|
||||
Write-Host "========================================" -ForegroundColor Green
|
||||
Write-Host "`nSituation:" -ForegroundColor Cyan
|
||||
Write-Host "The calculator has a bug - addition doesn't work correctly!" -ForegroundColor Red
|
||||
Write-Host "calc.add(5, 3) returns 2 instead of 8" -ForegroundColor Red
|
||||
Write-Host "`nThe bug was introduced somewhere in the last 10 commits." -ForegroundColor Yellow
|
||||
Write-Host "Manually checking each commit would be tedious." -ForegroundColor Yellow
|
||||
Write-Host "Use git bisect to find it efficiently!" -ForegroundColor Green
|
||||
Write-Host "`nYour task:" -ForegroundColor Yellow
|
||||
Write-Host "1. Navigate to the challenge directory: cd challenge" -ForegroundColor White
|
||||
Write-Host "2. Test the bug: node test.js (it will fail)" -ForegroundColor White
|
||||
Write-Host "3. Start bisect: git bisect start" -ForegroundColor White
|
||||
Write-Host "4. Mark current as bad: git bisect bad" -ForegroundColor White
|
||||
Write-Host "5. Mark old commit as good: git bisect good HEAD~10" -ForegroundColor White
|
||||
Write-Host "6. Git will checkout a commit - test it: node test.js" -ForegroundColor White
|
||||
Write-Host "7. Mark result: git bisect good (if test passes) or git bisect bad (if it fails)" -ForegroundColor White
|
||||
Write-Host "8. Repeat until Git finds the first bad commit" -ForegroundColor White
|
||||
Write-Host "9. Note the commit hash" -ForegroundColor White
|
||||
Write-Host "10. End bisect: git bisect reset" -ForegroundColor White
|
||||
Write-Host "11. Create bug-commit.txt with the bad commit hash" -ForegroundColor White
|
||||
Write-Host "`nHint: The bug is in commit 6 ('Refactor add function for clarity')" -ForegroundColor Cyan
|
||||
Write-Host "Run '../verify.ps1' from the challenge directory to check your solution.`n" -ForegroundColor Cyan
|
||||
133
module-14-bisect/verify.ps1
Normal file
133
module-14-bisect/verify.ps1
Normal file
@@ -0,0 +1,133 @@
|
||||
#!/usr/bin/env pwsh
|
||||
|
||||
<#
|
||||
.SYNOPSIS
|
||||
Verifies the bisect challenge solution.
|
||||
|
||||
.DESCRIPTION
|
||||
Checks that the user successfully used git bisect to find
|
||||
the commit that introduced the bug.
|
||||
#>
|
||||
|
||||
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 git repository exists
|
||||
if (-not (Test-Path ".git")) {
|
||||
Write-Host "[FAIL] No git repository found." -ForegroundColor Red
|
||||
Set-Location ..
|
||||
exit 1
|
||||
}
|
||||
|
||||
# Make sure we're not in a bisect session
|
||||
$bisectHead = Test-Path ".git/BISECT_HEAD"
|
||||
if ($bisectHead) {
|
||||
Write-Host "[FAIL] You're still in a bisect session." -ForegroundColor Red
|
||||
Write-Host "Hint: End the bisect with: git bisect reset" -ForegroundColor Yellow
|
||||
Set-Location ..
|
||||
exit 1
|
||||
}
|
||||
|
||||
# Check if bug-commit.txt exists
|
||||
if (-not (Test-Path "bug-commit.txt")) {
|
||||
Write-Host "[FAIL] bug-commit.txt not found." -ForegroundColor Red
|
||||
Write-Host "Hint: After finding the bad commit, create a file with its hash:" -ForegroundColor Yellow
|
||||
Write-Host " echo 'commit-hash' > bug-commit.txt" -ForegroundColor Yellow
|
||||
Set-Location ..
|
||||
exit 1
|
||||
}
|
||||
|
||||
# Read the commit hash from the file
|
||||
$userCommit = (Get-Content "bug-commit.txt" -Raw).Trim()
|
||||
|
||||
if (-not $userCommit) {
|
||||
Write-Host "[FAIL] bug-commit.txt is empty." -ForegroundColor Red
|
||||
Set-Location ..
|
||||
exit 1
|
||||
}
|
||||
|
||||
# Get all commit hashes
|
||||
$allCommits = git log --pretty=format:"%H" --reverse 2>$null
|
||||
$commitArray = $allCommits -split "`n"
|
||||
|
||||
# The bug was introduced in commit 6 (index 5 in 0-based array)
|
||||
# This is the "Refactor add function for clarity" commit
|
||||
$badCommitMessage = git log --pretty=format:"%s" --grep="Refactor add function" 2>$null
|
||||
$actualBadCommit = git log --pretty=format:"%H" --grep="Refactor add function" 2>$null
|
||||
|
||||
if (-not $actualBadCommit) {
|
||||
Write-Host "[FAIL] Could not find the expected bad commit." -ForegroundColor Red
|
||||
Write-Host "Something may be wrong with the repository setup." -ForegroundColor Yellow
|
||||
Set-Location ..
|
||||
exit 1
|
||||
}
|
||||
|
||||
# Check if user found the correct commit
|
||||
if ($userCommit -ne $actualBadCommit) {
|
||||
# Maybe they provided a short hash
|
||||
if ($actualBadCommit -like "$userCommit*") {
|
||||
Write-Host "[PASS] Correct commit identified (using short hash)!" -ForegroundColor Green
|
||||
} else {
|
||||
Write-Host "[FAIL] Incorrect commit identified." -ForegroundColor Red
|
||||
Write-Host "You identified: $userCommit" -ForegroundColor Yellow
|
||||
Write-Host "Expected: $actualBadCommit" -ForegroundColor Yellow
|
||||
Write-Host "Expected commit message: 'Refactor add function for clarity'" -ForegroundColor Yellow
|
||||
Write-Host "`nHint: Use git bisect to find where the add function broke:" -ForegroundColor Yellow
|
||||
Write-Host " git bisect start" -ForegroundColor White
|
||||
Write-Host " git bisect bad" -ForegroundColor White
|
||||
Write-Host " git bisect good HEAD~10" -ForegroundColor White
|
||||
Write-Host " # Then test with: node test.js" -ForegroundColor White
|
||||
Write-Host " git bisect good # or bad" -ForegroundColor White
|
||||
Set-Location ..
|
||||
exit 1
|
||||
}
|
||||
} else {
|
||||
Write-Host "[PASS] Correct commit identified!" -ForegroundColor Green
|
||||
}
|
||||
|
||||
# Verify the commit actually has the bug
|
||||
git checkout $actualBadCommit 2>$null | Out-Null
|
||||
$calcContent = Get-Content "calculator.js" -Raw
|
||||
|
||||
if ($calcContent -notmatch "add\(a, b\)[\s\S]*?return a - b") {
|
||||
Write-Host "[WARNING] The identified commit doesn't seem to have the expected bug." -ForegroundColor Yellow
|
||||
}
|
||||
|
||||
# Return to latest commit
|
||||
git checkout $(git branch --show-current 2>$null) 2>$null | Out-Null
|
||||
if (-not $?) {
|
||||
git checkout main 2>$null | Out-Null
|
||||
}
|
||||
|
||||
# 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 "- Used git bisect to perform a binary search" -ForegroundColor White
|
||||
Write-Host "- Tested commits systematically" -ForegroundColor White
|
||||
Write-Host "- Identified the exact commit that introduced the bug" -ForegroundColor White
|
||||
Write-Host "- Found: '$badCommitMessage'" -ForegroundColor White
|
||||
Write-Host "`nThe bug was in commit 6 out of 10 commits." -ForegroundColor Yellow
|
||||
Write-Host "Manual checking: up to 10 tests" -ForegroundColor Yellow
|
||||
Write-Host "With bisect: only ~4 tests needed!" -ForegroundColor Green
|
||||
Write-Host "`nYou now understand git bisect!" -ForegroundColor Green
|
||||
Write-Host "`nKey takeaway:" -ForegroundColor Yellow
|
||||
Write-Host "Bisect uses binary search to efficiently find bugs," -ForegroundColor White
|
||||
Write-Host "saving massive amounts of time in large codebases.`n" -ForegroundColor White
|
||||
|
||||
Set-Location ..
|
||||
exit 0
|
||||
Reference in New Issue
Block a user