From 575e083f332719f1895c1cfe969d229bf81307c4 Mon Sep 17 00:00:00 2001 From: Bjarke Sporring Date: Thu, 15 Jan 2026 16:11:24 +0100 Subject: [PATCH] refactor: rewrite the merge-revert section It is an advanced and difficult revert to accomplish and should probably be done through a reset instead, which means that we're modifying history which is dangerous and so should be handled by someone who understands these dangers. --- 01-essentials/06-revert/README.md | 270 +++++++++++------------------ 01-essentials/06-revert/reset.ps1 | 4 +- 01-essentials/06-revert/setup.ps1 | 121 +++++-------- 01-essentials/06-revert/verify.ps1 | 73 ++++---- 4 files changed, 186 insertions(+), 282 deletions(-) diff --git a/01-essentials/06-revert/README.md b/01-essentials/06-revert/README.md index 967acb8..e6c4a8a 100644 --- a/01-essentials/06-revert/README.md +++ b/01-essentials/06-revert/README.md @@ -1,8 +1,8 @@ -# Module 05: Git Revert - Safe Undoing +# Module 06: Git Revert - Safe Undoing ## About This Module -Welcome to Module 05, where you'll learn the **safe, team-friendly way to undo changes** in Git. Unlike destructive commands that erase history, `git revert` creates new commits that undo previous changes while preserving the complete project history. +Welcome to Module 06, where you'll learn the **safe, team-friendly way to undo changes** in Git. Unlike destructive commands that erase history, `git revert` creates new commits that undo previous changes while preserving the complete project history. **Why revert is important:** - ✅ Safe for shared/pushed commits @@ -17,19 +17,18 @@ Welcome to Module 05, where you'll learn the **safe, team-friendly way to undo c By completing this module, you will: -1. Revert regular commits safely while preserving surrounding changes -2. Revert merge commits using the `-m` flag -3. Understand merge commit parent numbering -4. Handle the re-merge problem that occurs after reverting merges -5. Revert multiple commits at once -6. Know when to use revert vs. other undo strategies +1. Revert commits safely while preserving surrounding changes +2. Revert old commits in the middle of history +3. Understand how revert preserves commits before and after the target +4. Revert multiple commits at once +5. Know when to use revert vs. other undo strategies ## Prerequisites Before starting this module, you should be comfortable with: - Creating commits (`git commit`) - Viewing commit history (`git log`) -- Understanding branches and merging (Module 03) +- Understanding branches (Module 03) ## Setup @@ -41,7 +40,7 @@ Run the setup script to create the challenge environment: This creates a `challenge/` directory with three branches demonstrating different revert scenarios: - `regular-revert` - Basic commit reversion -- `merge-revert` - Merge commit reversion +- `middle-revert` - Reverting a commit in the middle of history - `multi-revert` - Multiple commit reversion ## Challenge 1: Reverting a Regular Commit @@ -120,140 +119,108 @@ main.py (initial) → multiply (good) → divide (BAD) → modulo (good) → rev The revert commit adds a new point in history that undoes the divide changes. -## Challenge 2: Reverting a Merge Commit +## Challenge 2: Reverting a Commit in the Middle ### Scenario -Your team merged a `feature-auth` branch that added authentication functionality. After deployment, you discovered the authentication system has critical security issues. You need to revert the entire merge while the security team redesigns the feature. +You're working on improving your calculator application. Several commits were made in sequence: +1. Added input validation (good) +2. Added output formatter (BAD - has bugs!) +3. Added configuration module (good - but came after the bad commit) -**This is different from reverting a regular commit!** Merge commits have **two parents**, so you must tell Git which parent to keep. +The formatter has critical bugs and needs to be removed, but you want to keep both the validation module (added before) and the configuration module (added after). -### Understanding Merge Commit Parents +**This demonstrates an important Git principle:** Revert works on ANY commit in history, not just recent ones! -When you merge a feature branch into main: +### Understanding History Preservation + +Here's what the commit history looks like: ``` - feature-auth (parent 2) - ↓ - C---D - / \ -A---B-----M ← Merge commit (has TWO parents) - ↑ -parent 1 (main) +A (initial) → B (validation) → C (formatter BAD) → D (config) + ↑ + We want to remove THIS ``` -The merge commit `M` has: -- **Parent 1**: The branch you merged INTO (main) -- **Parent 2**: The branch you merged FROM (feature-auth) +When you revert commit C: -When reverting a merge, you must specify which parent to keep using the `-m` flag: -- `-m 1` means "keep parent 1" (main) - **Most common** -- `-m 2` means "keep parent 2" (feature-auth) - Rare +``` +A (initial) → B (validation) → C (formatter BAD) → D (config) → E (revert C) + ↑ + Removes formatter, keeps validation & config +``` -**In practice:** You almost always use `-m 1` to keep the main branch and undo the feature branch changes. +**Key insight:** The revert creates a NEW commit (E) that undoes commit C, but leaves B and D completely intact! ### Your Task -1. **Switch to the merge-revert branch:** +1. **Switch to the middle-revert branch:** ```pwsh - git switch merge-revert + git switch middle-revert ``` -2. **View the commit history with the graph:** +2. **View the commit history:** ```pwsh - git log --oneline --graph + git log --oneline ``` - Look for the merge commit message: "Merge feature-auth branch" - - Note the commit hash - - Write it down or copy it + You should see three commits after the initial: + - "Add input validation module" + - "Add broken formatter - needs to be reverted!" + - "Add configuration module" -3. **Revert the merge commit using `-m 1`** (replace `` with actual hash): +3. **Find the broken formatter commit:** + - Look for the message: "Add broken formatter - needs to be reverted!" + - Note the commit hash (the 7-character code) + - Write it down + +4. **Revert that middle commit** (replace `` with actual hash): ```pwsh - git revert -m 1 + git revert ``` - **What `-m 1` means:** - - `-m 1` tells Git to keep parent 1 (the main branch side) - - This undoes all changes from the feature-auth branch - - Creates a new "revert merge" commit - -4. **Visual Studio Code will open** with the revert commit message: +5. **Visual Studio Code will open** with the revert commit message: + - The default message is fine - Close the editor window to accept it - Git will create the revert commit -5. **Check the result:** +6. **Check the result:** ```pwsh - # View files - auth.py should be gone + # View files - formatter.py should be gone ls - # You should see calculator.py but NOT auth.py + # You should see validation.py and config.py but NOT formatter.py - # Verify calculator.py no longer imports auth - cat calculator.py - # Should NOT see "from auth import" anywhere + # View the history + git log --oneline + # You should see the new revert commit at the top ``` -### What Happens Without -m? +### What to Observe -If you try to revert a merge commit without the `-m` flag: +After reverting, notice: -```bash -git revert -# Error: commit is a merge but no -m option was given +```pwsh +# Check which files exist +ls + +# You should see: +# - calculator.py (from initial commit) +# - validation.py (from commit BEFORE bad one) ✅ +# - config.py (from commit AFTER bad one) ✅ +# - formatter.py is GONE (reverted) ❌ ``` -Git doesn't know which parent you want to keep, so it refuses to proceed. +**Important:** Git successfully removed the bad formatter while keeping everything else! -### The Re-Merge Problem +### Why This Matters -**Important gotcha:** After reverting a merge, you **cannot simply re-merge** the same branch! +This scenario demonstrates revert's power in real-world situations: +- You discover a bug in code committed days or weeks ago +- Many commits have been made since then +- You can't just delete the old commit (that would break history) +- Revert lets you surgically remove just the bad commit -Here's why: - -``` -Initial merge: -A---B---M (merged feature-auth) - ↑ - All changes from feature-auth are now in main - -After revert: -A---B---M---R (reverted merge) - ↑ - Changes removed, but Git remembers they were merged - -Attempting to re-merge: -A---B---M---R---M2 (try to merge feature-auth again) - ↑ - Git thinks: "I already merged these commits, - nothing new to add!" (Empty merge) -``` - -**Solutions if you need to re-merge:** - -1. **Revert the revert** (recommended): - ```bash - git revert - ``` - This brings back all the feature-auth changes. - -2. **Cherry-pick new commits** from the feature branch: - ```bash - git cherry-pick - ``` - -3. **Merge with --no-ff** and resolve conflicts manually (advanced). - -### When to Revert Merges - -Revert merge commits when: -- ✅ Feature causes production issues -- ✅ Need to temporarily remove a feature -- ✅ Discovered critical bugs after merging -- ✅ Security issues require immediate rollback - -Don't revert merges when: -- ❌ You just need to fix a small bug (fix it with a new commit instead) -- ❌ You plan to re-merge the same branch soon (use reset if local, or revert-the-revert later) +**Revert is your "undo button" for shared history!** ## Challenge 3: Reverting Multiple Commits @@ -311,7 +278,7 @@ Two separate commits added broken mathematical functions (`square_root` and `log **Reverting a range of commits:** -```bash +```pwsh # Revert commits from A to B (inclusive) git revert A^..B @@ -321,7 +288,7 @@ git revert HEAD~3..HEAD **Reverting without auto-commit:** -```bash +```pwsh # Stage revert changes without committing git revert --no-commit @@ -353,8 +320,7 @@ The script checks that: - ✅ Revert commits were created (not destructive deletion) - ✅ Bad code is removed - ✅ Good code before and after is preserved -- ✅ Merge commits still exist in history -- ✅ Proper use of `-m` flag for merge reverts +- ✅ Revert works on commits in the middle of history ## Command Reference @@ -371,14 +337,17 @@ git revert HEAD git revert HEAD~1 ``` -### Merge Commit Revert +### Reverting Old Commits ```pwsh -# Revert a merge commit (keep parent 1) -git revert -m 1 +# Revert a specific commit from any point in history +git revert -# Revert a merge commit (keep parent 2) - rare -git revert -m 2 +# Revert a commit from 5 commits ago +git revert HEAD~5 + +# View what a commit changed before reverting +git show ``` ### Multiple Commits @@ -450,7 +419,7 @@ Consider alternatives when: Sometimes reverting causes conflicts if subsequent changes touched the same code: -```bash +```pwsh # Start revert git revert @@ -463,47 +432,24 @@ git revert 1. Open conflicted files and fix conflicts (look for `<<<<<<<` markers) 2. Stage resolved files: - ```bash + ```pwsh git add ``` 3. Continue the revert: - ```bash + ```pwsh git revert --continue ``` Or abort if you change your mind: -```bash +```pwsh git revert --abort ``` ## Common Mistakes -### 1. Forgetting -m for Merge Commits +### 1. Using Reset on Pushed Commits -```bash -# ❌ Wrong - will fail -git revert - -# ✅ Correct -git revert -m 1 -``` - -### 2. Trying to Re-Merge After Revert - -```bash -# After reverting a merge: -git revert -m 1 - -# ❌ This won't work as expected -git merge feature-branch # Empty merge! - -# ✅ Do this instead -git revert # Revert the revert -``` - -### 3. Using Reset on Pushed Commits - -```bash +```pwsh # ❌ NEVER do this with pushed commits git reset --hard HEAD~3 @@ -511,11 +457,11 @@ git reset --hard HEAD~3 git revert HEAD~3..HEAD ``` -### 4. Reverting Commits in Wrong Order +### 2. Reverting Commits in Wrong Order When reverting multiple related commits, revert from newest to oldest: -```bash +```pwsh # If you have: A → B → C (and C depends on B) # ✅ Correct order @@ -530,7 +476,7 @@ git revert C ## Best Practices 1. **Write clear revert messages:** - ```bash + ```pwsh git revert -m "Revert authentication - security issue #1234" ``` @@ -561,15 +507,6 @@ git revert C ## Troubleshooting -### "Commit is a merge but no -m option was given" - -**Problem:** Trying to revert a merge commit without `-m`. - -**Solution:** -```bash -git revert -m 1 -``` - ### "Empty Revert / No Changes" **Problem:** Revert doesn't seem to do anything. @@ -580,7 +517,7 @@ git revert -m 1 - Wrong commit hash **Solution:** -```bash +```pwsh # Check what the commit actually changed git show @@ -601,24 +538,22 @@ git log --grep="Revert" Or consider fixing forward with a new commit instead of reverting. -### "Can't Re-Merge After Reverting Merge" +### "Reverting Old Commit Breaks Something" -**Problem:** After reverting a merge, re-merging the branch brings no changes. +**Problem:** After reverting an old commit, something else stops working. -**Solution:** Revert the revert commit: -```bash -# Find the revert commit -git log --oneline +**Why:** The old commit might have been a dependency for later commits. -# Revert the revert (brings changes back) -git revert -``` +**Solution:** +1. Check what changed: `git diff HEAD~1 HEAD` +2. Either fix the issue with a new commit, or +3. Revert the revert if needed: `git revert ` ## Advanced: Revert Internals Understanding what revert does under the hood: -```bash +```pwsh # Revert creates a new commit with inverse changes git revert @@ -645,9 +580,8 @@ You've learned: - ✅ `git revert` creates new commits that undo previous changes - ✅ Revert is safe for shared/pushed commits -- ✅ Merge commits require `-m 1` or `-m 2` flag -- ✅ Parent 1 = branch merged into, Parent 2 = branch merged from -- ✅ Can't simply re-merge after reverting a merge +- ✅ Revert works on any commit in history, even old ones +- ✅ Commits before and after the reverted commit are preserved - ✅ Multiple commits can be reverted in one command - ✅ Revert preserves complete history for audit trails diff --git a/01-essentials/06-revert/reset.ps1 b/01-essentials/06-revert/reset.ps1 index d40ab84..3c026ac 100644 --- a/01-essentials/06-revert/reset.ps1 +++ b/01-essentials/06-revert/reset.ps1 @@ -1,14 +1,14 @@ #!/usr/bin/env pwsh <# .SYNOPSIS - Resets the Module 05 challenge environment to start fresh. + Resets the Module 06 challenge environment to start fresh. .DESCRIPTION This script removes the challenge directory and re-runs setup.ps1 to create a fresh challenge environment. #> -Write-Host "`n=== Resetting Module 05: Git Revert Challenge ===" -ForegroundColor Cyan +Write-Host "`n=== Resetting Module 06: Git Revert Challenge ===" -ForegroundColor Cyan # Check if challenge directory exists if (Test-Path "challenge") { diff --git a/01-essentials/06-revert/setup.ps1 b/01-essentials/06-revert/setup.ps1 index cfe303b..12c6d6e 100644 --- a/01-essentials/06-revert/setup.ps1 +++ b/01-essentials/06-revert/setup.ps1 @@ -1,17 +1,17 @@ #!/usr/bin/env pwsh <# .SYNOPSIS - Sets up the Module 05 challenge environment for learning git revert. + Sets up the Module 06 challenge environment for learning git revert. .DESCRIPTION This script creates a challenge directory with three branches demonstrating different revert scenarios: - - regular-revert: Basic revert of a single bad commit - - merge-revert: Reverting a merge commit with -m flag + - regular-revert: Basic revert of a single bad commit at the end + - middle-revert: Reverting a bad commit in the middle of history - multi-revert: Reverting multiple commits at once #> -Write-Host "`n=== Setting up Module 05: Git Revert Challenge ===" -ForegroundColor Cyan +Write-Host "`n=== Setting up Module 06: Git Revert Challenge ===" -ForegroundColor Cyan # Remove existing challenge directory if it exists if (Test-Path "challenge") { @@ -104,90 +104,63 @@ git commit -m "Add modulo function" | Out-Null Write-Host "[CREATED] regular-revert branch with bad divide commit" -ForegroundColor Green # ============================================================================ -# SCENARIO 2: Merge Revert (Merge Commit with -m flag) +# SCENARIO 2: Revert in Middle of History # ============================================================================ -Write-Host "`nScenario 2: Creating merge-revert scenario..." -ForegroundColor Cyan +Write-Host "`nScenario 2: Creating middle-revert scenario..." -ForegroundColor Cyan # Switch back to main git switch $mainBranch | Out-Null -# Create merge-revert branch -git switch -c merge-revert | Out-Null +# Create middle-revert branch +git switch -c middle-revert | Out-Null -# Create a feature branch to merge -git switch -c feature-auth | Out-Null +# Good commit: Add validation module +$validationContent = @" +# validation.py - Input validation -# Add auth functionality -$authContent = @" -# auth.py - Authentication module - -def login(username, password): - \"\"\"Login user.\"\"\" - print(f"Logging in {username}...") - return True - -def logout(username): - \"\"\"Logout user.\"\"\" - print(f"Logging out {username}...") - return True -"@ -Set-Content -Path "auth.py" -Value $authContent -git add . -git commit -m "Add authentication module" | Out-Null - -# Add password validation -$authContent = @" -# auth.py - Authentication module - -def validate_password(password): - \"\"\"Validate password strength.\"\"\" - return len(password) >= 8 - -def login(username, password): - \"\"\"Login user.\"\"\" - if not validate_password(password): - print("Password too weak!") +def validate_number(value): + """Check if value is a valid number.""" + try: + float(value) + return True + except ValueError: return False - print(f"Logging in {username}...") - return True - -def logout(username): - \"\"\"Logout user.\"\"\" - print(f"Logging out {username}...") - return True "@ -Set-Content -Path "auth.py" -Value $authContent +Set-Content -Path "validation.py" -Value $validationContent git add . -git commit -m "Add password validation" | Out-Null +git commit -m "Add input validation module" | Out-Null -# Integrate auth into calculator (part of the feature branch) -$calcContent = @" -# calculator.py - Simple calculator -from auth import login +# BAD commit: Add broken formatter +$formatterContent = @" +# formatter.py - Output formatting -def add(a, b): - """Add two numbers.""" - return a + b - -def subtract(a, b): - """Subtract b from a.""" - return a - b - -def secure_divide(a, b, username): - """Secure divide - requires authentication.""" - if login(username, "password123"): - return a / b - return None +def format_result(result): + """BROKEN: Doesn't handle None or errors properly!""" + return f"Result: {result.upper()}" # This crashes if result is not a string! "@ -Set-Content -Path "calculator.py" -Value $calcContent +Set-Content -Path "formatter.py" -Value $formatterContent git add . -git commit -m "Integrate auth into calculator" | Out-Null +git commit -m "Add broken formatter - needs to be reverted!" | Out-Null -# Switch back to merge-revert and merge feature-auth -git switch merge-revert | Out-Null -git merge feature-auth --no-ff -m "Merge feature-auth branch" | Out-Null +# Good commit: Add configuration (depends on validation, not formatter) +$configContent = @" +# config.py - Application configuration -Write-Host "[CREATED] merge-revert branch with merge commit to revert" -ForegroundColor Green +from validation import validate_number + +DEFAULT_PRECISION = 2 + +def set_precision(value): + """Set calculation precision.""" + if validate_number(value): + return int(value) + return DEFAULT_PRECISION +"@ +Set-Content -Path "config.py" -Value $configContent +git add . +git commit -m "Add configuration module" | Out-Null + +Write-Host "[CREATED] middle-revert branch with bad commit in the middle" -ForegroundColor Green # ============================================================================ # SCENARIO 3: Multi Revert (Multiple Bad Commits) @@ -275,8 +248,8 @@ Set-Location .. Write-Host "`n=== Setup Complete! ===" -ForegroundColor Green Write-Host "`nThree revert scenarios have been created:" -ForegroundColor Cyan -Write-Host " 1. regular-revert - Revert a single bad commit (basic)" -ForegroundColor White -Write-Host " 2. merge-revert - Revert a merge commit with -m flag" -ForegroundColor White +Write-Host " 1. regular-revert - Revert a bad commit at the end" -ForegroundColor White +Write-Host " 2. middle-revert - Revert a bad commit in the middle of history" -ForegroundColor White Write-Host " 3. multi-revert - Revert multiple bad commits" -ForegroundColor White Write-Host "`nYou are currently on the 'regular-revert' branch." -ForegroundColor Cyan Write-Host "`nNext steps:" -ForegroundColor Cyan diff --git a/01-essentials/06-revert/verify.ps1 b/01-essentials/06-revert/verify.ps1 index 1fc89f5..4013851 100644 --- a/01-essentials/06-revert/verify.ps1 +++ b/01-essentials/06-revert/verify.ps1 @@ -1,16 +1,16 @@ #!/usr/bin/env pwsh <# .SYNOPSIS - Verifies the Module 05 challenge solutions. + Verifies the Module 06 challenge solutions. .DESCRIPTION Checks that all three revert scenarios have been completed correctly: - regular-revert: Single commit reverted - - merge-revert: Merge commit reverted with -m flag + - middle-revert: Commit in middle of history reverted - multi-revert: Multiple commits reverted #> -Write-Host "`n=== Verifying Module 05: Git Revert Solutions ===" -ForegroundColor Cyan +Write-Host "`n=== Verifying Module 06: Git Revert Solutions ===" -ForegroundColor Cyan $allChecksPassed = $true $originalDir = Get-Location @@ -87,53 +87,50 @@ if ($LASTEXITCODE -ne 0) { } # ============================================================================ -# SCENARIO 2: Merge Revert Verification +# SCENARIO 2: Middle Revert Verification # ============================================================================ -Write-Host "`n=== Scenario 2: Merge Revert ===" -ForegroundColor Cyan +Write-Host "`n=== Scenario 2: Middle Revert ===" -ForegroundColor Cyan -git switch merge-revert 2>&1 | Out-Null +git switch middle-revert 2>&1 | Out-Null if ($LASTEXITCODE -ne 0) { - Write-Host "[FAIL] merge-revert branch not found" -ForegroundColor Red + Write-Host "[FAIL] middle-revert branch not found" -ForegroundColor Red $allChecksPassed = $false } else { - # Check that a revert commit for the merge exists - $revertMerge = git log --oneline --grep="Revert.*Merge" 2>$null - if ($revertMerge) { - Write-Host "[PASS] Merge revert commit found" -ForegroundColor Green + # Check that a revert commit exists + $revertCommit = git log --oneline --grep="Revert" 2>$null + if ($revertCommit) { + Write-Host "[PASS] Revert commit found" -ForegroundColor Green } else { - Write-Host "[FAIL] No merge revert commit found" -ForegroundColor Red - Write-Host "[HINT] Use: git revert -m 1 " -ForegroundColor Yellow + Write-Host "[FAIL] No revert commit found" -ForegroundColor Red + Write-Host "[HINT] Use: git revert " -ForegroundColor Yellow $allChecksPassed = $false } - # Check that the original merge commit still exists (revert doesn't erase it) - $mergeCommit = git log --merges --oneline --grep="Merge feature-auth" 2>$null - if ($mergeCommit) { - Write-Host "[PASS] Original merge commit still in history (not erased)" -ForegroundColor Green + # Check that formatter.py is removed (reverted) + if (-not (Test-Path "formatter.py")) { + Write-Host "[PASS] Broken formatter.py successfully reverted (file removed)" -ForegroundColor Green } else { - Write-Host "[INFO] Original merge commit not found (this is OK if you used a different approach)" -ForegroundColor Yellow + Write-Host "[FAIL] formatter.py still exists (should be reverted)" -ForegroundColor Red + Write-Host "[HINT] The bad commit should be reverted, removing formatter.py" -ForegroundColor Yellow + $allChecksPassed = $false } - # Check that auth.py no longer exists or its effects are reverted - if (-not (Test-Path "auth.py")) { - Write-Host "[PASS] auth.py removed (merge reverted successfully)" -ForegroundColor Green + # Check that validation.py still exists (good commit before bad one) + if (Test-Path "validation.py") { + Write-Host "[PASS] validation.py preserved (good commit before bad one)" -ForegroundColor Green } else { - Write-Host "[INFO] auth.py still exists (check if merge was fully reverted)" -ForegroundColor Yellow + Write-Host "[FAIL] validation.py missing (should still exist)" -ForegroundColor Red + $allChecksPassed = $false } - # Check that calculator.py exists - if (Test-Path "calculator.py") { - $calcContent = Get-Content "calculator.py" -Raw - - # After reverting the merge, calculator shouldn't import auth - if ($calcContent -notmatch "from auth import") { - Write-Host "[PASS] Auth integration reverted from calculator.py" -ForegroundColor Green - } else { - Write-Host "[FAIL] calculator.py still imports auth (merge not fully reverted)" -ForegroundColor Red - Write-Host "[HINT] Reverting the merge should remove the auth integration" -ForegroundColor Yellow - $allChecksPassed = $false - } + # Check that config.py still exists (good commit after bad one) + if (Test-Path "config.py") { + Write-Host "[PASS] config.py preserved (good commit after bad one)" -ForegroundColor Green + } else { + Write-Host "[FAIL] config.py missing (should still exist)" -ForegroundColor Red + Write-Host "[HINT] Only revert the bad commit, not the good ones after it" -ForegroundColor Yellow + $allChecksPassed = $false } } @@ -211,11 +208,11 @@ if ($allChecksPassed) { Write-Host "=========================================" -ForegroundColor Green Write-Host "`nYou've mastered git revert!" -ForegroundColor Cyan Write-Host "You now understand:" -ForegroundColor Cyan - Write-Host " ✓ Reverting regular commits safely" -ForegroundColor White - Write-Host " ✓ Reverting merge commits with -m flag" -ForegroundColor White + Write-Host " ✓ Reverting commits safely without erasing history" -ForegroundColor White + Write-Host " ✓ Reverting old commits in the middle of history" -ForegroundColor White Write-Host " ✓ Reverting multiple commits at once" -ForegroundColor White - Write-Host " ✓ Preserving history while undoing changes" -ForegroundColor White - Write-Host "`nReady for Module 06: Git Reset!" -ForegroundColor Green + Write-Host " ✓ Preserving commits before and after the reverted one" -ForegroundColor White + Write-Host "`nReady for Module 07: Git Reset!" -ForegroundColor Green Write-Host "" exit 0 } else {