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.
This commit is contained in:
@@ -1,8 +1,8 @@
|
|||||||
# Module 05: Git Revert - Safe Undoing
|
# Module 06: Git Revert - Safe Undoing
|
||||||
|
|
||||||
## About This Module
|
## 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:**
|
**Why revert is important:**
|
||||||
- ✅ Safe for shared/pushed commits
|
- ✅ 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:
|
By completing this module, you will:
|
||||||
|
|
||||||
1. Revert regular commits safely while preserving surrounding changes
|
1. Revert commits safely while preserving surrounding changes
|
||||||
2. Revert merge commits using the `-m` flag
|
2. Revert old commits in the middle of history
|
||||||
3. Understand merge commit parent numbering
|
3. Understand how revert preserves commits before and after the target
|
||||||
4. Handle the re-merge problem that occurs after reverting merges
|
4. Revert multiple commits at once
|
||||||
5. Revert multiple commits at once
|
5. Know when to use revert vs. other undo strategies
|
||||||
6. Know when to use revert vs. other undo strategies
|
|
||||||
|
|
||||||
## Prerequisites
|
## Prerequisites
|
||||||
|
|
||||||
Before starting this module, you should be comfortable with:
|
Before starting this module, you should be comfortable with:
|
||||||
- Creating commits (`git commit`)
|
- Creating commits (`git commit`)
|
||||||
- Viewing commit history (`git log`)
|
- Viewing commit history (`git log`)
|
||||||
- Understanding branches and merging (Module 03)
|
- Understanding branches (Module 03)
|
||||||
|
|
||||||
## Setup
|
## 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:
|
This creates a `challenge/` directory with three branches demonstrating different revert scenarios:
|
||||||
- `regular-revert` - Basic commit reversion
|
- `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
|
- `multi-revert` - Multiple commit reversion
|
||||||
|
|
||||||
## Challenge 1: Reverting a Regular Commit
|
## 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.
|
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
|
### 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)
|
A (initial) → B (validation) → C (formatter BAD) → D (config)
|
||||||
↓
|
|
||||||
C---D
|
|
||||||
/ \
|
|
||||||
A---B-----M ← Merge commit (has TWO parents)
|
|
||||||
↑
|
↑
|
||||||
parent 1 (main)
|
We want to remove THIS
|
||||||
```
|
```
|
||||||
|
|
||||||
The merge commit `M` has:
|
When you revert commit C:
|
||||||
- **Parent 1**: The branch you merged INTO (main)
|
|
||||||
- **Parent 2**: The branch you merged FROM (feature-auth)
|
|
||||||
|
|
||||||
When reverting a merge, you must specify which parent to keep using the `-m` flag:
|
```
|
||||||
- `-m 1` means "keep parent 1" (main) - **Most common**
|
A (initial) → B (validation) → C (formatter BAD) → D (config) → E (revert C)
|
||||||
- `-m 2` means "keep parent 2" (feature-auth) - Rare
|
↑
|
||||||
|
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
|
### Your Task
|
||||||
|
|
||||||
1. **Switch to the merge-revert branch:**
|
1. **Switch to the middle-revert branch:**
|
||||||
```pwsh
|
```pwsh
|
||||||
git switch merge-revert
|
git switch middle-revert
|
||||||
```
|
```
|
||||||
|
|
||||||
2. **View the commit history with the graph:**
|
2. **View the commit history:**
|
||||||
```pwsh
|
```pwsh
|
||||||
git log --oneline --graph
|
git log --oneline
|
||||||
```
|
```
|
||||||
|
|
||||||
Look for the merge commit message: "Merge feature-auth branch"
|
You should see three commits after the initial:
|
||||||
- Note the commit hash
|
- "Add input validation module"
|
||||||
- Write it down or copy it
|
- "Add broken formatter - needs to be reverted!"
|
||||||
|
- "Add configuration module"
|
||||||
|
|
||||||
3. **Revert the merge commit using `-m 1`** (replace `<merge-commit-hash>` 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 `<commit-hash>` with actual hash):
|
||||||
```pwsh
|
```pwsh
|
||||||
git revert -m 1 <merge-commit-hash>
|
git revert <commit-hash>
|
||||||
```
|
```
|
||||||
|
|
||||||
**What `-m 1` means:**
|
5. **Visual Studio Code will open** with the revert commit message:
|
||||||
- `-m 1` tells Git to keep parent 1 (the main branch side)
|
- The default message is fine
|
||||||
- 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:
|
|
||||||
- Close the editor window to accept it
|
- Close the editor window to accept it
|
||||||
- Git will create the revert commit
|
- Git will create the revert commit
|
||||||
|
|
||||||
5. **Check the result:**
|
6. **Check the result:**
|
||||||
```pwsh
|
```pwsh
|
||||||
# View files - auth.py should be gone
|
# View files - formatter.py should be gone
|
||||||
ls
|
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
|
# View the history
|
||||||
cat calculator.py
|
git log --oneline
|
||||||
# Should NOT see "from auth import" anywhere
|
# 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
|
```pwsh
|
||||||
git revert <merge-commit-hash>
|
# Check which files exist
|
||||||
# Error: commit <hash> is a merge but no -m option was given
|
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:
|
**Revert is your "undo button" for shared history!**
|
||||||
|
|
||||||
```
|
|
||||||
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 <revert-commit-hash>
|
|
||||||
```
|
|
||||||
This brings back all the feature-auth changes.
|
|
||||||
|
|
||||||
2. **Cherry-pick new commits** from the feature branch:
|
|
||||||
```bash
|
|
||||||
git cherry-pick <new-commits>
|
|
||||||
```
|
|
||||||
|
|
||||||
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)
|
|
||||||
|
|
||||||
## Challenge 3: Reverting Multiple Commits
|
## 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:**
|
**Reverting a range of commits:**
|
||||||
|
|
||||||
```bash
|
```pwsh
|
||||||
# Revert commits from A to B (inclusive)
|
# Revert commits from A to B (inclusive)
|
||||||
git revert A^..B
|
git revert A^..B
|
||||||
|
|
||||||
@@ -321,7 +288,7 @@ git revert HEAD~3..HEAD
|
|||||||
|
|
||||||
**Reverting without auto-commit:**
|
**Reverting without auto-commit:**
|
||||||
|
|
||||||
```bash
|
```pwsh
|
||||||
# Stage revert changes without committing
|
# Stage revert changes without committing
|
||||||
git revert --no-commit <commit-hash>
|
git revert --no-commit <commit-hash>
|
||||||
|
|
||||||
@@ -353,8 +320,7 @@ The script checks that:
|
|||||||
- ✅ Revert commits were created (not destructive deletion)
|
- ✅ Revert commits were created (not destructive deletion)
|
||||||
- ✅ Bad code is removed
|
- ✅ Bad code is removed
|
||||||
- ✅ Good code before and after is preserved
|
- ✅ Good code before and after is preserved
|
||||||
- ✅ Merge commits still exist in history
|
- ✅ Revert works on commits in the middle of history
|
||||||
- ✅ Proper use of `-m` flag for merge reverts
|
|
||||||
|
|
||||||
## Command Reference
|
## Command Reference
|
||||||
|
|
||||||
@@ -371,14 +337,17 @@ git revert HEAD
|
|||||||
git revert HEAD~1
|
git revert HEAD~1
|
||||||
```
|
```
|
||||||
|
|
||||||
### Merge Commit Revert
|
### Reverting Old Commits
|
||||||
|
|
||||||
```pwsh
|
```pwsh
|
||||||
# Revert a merge commit (keep parent 1)
|
# Revert a specific commit from any point in history
|
||||||
git revert -m 1 <merge-commit-hash>
|
git revert <commit-hash>
|
||||||
|
|
||||||
# Revert a merge commit (keep parent 2) - rare
|
# Revert a commit from 5 commits ago
|
||||||
git revert -m 2 <merge-commit-hash>
|
git revert HEAD~5
|
||||||
|
|
||||||
|
# View what a commit changed before reverting
|
||||||
|
git show <commit-hash>
|
||||||
```
|
```
|
||||||
|
|
||||||
### Multiple Commits
|
### Multiple Commits
|
||||||
@@ -450,7 +419,7 @@ Consider alternatives when:
|
|||||||
|
|
||||||
Sometimes reverting causes conflicts if subsequent changes touched the same code:
|
Sometimes reverting causes conflicts if subsequent changes touched the same code:
|
||||||
|
|
||||||
```bash
|
```pwsh
|
||||||
# Start revert
|
# Start revert
|
||||||
git revert <commit-hash>
|
git revert <commit-hash>
|
||||||
|
|
||||||
@@ -463,47 +432,24 @@ git revert <commit-hash>
|
|||||||
|
|
||||||
1. Open conflicted files and fix conflicts (look for `<<<<<<<` markers)
|
1. Open conflicted files and fix conflicts (look for `<<<<<<<` markers)
|
||||||
2. Stage resolved files:
|
2. Stage resolved files:
|
||||||
```bash
|
```pwsh
|
||||||
git add <resolved-files>
|
git add <resolved-files>
|
||||||
```
|
```
|
||||||
3. Continue the revert:
|
3. Continue the revert:
|
||||||
```bash
|
```pwsh
|
||||||
git revert --continue
|
git revert --continue
|
||||||
```
|
```
|
||||||
|
|
||||||
Or abort if you change your mind:
|
Or abort if you change your mind:
|
||||||
```bash
|
```pwsh
|
||||||
git revert --abort
|
git revert --abort
|
||||||
```
|
```
|
||||||
|
|
||||||
## Common Mistakes
|
## Common Mistakes
|
||||||
|
|
||||||
### 1. Forgetting -m for Merge Commits
|
### 1. Using Reset on Pushed Commits
|
||||||
|
|
||||||
```bash
|
```pwsh
|
||||||
# ❌ Wrong - will fail
|
|
||||||
git revert <merge-commit>
|
|
||||||
|
|
||||||
# ✅ Correct
|
|
||||||
git revert -m 1 <merge-commit>
|
|
||||||
```
|
|
||||||
|
|
||||||
### 2. Trying to Re-Merge After Revert
|
|
||||||
|
|
||||||
```bash
|
|
||||||
# After reverting a merge:
|
|
||||||
git revert -m 1 <merge-commit>
|
|
||||||
|
|
||||||
# ❌ This won't work as expected
|
|
||||||
git merge feature-branch # Empty merge!
|
|
||||||
|
|
||||||
# ✅ Do this instead
|
|
||||||
git revert <the-revert-commit> # Revert the revert
|
|
||||||
```
|
|
||||||
|
|
||||||
### 3. Using Reset on Pushed Commits
|
|
||||||
|
|
||||||
```bash
|
|
||||||
# ❌ NEVER do this with pushed commits
|
# ❌ NEVER do this with pushed commits
|
||||||
git reset --hard HEAD~3
|
git reset --hard HEAD~3
|
||||||
|
|
||||||
@@ -511,11 +457,11 @@ git reset --hard HEAD~3
|
|||||||
git revert HEAD~3..HEAD
|
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:
|
When reverting multiple related commits, revert from newest to oldest:
|
||||||
|
|
||||||
```bash
|
```pwsh
|
||||||
# If you have: A → B → C (and C depends on B)
|
# If you have: A → B → C (and C depends on B)
|
||||||
|
|
||||||
# ✅ Correct order
|
# ✅ Correct order
|
||||||
@@ -530,7 +476,7 @@ git revert C
|
|||||||
## Best Practices
|
## Best Practices
|
||||||
|
|
||||||
1. **Write clear revert messages:**
|
1. **Write clear revert messages:**
|
||||||
```bash
|
```pwsh
|
||||||
git revert <hash> -m "Revert authentication - security issue #1234"
|
git revert <hash> -m "Revert authentication - security issue #1234"
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -561,15 +507,6 @@ git revert C
|
|||||||
|
|
||||||
## Troubleshooting
|
## 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 <merge-commit-hash>
|
|
||||||
```
|
|
||||||
|
|
||||||
### "Empty Revert / No Changes"
|
### "Empty Revert / No Changes"
|
||||||
|
|
||||||
**Problem:** Revert doesn't seem to do anything.
|
**Problem:** Revert doesn't seem to do anything.
|
||||||
@@ -580,7 +517,7 @@ git revert -m 1 <merge-commit-hash>
|
|||||||
- Wrong commit hash
|
- Wrong commit hash
|
||||||
|
|
||||||
**Solution:**
|
**Solution:**
|
||||||
```bash
|
```pwsh
|
||||||
# Check what the commit actually changed
|
# Check what the commit actually changed
|
||||||
git show <commit-hash>
|
git show <commit-hash>
|
||||||
|
|
||||||
@@ -601,24 +538,22 @@ git log --grep="Revert"
|
|||||||
|
|
||||||
Or consider fixing forward with a new commit instead of reverting.
|
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:
|
**Why:** The old commit might have been a dependency for later commits.
|
||||||
```bash
|
|
||||||
# Find the revert commit
|
|
||||||
git log --oneline
|
|
||||||
|
|
||||||
# Revert the revert (brings changes back)
|
**Solution:**
|
||||||
git revert <revert-commit-hash>
|
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 <revert-commit-hash>`
|
||||||
|
|
||||||
## Advanced: Revert Internals
|
## Advanced: Revert Internals
|
||||||
|
|
||||||
Understanding what revert does under the hood:
|
Understanding what revert does under the hood:
|
||||||
|
|
||||||
```bash
|
```pwsh
|
||||||
# Revert creates a new commit with inverse changes
|
# Revert creates a new commit with inverse changes
|
||||||
git revert <commit-hash>
|
git revert <commit-hash>
|
||||||
|
|
||||||
@@ -645,9 +580,8 @@ You've learned:
|
|||||||
|
|
||||||
- ✅ `git revert` creates new commits that undo previous changes
|
- ✅ `git revert` creates new commits that undo previous changes
|
||||||
- ✅ Revert is safe for shared/pushed commits
|
- ✅ Revert is safe for shared/pushed commits
|
||||||
- ✅ Merge commits require `-m 1` or `-m 2` flag
|
- ✅ Revert works on any commit in history, even old ones
|
||||||
- ✅ Parent 1 = branch merged into, Parent 2 = branch merged from
|
- ✅ Commits before and after the reverted commit are preserved
|
||||||
- ✅ Can't simply re-merge after reverting a merge
|
|
||||||
- ✅ Multiple commits can be reverted in one command
|
- ✅ Multiple commits can be reverted in one command
|
||||||
- ✅ Revert preserves complete history for audit trails
|
- ✅ Revert preserves complete history for audit trails
|
||||||
|
|
||||||
|
|||||||
@@ -1,14 +1,14 @@
|
|||||||
#!/usr/bin/env pwsh
|
#!/usr/bin/env pwsh
|
||||||
<#
|
<#
|
||||||
.SYNOPSIS
|
.SYNOPSIS
|
||||||
Resets the Module 05 challenge environment to start fresh.
|
Resets the Module 06 challenge environment to start fresh.
|
||||||
|
|
||||||
.DESCRIPTION
|
.DESCRIPTION
|
||||||
This script removes the challenge directory and re-runs setup.ps1
|
This script removes the challenge directory and re-runs setup.ps1
|
||||||
to create a fresh challenge environment.
|
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
|
# Check if challenge directory exists
|
||||||
if (Test-Path "challenge") {
|
if (Test-Path "challenge") {
|
||||||
|
|||||||
@@ -1,17 +1,17 @@
|
|||||||
#!/usr/bin/env pwsh
|
#!/usr/bin/env pwsh
|
||||||
<#
|
<#
|
||||||
.SYNOPSIS
|
.SYNOPSIS
|
||||||
Sets up the Module 05 challenge environment for learning git revert.
|
Sets up the Module 06 challenge environment for learning git revert.
|
||||||
|
|
||||||
.DESCRIPTION
|
.DESCRIPTION
|
||||||
This script creates a challenge directory with three branches demonstrating
|
This script creates a challenge directory with three branches demonstrating
|
||||||
different revert scenarios:
|
different revert scenarios:
|
||||||
- regular-revert: Basic revert of a single bad commit
|
- regular-revert: Basic revert of a single bad commit at the end
|
||||||
- merge-revert: Reverting a merge commit with -m flag
|
- middle-revert: Reverting a bad commit in the middle of history
|
||||||
- multi-revert: Reverting multiple commits at once
|
- 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
|
# Remove existing challenge directory if it exists
|
||||||
if (Test-Path "challenge") {
|
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
|
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
|
# Switch back to main
|
||||||
git switch $mainBranch | Out-Null
|
git switch $mainBranch | Out-Null
|
||||||
|
|
||||||
# Create merge-revert branch
|
# Create middle-revert branch
|
||||||
git switch -c merge-revert | Out-Null
|
git switch -c middle-revert | Out-Null
|
||||||
|
|
||||||
# Create a feature branch to merge
|
# Good commit: Add validation module
|
||||||
git switch -c feature-auth | Out-Null
|
$validationContent = @"
|
||||||
|
# validation.py - Input validation
|
||||||
|
|
||||||
# Add auth functionality
|
def validate_number(value):
|
||||||
$authContent = @"
|
"""Check if value is a valid number."""
|
||||||
# auth.py - Authentication module
|
try:
|
||||||
|
float(value)
|
||||||
def login(username, password):
|
|
||||||
\"\"\"Login user.\"\"\"
|
|
||||||
print(f"Logging in {username}...")
|
|
||||||
return True
|
return True
|
||||||
|
except ValueError:
|
||||||
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!")
|
|
||||||
return False
|
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 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)
|
# BAD commit: Add broken formatter
|
||||||
$calcContent = @"
|
$formatterContent = @"
|
||||||
# calculator.py - Simple calculator
|
# formatter.py - Output formatting
|
||||||
from auth import login
|
|
||||||
|
|
||||||
def add(a, b):
|
def format_result(result):
|
||||||
"""Add two numbers."""
|
"""BROKEN: Doesn't handle None or errors properly!"""
|
||||||
return a + b
|
return f"Result: {result.upper()}" # This crashes if result is not a string!
|
||||||
|
|
||||||
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
|
|
||||||
"@
|
"@
|
||||||
Set-Content -Path "calculator.py" -Value $calcContent
|
Set-Content -Path "formatter.py" -Value $formatterContent
|
||||||
git add .
|
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
|
# Good commit: Add configuration (depends on validation, not formatter)
|
||||||
git switch merge-revert | Out-Null
|
$configContent = @"
|
||||||
git merge feature-auth --no-ff -m "Merge feature-auth branch" | Out-Null
|
# 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)
|
# SCENARIO 3: Multi Revert (Multiple Bad Commits)
|
||||||
@@ -275,8 +248,8 @@ Set-Location ..
|
|||||||
|
|
||||||
Write-Host "`n=== Setup Complete! ===" -ForegroundColor Green
|
Write-Host "`n=== Setup Complete! ===" -ForegroundColor Green
|
||||||
Write-Host "`nThree revert scenarios have been created:" -ForegroundColor Cyan
|
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 " 1. regular-revert - Revert a bad commit at the end" -ForegroundColor White
|
||||||
Write-Host " 2. merge-revert - Revert a merge commit with -m flag" -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 " 3. multi-revert - Revert multiple bad commits" -ForegroundColor White
|
||||||
Write-Host "`nYou are currently on the 'regular-revert' branch." -ForegroundColor Cyan
|
Write-Host "`nYou are currently on the 'regular-revert' branch." -ForegroundColor Cyan
|
||||||
Write-Host "`nNext steps:" -ForegroundColor Cyan
|
Write-Host "`nNext steps:" -ForegroundColor Cyan
|
||||||
|
|||||||
@@ -1,16 +1,16 @@
|
|||||||
#!/usr/bin/env pwsh
|
#!/usr/bin/env pwsh
|
||||||
<#
|
<#
|
||||||
.SYNOPSIS
|
.SYNOPSIS
|
||||||
Verifies the Module 05 challenge solutions.
|
Verifies the Module 06 challenge solutions.
|
||||||
|
|
||||||
.DESCRIPTION
|
.DESCRIPTION
|
||||||
Checks that all three revert scenarios have been completed correctly:
|
Checks that all three revert scenarios have been completed correctly:
|
||||||
- regular-revert: Single commit reverted
|
- 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
|
- 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
|
$allChecksPassed = $true
|
||||||
$originalDir = Get-Location
|
$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) {
|
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
|
$allChecksPassed = $false
|
||||||
} else {
|
} else {
|
||||||
# Check that a revert commit for the merge exists
|
# Check that a revert commit exists
|
||||||
$revertMerge = git log --oneline --grep="Revert.*Merge" 2>$null
|
$revertCommit = git log --oneline --grep="Revert" 2>$null
|
||||||
if ($revertMerge) {
|
if ($revertCommit) {
|
||||||
Write-Host "[PASS] Merge revert commit found" -ForegroundColor Green
|
Write-Host "[PASS] Revert commit found" -ForegroundColor Green
|
||||||
} else {
|
} else {
|
||||||
Write-Host "[FAIL] No merge revert commit found" -ForegroundColor Red
|
Write-Host "[FAIL] No revert commit found" -ForegroundColor Red
|
||||||
Write-Host "[HINT] Use: git revert -m 1 <merge-commit-hash>" -ForegroundColor Yellow
|
Write-Host "[HINT] Use: git revert <commit-hash>" -ForegroundColor Yellow
|
||||||
$allChecksPassed = $false
|
$allChecksPassed = $false
|
||||||
}
|
}
|
||||||
|
|
||||||
# Check that the original merge commit still exists (revert doesn't erase it)
|
# Check that formatter.py is removed (reverted)
|
||||||
$mergeCommit = git log --merges --oneline --grep="Merge feature-auth" 2>$null
|
if (-not (Test-Path "formatter.py")) {
|
||||||
if ($mergeCommit) {
|
Write-Host "[PASS] Broken formatter.py successfully reverted (file removed)" -ForegroundColor Green
|
||||||
Write-Host "[PASS] Original merge commit still in history (not erased)" -ForegroundColor Green
|
|
||||||
} else {
|
} 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
|
||||||
|
|
||||||
# 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
|
|
||||||
} else {
|
|
||||||
Write-Host "[INFO] auth.py still exists (check if merge was fully reverted)" -ForegroundColor Yellow
|
|
||||||
}
|
|
||||||
|
|
||||||
# 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
|
$allChecksPassed = $false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# 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 "[FAIL] validation.py missing (should still exist)" -ForegroundColor Red
|
||||||
|
$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 "=========================================" -ForegroundColor Green
|
||||||
Write-Host "`nYou've mastered git revert!" -ForegroundColor Cyan
|
Write-Host "`nYou've mastered git revert!" -ForegroundColor Cyan
|
||||||
Write-Host "You now understand:" -ForegroundColor Cyan
|
Write-Host "You now understand:" -ForegroundColor Cyan
|
||||||
Write-Host " ✓ Reverting regular commits safely" -ForegroundColor White
|
Write-Host " ✓ Reverting commits safely without erasing history" -ForegroundColor White
|
||||||
Write-Host " ✓ Reverting merge commits with -m flag" -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 " ✓ Reverting multiple commits at once" -ForegroundColor White
|
||||||
Write-Host " ✓ Preserving history while undoing changes" -ForegroundColor White
|
Write-Host " ✓ Preserving commits before and after the reverted one" -ForegroundColor White
|
||||||
Write-Host "`nReady for Module 06: Git Reset!" -ForegroundColor Green
|
Write-Host "`nReady for Module 07: Git Reset!" -ForegroundColor Green
|
||||||
Write-Host ""
|
Write-Host ""
|
||||||
exit 0
|
exit 0
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
Reference in New Issue
Block a user