refactor: move reset to advanced
This commit is contained in:
717
02-advanced/01-reset/README.md
Normal file
717
02-advanced/01-reset/README.md
Normal file
@@ -0,0 +1,717 @@
|
||||
# Module 06: Git Reset - Dangerous History Rewriting
|
||||
|
||||
## ⚠️ CRITICAL SAFETY WARNING ⚠️
|
||||
|
||||
**Git reset is DESTRUCTIVE and DANGEROUS when misused!**
|
||||
|
||||
Before using `git reset`, always ask yourself:
|
||||
|
||||
```
|
||||
Have I pushed these commits to a remote repository?
|
||||
├─ YES → ❌ DO NOT USE RESET!
|
||||
│ Use git revert instead (Module 05)
|
||||
│ Rewriting pushed history breaks collaboration!
|
||||
│
|
||||
└─ NO → ✅ Proceed with reset (local cleanup only)
|
||||
Choose your mode carefully:
|
||||
--soft (safest), --mixed (moderate), --hard (DANGEROUS)
|
||||
```
|
||||
|
||||
**The Golden Rule:** NEVER reset commits that have been pushed/shared.
|
||||
|
||||
## About This Module
|
||||
|
||||
Welcome to Module 06, where you'll learn the powerful but dangerous `git reset` command. Unlike `git revert` (Module 05) which safely creates new commits, **reset erases commits from history**.
|
||||
|
||||
**Why reset exists:**
|
||||
- ✅ Clean up messy local commit history before pushing
|
||||
- ✅ Undo commits you haven't shared yet
|
||||
- ✅ Unstage files from the staging area
|
||||
- ✅ Recover from mistakes (with reflog)
|
||||
|
||||
**Why reset is dangerous:**
|
||||
- ⚠️ Erases commits permanently (without reflog)
|
||||
- ⚠️ Breaks repositories if used on pushed commits
|
||||
- ⚠️ Can lose work if used incorrectly
|
||||
- ⚠️ Confuses teammates if they have your commits
|
||||
|
||||
**Key principle:** Reset is for polishing LOCAL history before sharing.
|
||||
|
||||
## Learning Objectives
|
||||
|
||||
By completing this module, you will:
|
||||
|
||||
1. Understand the three reset modes: --soft, --mixed, --hard
|
||||
2. Reset commits while keeping changes staged (--soft)
|
||||
3. Reset commits and unstage changes (--mixed)
|
||||
4. Reset commits and discard everything (--hard)
|
||||
5. Know when reset is appropriate (local only!)
|
||||
6. Understand when to use revert instead
|
||||
7. Use reflog to recover from mistakes
|
||||
|
||||
## Prerequisites
|
||||
|
||||
Before starting this module, you should:
|
||||
- Be comfortable with commits and staging (`git add`, `git commit`)
|
||||
- Understand `git revert` from Module 05
|
||||
- **Know the difference between local and pushed commits!**
|
||||
|
||||
## Setup
|
||||
|
||||
Run the setup script to create the challenge environment:
|
||||
|
||||
```powershell
|
||||
./setup.ps1
|
||||
```
|
||||
|
||||
This creates a `challenge/` directory with three branches demonstrating different reset modes:
|
||||
- `soft-reset` - Reset with --soft (keep changes staged)
|
||||
- `mixed-reset` - Reset with --mixed (unstage changes)
|
||||
- `hard-reset` - Reset with --hard (discard everything)
|
||||
|
||||
**Remember:** These are all LOCAL commits that have NEVER been pushed!
|
||||
|
||||
## Understanding Reset Modes
|
||||
|
||||
Git reset has three modes that control what happens to your changes:
|
||||
|
||||
| Mode | Commits | Staging Area | Working Directory |
|
||||
|------|---------|--------------|-------------------|
|
||||
| **--soft** | ✂️ Removed | ✅ Kept (staged) | ✅ Kept |
|
||||
| **--mixed** (default) | ✂️ Removed | ✂️ Cleared | ✅ Kept (unstaged) |
|
||||
| **--hard** | ✂️ Removed | ✂️ Cleared | ✂️ **LOST!** |
|
||||
|
||||
**Visual explanation:**
|
||||
|
||||
```
|
||||
Before reset (3 commits):
|
||||
A → B → C → HEAD
|
||||
|
||||
After git reset --soft HEAD~1:
|
||||
A → B → HEAD
|
||||
↑
|
||||
C's changes are staged
|
||||
|
||||
After git reset --mixed HEAD~1 (or just git reset HEAD~1):
|
||||
A → B → HEAD
|
||||
↑
|
||||
C's changes are unstaged (in working directory)
|
||||
|
||||
After git reset --hard HEAD~1:
|
||||
A → B → HEAD
|
||||
↑
|
||||
C's changes are GONE (discarded completely!)
|
||||
```
|
||||
|
||||
## Challenge 1: Soft Reset (Safest)
|
||||
|
||||
### Scenario
|
||||
|
||||
You committed "feature C" but immediately realized the implementation is wrong. You want to undo the commit but keep the changes staged so you can edit and re-commit them properly.
|
||||
|
||||
**Use case:** Fixing the last commit's message or contents.
|
||||
|
||||
### Your Task
|
||||
|
||||
1. Navigate to the challenge directory:
|
||||
```bash
|
||||
cd challenge
|
||||
```
|
||||
|
||||
2. You should be on the `soft-reset` branch. View the commits:
|
||||
```bash
|
||||
git log --oneline
|
||||
```
|
||||
|
||||
You should see:
|
||||
- "Add feature C - needs better implementation!"
|
||||
- "Add feature B"
|
||||
- "Add feature A"
|
||||
- "Initial project setup"
|
||||
|
||||
3. View the current state:
|
||||
```bash
|
||||
git status
|
||||
# Should be clean
|
||||
```
|
||||
|
||||
4. Reset the last commit with --soft:
|
||||
```bash
|
||||
git reset --soft HEAD~1
|
||||
```
|
||||
|
||||
5. Check what happened:
|
||||
```bash
|
||||
# Commit is gone
|
||||
git log --oneline
|
||||
# Should only show 3 commits now (feature C commit removed)
|
||||
|
||||
# Changes are still staged
|
||||
git status
|
||||
# Should show "Changes to be committed"
|
||||
|
||||
# View the staged changes
|
||||
git diff --cached
|
||||
# Should show feature C code ready to be re-committed
|
||||
```
|
||||
|
||||
### What to Observe
|
||||
|
||||
After `--soft` reset:
|
||||
- ✅ Commit removed from history
|
||||
- ✅ Changes remain in staging area
|
||||
- ✅ Working directory unchanged
|
||||
- ✅ Ready to edit and re-commit
|
||||
|
||||
**When to use --soft:**
|
||||
- Fix the last commit message (though `commit --amend` is simpler)
|
||||
- Combine multiple commits into one
|
||||
- Re-do a commit with better changes
|
||||
|
||||
## Challenge 2: Mixed Reset (Default, Moderate)
|
||||
|
||||
### Scenario
|
||||
|
||||
You committed two experimental features that aren't ready. You want to remove both commits and have the changes back in your working directory (unstaged) so you can review and selectively re-commit them.
|
||||
|
||||
**Use case:** Undoing commits and starting over with more careful staging.
|
||||
|
||||
### Your Task
|
||||
|
||||
1. Switch to the mixed-reset branch:
|
||||
```bash
|
||||
git switch mixed-reset
|
||||
```
|
||||
|
||||
2. View the commits:
|
||||
```bash
|
||||
git log --oneline
|
||||
```
|
||||
|
||||
You should see:
|
||||
- "Add debug mode - REMOVE THIS TOO!"
|
||||
- "Add experimental feature X - REMOVE THIS!"
|
||||
- "Add logging system"
|
||||
- "Add application lifecycle"
|
||||
|
||||
3. Reset the last TWO commits (default is --mixed):
|
||||
```bash
|
||||
git reset HEAD~2
|
||||
# This is equivalent to: git reset --mixed HEAD~2
|
||||
```
|
||||
|
||||
4. Check what happened:
|
||||
```bash
|
||||
# Commits are gone
|
||||
git log --oneline
|
||||
# Should only show 2 commits (lifecycle + logging)
|
||||
|
||||
# NO staged changes
|
||||
git diff --cached
|
||||
# Should be empty
|
||||
|
||||
# Changes are in working directory (unstaged)
|
||||
git status
|
||||
# Should show "Changes not staged for commit"
|
||||
|
||||
# View the unstaged changes
|
||||
git diff
|
||||
# Should show experimental and debug code
|
||||
```
|
||||
|
||||
### What to Observe
|
||||
|
||||
After `--mixed` reset (the default):
|
||||
- ✅ Commits removed from history
|
||||
- ✅ Staging area cleared
|
||||
- ✅ Changes moved to working directory (unstaged)
|
||||
- ✅ Can selectively stage and re-commit parts
|
||||
|
||||
**When to use --mixed (default):**
|
||||
- Undo commits and start over with clean staging
|
||||
- Split one large commit into multiple smaller ones
|
||||
- Review changes before re-committing
|
||||
- Most common reset mode for cleanup
|
||||
|
||||
## Challenge 3: Hard Reset (MOST DANGEROUS!)
|
||||
|
||||
### ⚠️ EXTREME CAUTION REQUIRED ⚠️
|
||||
|
||||
**This will PERMANENTLY DELETE your work!**
|
||||
|
||||
Only use `--hard` when you're absolutely sure you want to throw away changes.
|
||||
|
||||
### Scenario
|
||||
|
||||
You committed completely broken code that you want to discard entirely. There's no salvaging it—you just want it gone.
|
||||
|
||||
**Use case:** Throwing away failed experiments or completely wrong code.
|
||||
|
||||
### Your Task
|
||||
|
||||
1. Switch to the hard-reset branch:
|
||||
```bash
|
||||
git switch hard-reset
|
||||
```
|
||||
|
||||
2. View the commits and the broken code:
|
||||
```bash
|
||||
git log --oneline
|
||||
# Shows "Add broken helper D - DISCARD COMPLETELY!"
|
||||
|
||||
cat utils.py
|
||||
# Shows the broken helper_d function
|
||||
```
|
||||
|
||||
3. Reset the last commit with --hard:
|
||||
```bash
|
||||
git reset --hard HEAD~1
|
||||
```
|
||||
|
||||
**WARNING:** This will permanently discard all changes from that commit!
|
||||
|
||||
4. Check what happened:
|
||||
```bash
|
||||
# Commit is gone
|
||||
git log --oneline
|
||||
# Should only show 2 commits
|
||||
|
||||
# NO staged changes
|
||||
git diff --cached
|
||||
# Empty
|
||||
|
||||
# NO unstaged changes
|
||||
git diff
|
||||
# Empty
|
||||
|
||||
# Working directory clean
|
||||
git status
|
||||
# "nothing to commit, working tree clean"
|
||||
|
||||
# File doesn't have broken code
|
||||
cat utils.py
|
||||
# helper_d is completely gone
|
||||
```
|
||||
|
||||
### What to Observe
|
||||
|
||||
After `--hard` reset:
|
||||
- ✅ Commit removed from history
|
||||
- ✅ Staging area cleared
|
||||
- ✅ Working directory reset to match
|
||||
- ⚠️ All changes from that commit PERMANENTLY DELETED
|
||||
|
||||
**When to use --hard:**
|
||||
- Discarding failed experiments completely
|
||||
- Throwing away work you don't want (CAREFUL!)
|
||||
- Cleaning up after mistakes (use reflog to recover if needed)
|
||||
- Resetting to a known good state
|
||||
|
||||
**⚠️ WARNING:** Files in the discarded commit are NOT gone forever—they're still in reflog for about 90 days. See "Recovery with Reflog" section below.
|
||||
|
||||
## Understanding HEAD~N Syntax
|
||||
|
||||
When resetting, you specify where to reset to:
|
||||
|
||||
```bash
|
||||
# Reset to the commit before HEAD
|
||||
git reset HEAD~1
|
||||
|
||||
# Reset to 2 commits before HEAD
|
||||
git reset HEAD~2
|
||||
|
||||
# Reset to 3 commits before HEAD
|
||||
git reset HEAD~3
|
||||
|
||||
# Reset to a specific commit hash
|
||||
git reset abc123
|
||||
|
||||
# Reset to a branch
|
||||
git reset main
|
||||
```
|
||||
|
||||
**Visualization:**
|
||||
|
||||
```
|
||||
HEAD~3 HEAD~2 HEAD~1 HEAD
|
||||
↓ ↓ ↓ ↓
|
||||
A → B → C → D → E
|
||||
↑
|
||||
Current commit
|
||||
```
|
||||
|
||||
- `git reset HEAD~1` moves HEAD from E to D
|
||||
- `git reset HEAD~2` moves HEAD from E to C
|
||||
- `git reset abc123` moves HEAD to that specific commit
|
||||
|
||||
## Verification
|
||||
|
||||
Verify your solutions by running the verification script:
|
||||
|
||||
```bash
|
||||
cd .. # Return to module directory
|
||||
./verify.ps1
|
||||
```
|
||||
|
||||
The script checks that:
|
||||
- ✅ Commits were reset (count decreased)
|
||||
- ✅ --soft: Changes remain staged
|
||||
- ✅ --mixed: Changes are unstaged
|
||||
- ✅ --hard: Everything is clean
|
||||
|
||||
## Recovery with Reflog
|
||||
|
||||
**Good news:** Even `--hard` reset doesn't immediately destroy commits!
|
||||
|
||||
Git keeps a "reflog" (reference log) of where HEAD has been for about 90 days. You can use this to recover "lost" commits.
|
||||
|
||||
### How to Recover from a Reset
|
||||
|
||||
1. View the reflog:
|
||||
```bash
|
||||
git reflog
|
||||
```
|
||||
|
||||
Output example:
|
||||
```
|
||||
abc123 HEAD@{0}: reset: moving to HEAD~1
|
||||
def456 HEAD@{1}: commit: Add broken helper D
|
||||
...
|
||||
```
|
||||
|
||||
2. Find the commit you want to recover (def456 in this example)
|
||||
|
||||
3. Reset back to it:
|
||||
```bash
|
||||
git reset def456
|
||||
# Or use the reflog reference:
|
||||
git reset HEAD@{1}
|
||||
```
|
||||
|
||||
4. Your "lost" commit is back!
|
||||
|
||||
### Reflog Safety Net
|
||||
|
||||
**Important:**
|
||||
- Reflog entries expire after ~90 days (configurable)
|
||||
- Reflog is LOCAL to your repository (not shared)
|
||||
- `git gc` can clean up old reflog entries
|
||||
- If you really lose a commit, check reflog first!
|
||||
|
||||
**Pro tip:** Before doing dangerous operations, note your current commit hash:
|
||||
```bash
|
||||
git log --oneline | head -1
|
||||
# abc123 Current work
|
||||
```
|
||||
|
||||
## When to Use Git Reset
|
||||
|
||||
Use `git reset` when:
|
||||
|
||||
- ✅ **Commits are LOCAL only** (never pushed)
|
||||
- ✅ **Cleaning up messy history** before sharing
|
||||
- ✅ **Undoing recent commits** you don't want
|
||||
- ✅ **Combining commits** into one clean commit
|
||||
- ✅ **Unstaging files** (mixed mode)
|
||||
- ✅ **Polishing commit history** before pull request
|
||||
|
||||
**Golden Rule:** Only reset commits that are local to your machine!
|
||||
|
||||
## When NOT to Use Git Reset
|
||||
|
||||
DO NOT use `git reset` when:
|
||||
|
||||
- ❌ **Commits are pushed/shared** with others
|
||||
- ❌ **Teammates have your commits** (breaks their repos)
|
||||
- ❌ **In public repositories** (use revert instead)
|
||||
- ❌ **Unsure if pushed** (check `git log origin/main`)
|
||||
- ❌ **On main/master branch** after push
|
||||
- ❌ **Need audit trail** of changes
|
||||
|
||||
**Use git revert instead** (Module 05) for pushed commits!
|
||||
|
||||
## Decision Tree: Reset vs Revert
|
||||
|
||||
```
|
||||
Need to undo a commit?
|
||||
│
|
||||
├─ Have you pushed this commit?
|
||||
│ │
|
||||
│ ├─ YES → Use git revert (Module 05)
|
||||
│ │ Safe for shared history
|
||||
│ │ Preserves complete audit trail
|
||||
│ │
|
||||
│ └─ NO → Can use git reset (local only)
|
||||
│ │
|
||||
│ ├─ Want to keep changes?
|
||||
│ │ │
|
||||
│ │ ├─ Keep staged → git reset --soft
|
||||
│ │ └─ Keep unstaged → git reset --mixed
|
||||
│ │
|
||||
│ └─ Discard everything? → git reset --hard
|
||||
│ (CAREFUL!)
|
||||
```
|
||||
|
||||
## Reset vs Revert vs Rebase
|
||||
|
||||
| Command | History | Safety | Use Case |
|
||||
|---------|---------|--------|----------|
|
||||
| **reset** | Erases | ⚠️ Dangerous | Local cleanup before push |
|
||||
| **revert** | Preserves | ✅ Safe | Undo pushed commits |
|
||||
| **rebase** | Rewrites | ⚠️ Dangerous | Polish history before push |
|
||||
|
||||
**This module teaches reset.** You learned revert in Module 05.
|
||||
|
||||
## Command Reference
|
||||
|
||||
### Basic Reset
|
||||
|
||||
```bash
|
||||
# Reset last commit, keep changes staged
|
||||
git reset --soft HEAD~1
|
||||
|
||||
# Reset last commit, unstage changes (default)
|
||||
git reset HEAD~1
|
||||
git reset --mixed HEAD~1 # Same as above
|
||||
|
||||
# Reset last commit, discard everything (DANGEROUS!)
|
||||
git reset --hard HEAD~1
|
||||
|
||||
# Reset multiple commits
|
||||
git reset --soft HEAD~3 # Last 3 commits
|
||||
|
||||
# Reset to specific commit
|
||||
git reset --soft abc123
|
||||
```
|
||||
|
||||
### Unstaging Files
|
||||
|
||||
```bash
|
||||
# Unstage a specific file (common use of reset)
|
||||
git reset HEAD filename.txt
|
||||
|
||||
# Unstage all files
|
||||
git reset HEAD .
|
||||
|
||||
# This is the same as:
|
||||
git restore --staged filename.txt # Modern syntax
|
||||
```
|
||||
|
||||
### Reflog and Recovery
|
||||
|
||||
```bash
|
||||
# View reflog
|
||||
git reflog
|
||||
|
||||
# Recover from reset
|
||||
git reset --hard HEAD@{1}
|
||||
git reset --hard abc123
|
||||
```
|
||||
|
||||
### Check Before Reset
|
||||
|
||||
```bash
|
||||
# Check if commits are pushed
|
||||
git log origin/main..HEAD
|
||||
# If output is empty, commits are pushed (DO NOT RESET)
|
||||
# If output shows commits, they're local (safe to reset)
|
||||
|
||||
# Another way to check
|
||||
git log --oneline --graph --all
|
||||
# Look for origin/main marker
|
||||
```
|
||||
|
||||
## Common Mistakes
|
||||
|
||||
### 1. Resetting Pushed Commits
|
||||
|
||||
```bash
|
||||
# ❌ NEVER do this if you've pushed!
|
||||
git push
|
||||
# ... time passes ...
|
||||
git reset --hard HEAD~3 # BREAKS teammate repos!
|
||||
|
||||
# ✅ Do this instead
|
||||
git revert HEAD~3..HEAD # Safe for shared history
|
||||
```
|
||||
|
||||
### 2. Using --hard Without Thinking
|
||||
|
||||
```bash
|
||||
# ❌ Dangerous - loses work!
|
||||
git reset --hard HEAD~1
|
||||
|
||||
# ✅ Better - keep changes to review
|
||||
git reset --mixed HEAD~1
|
||||
# Now you can review changes and decide
|
||||
```
|
||||
|
||||
### 3. Resetting Without Checking If Pushed
|
||||
|
||||
```bash
|
||||
# ❌ Risky - are these commits pushed?
|
||||
git reset HEAD~5
|
||||
|
||||
# ✅ Check first
|
||||
git log origin/main..HEAD # Local commits only
|
||||
git reset HEAD~5 # Now safe if output showed commits
|
||||
```
|
||||
|
||||
### 4. Forgetting Reflog Exists
|
||||
|
||||
```bash
|
||||
# ❌ Panic after accidental --hard reset
|
||||
# "I lost my work!"
|
||||
|
||||
# ✅ Check reflog first!
|
||||
git reflog # Find the "lost" commit
|
||||
git reset --hard HEAD@{1} # Recover it
|
||||
```
|
||||
|
||||
## Best Practices
|
||||
|
||||
1. **Always check if commits are pushed before reset:**
|
||||
```bash
|
||||
git log origin/main..HEAD
|
||||
```
|
||||
|
||||
2. **Prefer --mixed over --hard:**
|
||||
- You can always discard changes later
|
||||
- Hard to recover if you use --hard by mistake
|
||||
|
||||
3. **Commit often locally, reset before push:**
|
||||
- Make many small local commits
|
||||
- Reset/squash into clean commits before pushing
|
||||
|
||||
4. **Use descriptive commit messages even for local commits:**
|
||||
- Helps when reviewing before reset
|
||||
- Useful when checking reflog
|
||||
|
||||
5. **Know your escape hatch:**
|
||||
```bash
|
||||
git reflog # Your safety net!
|
||||
```
|
||||
|
||||
6. **Communicate with team:**
|
||||
- NEVER reset shared branches (main, develop, etc.)
|
||||
- Only reset your personal feature branches
|
||||
- Only before pushing!
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### "I accidentally reset with --hard and lost work!"
|
||||
|
||||
**Solution:** Check reflog:
|
||||
```bash
|
||||
git reflog
|
||||
# Find the commit before your reset
|
||||
git reset --hard HEAD@{1} # Or the commit hash
|
||||
```
|
||||
|
||||
**Prevention:** Always use --mixed first, then discard if really needed.
|
||||
|
||||
### "I reset but teammates still have my commits"
|
||||
|
||||
**Problem:** You reset and pushed with --force after they pulled.
|
||||
|
||||
**Impact:** Their repository is now broken/inconsistent.
|
||||
|
||||
**Solution:** Communicate! They need to:
|
||||
```bash
|
||||
git fetch
|
||||
git reset --hard origin/main # Or whatever branch
|
||||
```
|
||||
|
||||
**Prevention:** NEVER reset pushed commits!
|
||||
|
||||
### "Reset didn't do what I expected"
|
||||
|
||||
**Issue:** Wrong mode or wrong HEAD~N count.
|
||||
|
||||
**Solution:** Check current state:
|
||||
```bash
|
||||
git status
|
||||
git diff
|
||||
git diff --cached
|
||||
git log --oneline
|
||||
```
|
||||
|
||||
Undo the reset:
|
||||
```bash
|
||||
git reflog
|
||||
git reset HEAD@{1} # Go back to before your reset
|
||||
```
|
||||
|
||||
### "Can't reset - 'fatal: ambiguous argument HEAD~1'"
|
||||
|
||||
**Issue:** No commits to reset (probably first commit).
|
||||
|
||||
**Solution:** You can't reset before the first commit. If you want to remove the first commit entirely:
|
||||
```bash
|
||||
rm -rf .git # Nuclear option - deletes entire repo
|
||||
git init # Start over
|
||||
```
|
||||
|
||||
## Advanced: Reset Internals
|
||||
|
||||
Understanding what reset does under the hood:
|
||||
|
||||
```bash
|
||||
# Reset moves the branch pointer
|
||||
# Before:
|
||||
main → A → B → C (HEAD)
|
||||
|
||||
# After git reset --soft HEAD~1:
|
||||
main → A → B (HEAD)
|
||||
↑
|
||||
C still exists in reflog, just not in branch history
|
||||
|
||||
# The commit object C is still in .git/objects
|
||||
# It's just unreachable from any branch
|
||||
```
|
||||
|
||||
**Key insight:** Reset moves the HEAD and branch pointers backward. The commits still exist temporarily in reflog until garbage collection.
|
||||
|
||||
## Going Further
|
||||
|
||||
Now that you understand reset, you're ready for:
|
||||
|
||||
- **Module 07: Git Stash** - Temporarily save uncommitted work
|
||||
- **Module 08: Multiplayer Git** - Collaborate with complex workflows
|
||||
- **Interactive Rebase** - Advanced history polishing (beyond this workshop)
|
||||
|
||||
## Summary
|
||||
|
||||
You've learned:
|
||||
|
||||
- ✅ `git reset` rewrites history by moving HEAD backward
|
||||
- ✅ `--soft` keeps changes staged (safest)
|
||||
- ✅ `--mixed` (default) unstages changes
|
||||
- ✅ `--hard` discards everything (most dangerous)
|
||||
- ✅ NEVER reset pushed/shared commits
|
||||
- ✅ Use reflog to recover from mistakes
|
||||
- ✅ Check if commits are pushed before resetting
|
||||
- ✅ Use revert (Module 05) for shared commits
|
||||
|
||||
**The Critical Rule:** Reset is for LOCAL commits ONLY. Once you push, use revert!
|
||||
|
||||
## Next Steps
|
||||
|
||||
1. Complete all three challenge scenarios
|
||||
2. Run `./verify.ps1` to check your solutions
|
||||
3. Practice checking if commits are pushed before reset
|
||||
4. Move on to Module 07: Git Stash
|
||||
|
||||
---
|
||||
|
||||
**⚠️ FINAL REMINDER ⚠️**
|
||||
|
||||
**Before any `git reset` command, ask yourself:**
|
||||
|
||||
> "Have I pushed these commits?"
|
||||
|
||||
If YES → Use `git revert` instead!
|
||||
|
||||
If NO → Proceed carefully, choose the right mode.
|
||||
|
||||
**When in doubt, use --mixed instead of --hard!**
|
||||
24
02-advanced/01-reset/reset.ps1
Normal file
24
02-advanced/01-reset/reset.ps1
Normal file
@@ -0,0 +1,24 @@
|
||||
#!/usr/bin/env pwsh
|
||||
<#
|
||||
.SYNOPSIS
|
||||
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 06: Git Reset Challenge ===" -ForegroundColor Cyan
|
||||
|
||||
# Check if challenge directory exists
|
||||
if (Test-Path "challenge") {
|
||||
Write-Host "Removing existing challenge directory..." -ForegroundColor Yellow
|
||||
Remove-Item -Recurse -Force "challenge"
|
||||
Write-Host "[OK] Challenge directory removed" -ForegroundColor Green
|
||||
} else {
|
||||
Write-Host "[INFO] No existing challenge directory found" -ForegroundColor Yellow
|
||||
}
|
||||
|
||||
# Run setup to create fresh environment
|
||||
Write-Host "`nRunning setup to create fresh challenge environment..." -ForegroundColor Cyan
|
||||
& "$PSScriptRoot/setup.ps1"
|
||||
359
02-advanced/01-reset/setup.ps1
Normal file
359
02-advanced/01-reset/setup.ps1
Normal file
@@ -0,0 +1,359 @@
|
||||
#!/usr/bin/env pwsh
|
||||
<#
|
||||
.SYNOPSIS
|
||||
Sets up the Module 06 challenge environment for learning git reset.
|
||||
|
||||
.DESCRIPTION
|
||||
This script creates a challenge directory with three branches demonstrating
|
||||
different reset scenarios:
|
||||
- soft-reset: Reset with --soft (keeps changes staged)
|
||||
- mixed-reset: Reset with --mixed (unstages changes)
|
||||
- hard-reset: Reset with --hard (discards everything) + reflog recovery
|
||||
#>
|
||||
|
||||
Write-Host "`n=== Setting up Module 06: Git Reset Challenge ===" -ForegroundColor Cyan
|
||||
Write-Host "⚠️ WARNING: Git reset is DANGEROUS - use with extreme caution! ⚠️" -ForegroundColor Red
|
||||
|
||||
# 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
|
||||
|
||||
# Configure git for this repository
|
||||
git config user.name "Workshop Student"
|
||||
git config user.email "student@example.com"
|
||||
|
||||
# Detect the default branch name after first commit (created below)
|
||||
# Will be detected after the initial commit
|
||||
|
||||
# ============================================================================
|
||||
# Create initial commit (shared by all scenarios)
|
||||
# ============================================================================
|
||||
$readmeContent = @"
|
||||
# Git Reset Practice
|
||||
|
||||
This repository contains practice scenarios for learning git reset.
|
||||
"@
|
||||
Set-Content -Path "README.md" -Value $readmeContent
|
||||
git add .
|
||||
git commit -m "Initial commit" | Out-Null
|
||||
|
||||
# Detect the main branch name after first commit
|
||||
$mainBranch = git branch --show-current
|
||||
if (-not $mainBranch) {
|
||||
$mainBranch = git config --get init.defaultBranch
|
||||
if (-not $mainBranch) { $mainBranch = "main" }
|
||||
}
|
||||
Write-Host "Default branch detected: $mainBranch" -ForegroundColor Yellow
|
||||
|
||||
# ============================================================================
|
||||
# SCENARIO 1: Soft Reset (--soft)
|
||||
# ============================================================================
|
||||
Write-Host "`nScenario 1: Creating soft-reset branch..." -ForegroundColor Cyan
|
||||
|
||||
# Create soft-reset branch from initial commit
|
||||
git switch -c soft-reset | Out-Null
|
||||
|
||||
# Build up scenario 1 commits
|
||||
$projectContent = @"
|
||||
# project.py - Main project file
|
||||
|
||||
def initialize():
|
||||
"""Initialize the project."""
|
||||
print("Project initialized")
|
||||
|
||||
def main():
|
||||
initialize()
|
||||
print("Running application...")
|
||||
"@
|
||||
Set-Content -Path "project.py" -Value $projectContent
|
||||
git add .
|
||||
git commit -m "Initial project setup" | Out-Null
|
||||
|
||||
# Good commit: Add feature A
|
||||
$projectContent = @"
|
||||
# project.py - Main project file
|
||||
|
||||
def initialize():
|
||||
"""Initialize the project."""
|
||||
print("Project initialized")
|
||||
|
||||
def feature_a():
|
||||
"""Feature A implementation."""
|
||||
print("Feature A is working")
|
||||
|
||||
def main():
|
||||
initialize()
|
||||
feature_a()
|
||||
print("Running application...")
|
||||
"@
|
||||
Set-Content -Path "project.py" -Value $projectContent
|
||||
git add .
|
||||
git commit -m "Add feature A" | Out-Null
|
||||
|
||||
# Good commit: Add feature B
|
||||
$projectContent = @"
|
||||
# project.py - Main project file
|
||||
|
||||
def initialize():
|
||||
"""Initialize the project."""
|
||||
print("Project initialized")
|
||||
|
||||
def feature_a():
|
||||
"""Feature A implementation."""
|
||||
print("Feature A is working")
|
||||
|
||||
def feature_b():
|
||||
"""Feature B implementation."""
|
||||
print("Feature B is working")
|
||||
|
||||
def main():
|
||||
initialize()
|
||||
feature_a()
|
||||
feature_b()
|
||||
print("Running application...")
|
||||
"@
|
||||
Set-Content -Path "project.py" -Value $projectContent
|
||||
git add .
|
||||
git commit -m "Add feature B" | Out-Null
|
||||
|
||||
# BAD commit: Add feature C (wrong implementation)
|
||||
$projectContent = @"
|
||||
# project.py - Main project file
|
||||
|
||||
def initialize():
|
||||
"""Initialize the project."""
|
||||
print("Project initialized")
|
||||
|
||||
def feature_a():
|
||||
"""Feature A implementation."""
|
||||
print("Feature A is working")
|
||||
|
||||
def feature_b():
|
||||
"""Feature B implementation."""
|
||||
print("Feature B is working")
|
||||
|
||||
def feature_c():
|
||||
"""Feature C implementation - WRONG!"""
|
||||
print("Feature C has bugs!") # This needs to be re-implemented
|
||||
|
||||
def main():
|
||||
initialize()
|
||||
feature_a()
|
||||
feature_b()
|
||||
feature_c()
|
||||
print("Running application...")
|
||||
"@
|
||||
Set-Content -Path "project.py" -Value $projectContent
|
||||
git add .
|
||||
git commit -m "Add feature C - needs better implementation!" | Out-Null
|
||||
|
||||
Write-Host "[CREATED] soft-reset branch with commit to reset --soft" -ForegroundColor Green
|
||||
|
||||
# ============================================================================
|
||||
# SCENARIO 2: Mixed Reset (--mixed, default)
|
||||
# ============================================================================
|
||||
Write-Host "`nScenario 2: Creating mixed-reset branch..." -ForegroundColor Cyan
|
||||
|
||||
# Switch back to initial commit and create mixed-reset branch
|
||||
git switch $mainBranch | Out-Null
|
||||
git switch -c mixed-reset | Out-Null
|
||||
|
||||
# Build up scenario 2 commits
|
||||
$appContent = @"
|
||||
# app.py - Application entry point
|
||||
|
||||
def start():
|
||||
"""Start the application."""
|
||||
print("Application started")
|
||||
|
||||
def stop():
|
||||
"""Stop the application."""
|
||||
print("Application stopped")
|
||||
"@
|
||||
Set-Content -Path "app.py" -Value $appContent
|
||||
git add .
|
||||
git commit -m "Add application lifecycle" | Out-Null
|
||||
|
||||
# Good commit: Add logging
|
||||
$appContent = @"
|
||||
# app.py - Application entry point
|
||||
|
||||
def log(message):
|
||||
"""Log a message."""
|
||||
print(f"[LOG] {message}")
|
||||
|
||||
def start():
|
||||
"""Start the application."""
|
||||
log("Application started")
|
||||
|
||||
def stop():
|
||||
"""Stop the application."""
|
||||
log("Application stopped")
|
||||
"@
|
||||
Set-Content -Path "app.py" -Value $appContent
|
||||
git add .
|
||||
git commit -m "Add logging system" | Out-Null
|
||||
|
||||
# BAD commit 1: Add experimental feature X
|
||||
$appContent = @"
|
||||
# app.py - Application entry point
|
||||
|
||||
def log(message):
|
||||
"""Log a message."""
|
||||
print(f"[LOG] {message}")
|
||||
|
||||
def experimental_feature_x():
|
||||
"""Experimental feature - NOT READY!"""
|
||||
log("Feature X is experimental and buggy")
|
||||
|
||||
def start():
|
||||
"""Start the application."""
|
||||
log("Application started")
|
||||
experimental_feature_x()
|
||||
|
||||
def stop():
|
||||
"""Stop the application."""
|
||||
log("Application stopped")
|
||||
"@
|
||||
Set-Content -Path "app.py" -Value $appContent
|
||||
git add .
|
||||
git commit -m "Add experimental feature X - REMOVE THIS!" | Out-Null
|
||||
|
||||
# BAD commit 2: Add debug mode (also not ready)
|
||||
$appContent = @"
|
||||
# app.py - Application entry point
|
||||
|
||||
DEBUG_MODE = True # Should not be committed!
|
||||
|
||||
def log(message):
|
||||
"""Log a message."""
|
||||
print(f"[LOG] {message}")
|
||||
|
||||
def experimental_feature_x():
|
||||
"""Experimental feature - NOT READY!"""
|
||||
log("Feature X is experimental and buggy")
|
||||
|
||||
def start():
|
||||
"""Start the application."""
|
||||
if DEBUG_MODE:
|
||||
log("DEBUG MODE ACTIVE!")
|
||||
log("Application started")
|
||||
experimental_feature_x()
|
||||
|
||||
def stop():
|
||||
"""Stop the application."""
|
||||
log("Application stopped")
|
||||
"@
|
||||
Set-Content -Path "app.py" -Value $appContent
|
||||
git add .
|
||||
git commit -m "Add debug mode - REMOVE THIS TOO!" | Out-Null
|
||||
|
||||
Write-Host "[CREATED] mixed-reset branch with commits to reset --mixed" -ForegroundColor Green
|
||||
|
||||
# ============================================================================
|
||||
# SCENARIO 3: Hard Reset (--hard) + Reflog Recovery
|
||||
# ============================================================================
|
||||
Write-Host "`nScenario 3: Creating hard-reset branch..." -ForegroundColor Cyan
|
||||
|
||||
# Switch back to main and create hard-reset branch
|
||||
git switch $mainBranch | Out-Null
|
||||
git switch -c hard-reset | Out-Null
|
||||
|
||||
# Reset to basic state
|
||||
$utilsContent = @"
|
||||
# utils.py - Utility functions
|
||||
|
||||
def helper_a():
|
||||
"""Helper function A."""
|
||||
return "Helper A"
|
||||
|
||||
def helper_b():
|
||||
"""Helper function B."""
|
||||
return "Helper B"
|
||||
"@
|
||||
Set-Content -Path "utils.py" -Value $utilsContent
|
||||
git add .
|
||||
git commit -m "Add utility helpers" | Out-Null
|
||||
|
||||
# Good commit: Add helper C
|
||||
$utilsContent = @"
|
||||
# utils.py - Utility functions
|
||||
|
||||
def helper_a():
|
||||
"""Helper function A."""
|
||||
return "Helper A"
|
||||
|
||||
def helper_b():
|
||||
"""Helper function B."""
|
||||
return "Helper B"
|
||||
|
||||
def helper_c():
|
||||
"""Helper function C."""
|
||||
return "Helper C"
|
||||
"@
|
||||
Set-Content -Path "utils.py" -Value $utilsContent
|
||||
git add .
|
||||
git commit -m "Add helper C" | Out-Null
|
||||
|
||||
# BAD commit: Add broken helper D (completely wrong)
|
||||
$utilsContent = @"
|
||||
# utils.py - Utility functions
|
||||
|
||||
def helper_a():
|
||||
"""Helper function A."""
|
||||
return "Helper A"
|
||||
|
||||
def helper_b():
|
||||
"""Helper function B."""
|
||||
return "Helper B"
|
||||
|
||||
def helper_c():
|
||||
"""Helper function C."""
|
||||
return "Helper C"
|
||||
|
||||
def helper_d():
|
||||
"""COMPLETELY BROKEN - throw away!"""
|
||||
# This is all wrong and needs to be discarded
|
||||
broken_code = "This doesn't even make sense"
|
||||
return broken_code.nonexistent_method() # Will crash!
|
||||
"@
|
||||
Set-Content -Path "utils.py" -Value $utilsContent
|
||||
git add .
|
||||
git commit -m "Add broken helper D - DISCARD COMPLETELY!" | Out-Null
|
||||
|
||||
Write-Host "[CREATED] hard-reset branch with commit to reset --hard" -ForegroundColor Green
|
||||
|
||||
# ============================================================================
|
||||
# Return to soft-reset to start
|
||||
# ============================================================================
|
||||
git switch soft-reset | Out-Null
|
||||
|
||||
# Return to module directory
|
||||
Set-Location ..
|
||||
|
||||
Write-Host "`n=== Setup Complete! ===`n" -ForegroundColor Green
|
||||
Write-Host "Three reset scenarios have been created:" -ForegroundColor Cyan
|
||||
Write-Host " 1. soft-reset - Reset --soft (keep changes staged)" -ForegroundColor White
|
||||
Write-Host " 2. mixed-reset - Reset --mixed (unstage changes)" -ForegroundColor White
|
||||
Write-Host " 3. hard-reset - Reset --hard (discard everything) + reflog recovery" -ForegroundColor White
|
||||
Write-Host "`n⚠️ CRITICAL SAFETY REMINDER ⚠️" -ForegroundColor Red
|
||||
Write-Host "NEVER use git reset on commits that have been PUSHED!" -ForegroundColor Red
|
||||
Write-Host "These scenarios are LOCAL ONLY for practice." -ForegroundColor Yellow
|
||||
Write-Host "`nYou are currently on the 'soft-reset' branch." -ForegroundColor Cyan
|
||||
Write-Host "`nNext steps:" -ForegroundColor Cyan
|
||||
Write-Host " 1. cd challenge" -ForegroundColor White
|
||||
Write-Host " 2. Read the README.md for detailed instructions" -ForegroundColor White
|
||||
Write-Host " 3. Complete each reset challenge" -ForegroundColor White
|
||||
Write-Host " 4. Run '..\\verify.ps1' to check your solutions" -ForegroundColor White
|
||||
Write-Host ""
|
||||
231
02-advanced/01-reset/verify.ps1
Normal file
231
02-advanced/01-reset/verify.ps1
Normal file
@@ -0,0 +1,231 @@
|
||||
#!/usr/bin/env pwsh
|
||||
<#
|
||||
.SYNOPSIS
|
||||
Verifies the Module 06 challenge solutions.
|
||||
|
||||
.DESCRIPTION
|
||||
Checks that all three reset scenarios have been completed correctly:
|
||||
- soft-reset: Commit reset but changes remain staged
|
||||
- mixed-reset: Commits reset and changes unstaged
|
||||
- hard-reset: Everything reset and discarded
|
||||
#>
|
||||
|
||||
Write-Host "`n=== Verifying Module 06: Git Reset Solutions ===" -ForegroundColor Cyan
|
||||
Write-Host "⚠️ Remember: NEVER reset pushed commits! ⚠️" -ForegroundColor Red
|
||||
|
||||
$allChecksPassed = $true
|
||||
$originalDir = Get-Location
|
||||
|
||||
# Check if challenge directory exists
|
||||
if (-not (Test-Path "challenge")) {
|
||||
Write-Host "[FAIL] Challenge directory not found. Run setup.ps1 first." -ForegroundColor Red
|
||||
exit 1
|
||||
}
|
||||
|
||||
Set-Location "challenge"
|
||||
|
||||
# Check if git repository exists
|
||||
if (-not (Test-Path ".git")) {
|
||||
Write-Host "[FAIL] Not a git repository. Run setup.ps1 first." -ForegroundColor Red
|
||||
Set-Location $originalDir
|
||||
exit 1
|
||||
}
|
||||
|
||||
# ============================================================================
|
||||
# SCENARIO 1: Soft Reset Verification
|
||||
# ============================================================================
|
||||
Write-Host "`n=== Scenario 1: Soft Reset ===`n" -ForegroundColor Cyan
|
||||
|
||||
git switch soft-reset 2>&1 | Out-Null
|
||||
|
||||
if ($LASTEXITCODE -ne 0) {
|
||||
Write-Host "[FAIL] soft-reset branch not found" -ForegroundColor Red
|
||||
$allChecksPassed = $false
|
||||
} else {
|
||||
# Count commits (should be 4: Initial + project setup + feature A + feature B)
|
||||
$commitCount = [int](git rev-list --count HEAD 2>$null)
|
||||
|
||||
if ($commitCount -eq 4) {
|
||||
Write-Host "[PASS] Commit count is 4 (feature C commit was reset)" -ForegroundColor Green
|
||||
} else {
|
||||
Write-Host "[FAIL] Expected 4 commits, found $commitCount" -ForegroundColor Red
|
||||
Write-Host "[HINT] Use: git reset --soft HEAD~1" -ForegroundColor Yellow
|
||||
$allChecksPassed = $false
|
||||
}
|
||||
|
||||
# Check if changes are staged
|
||||
$stagedChanges = git diff --cached --name-only 2>$null
|
||||
if ($stagedChanges) {
|
||||
Write-Host "[PASS] Changes are staged (feature C code in staging area)" -ForegroundColor Green
|
||||
|
||||
# Verify the staged changes contain feature C code
|
||||
$stagedContent = git diff --cached 2>$null
|
||||
if ($stagedContent -match "feature_c") {
|
||||
Write-Host "[PASS] Staged changes contain feature C code" -ForegroundColor Green
|
||||
} else {
|
||||
Write-Host "[INFO] Staged changes don't seem to contain feature C" -ForegroundColor Yellow
|
||||
}
|
||||
} else {
|
||||
Write-Host "[FAIL] No staged changes found" -ForegroundColor Red
|
||||
Write-Host "[HINT] After --soft reset, changes should remain staged" -ForegroundColor Yellow
|
||||
$allChecksPassed = $false
|
||||
}
|
||||
|
||||
# Check working directory has no unstaged changes to tracked files
|
||||
$unstagedChanges = git diff --name-only 2>$null
|
||||
if (-not $unstagedChanges) {
|
||||
Write-Host "[PASS] No unstaged changes (all changes are staged)" -ForegroundColor Green
|
||||
} else {
|
||||
Write-Host "[INFO] Found unstaged changes (expected only staged changes)" -ForegroundColor Yellow
|
||||
}
|
||||
}
|
||||
|
||||
# ============================================================================
|
||||
# SCENARIO 2: Mixed Reset Verification
|
||||
# ============================================================================
|
||||
Write-Host "`n=== Scenario 2: Mixed Reset ===`n" -ForegroundColor Cyan
|
||||
|
||||
git switch mixed-reset 2>&1 | Out-Null
|
||||
|
||||
if ($LASTEXITCODE -ne 0) {
|
||||
Write-Host "[FAIL] mixed-reset branch not found" -ForegroundColor Red
|
||||
$allChecksPassed = $false
|
||||
} else {
|
||||
# Count commits (should be 3: Initial + lifecycle + logging, bad commits removed)
|
||||
$commitCount = [int](git rev-list --count HEAD 2>$null)
|
||||
|
||||
if ($commitCount -eq 3) {
|
||||
Write-Host "[PASS] Commit count is 3 (both bad commits were reset)" -ForegroundColor Green
|
||||
} elseif ($commitCount -eq 4) {
|
||||
Write-Host "[INFO] Commit count is 4 (one commit reset, need to reset one more)" -ForegroundColor Yellow
|
||||
Write-Host "[HINT] Use: git reset HEAD~1 (or git reset --mixed HEAD~1)" -ForegroundColor Yellow
|
||||
$allChecksPassed = $false
|
||||
} else {
|
||||
Write-Host "[FAIL] Expected 3 commits, found $commitCount" -ForegroundColor Red
|
||||
Write-Host "[HINT] Use: git reset --mixed HEAD~2 to remove both bad commits" -ForegroundColor Yellow
|
||||
$allChecksPassed = $false
|
||||
}
|
||||
|
||||
# Check that there are NO staged changes
|
||||
$stagedChanges = git diff --cached --name-only 2>$null
|
||||
if (-not $stagedChanges) {
|
||||
Write-Host "[PASS] No staged changes (--mixed unstages everything)" -ForegroundColor Green
|
||||
} else {
|
||||
Write-Host "[FAIL] Found staged changes (--mixed should unstage)" -ForegroundColor Red
|
||||
Write-Host "[HINT] After --mixed reset, changes should be unstaged" -ForegroundColor Yellow
|
||||
$allChecksPassed = $false
|
||||
}
|
||||
|
||||
# Check that there ARE unstaged changes in working directory
|
||||
$unstagedChanges = git diff --name-only 2>$null
|
||||
if ($unstagedChanges) {
|
||||
Write-Host "[PASS] Unstaged changes present in working directory" -ForegroundColor Green
|
||||
|
||||
# Verify unstaged changes contain the experimental/debug code
|
||||
$workingContent = git diff 2>$null
|
||||
if ($workingContent -match "experimental|DEBUG") {
|
||||
Write-Host "[PASS] Unstaged changes contain the reset code" -ForegroundColor Green
|
||||
} else {
|
||||
Write-Host "[INFO] Unstaged changes don't contain expected code" -ForegroundColor Yellow
|
||||
}
|
||||
} else {
|
||||
Write-Host "[FAIL] No unstaged changes found" -ForegroundColor Red
|
||||
Write-Host "[HINT] After --mixed reset, changes should be in working directory (unstaged)" -ForegroundColor Yellow
|
||||
$allChecksPassed = $false
|
||||
}
|
||||
}
|
||||
|
||||
# ============================================================================
|
||||
# SCENARIO 3: Hard Reset Verification
|
||||
# ============================================================================
|
||||
Write-Host "`n=== Scenario 3: Hard Reset ===`n" -ForegroundColor Cyan
|
||||
|
||||
git switch hard-reset 2>&1 | Out-Null
|
||||
|
||||
if ($LASTEXITCODE -ne 0) {
|
||||
Write-Host "[FAIL] hard-reset branch not found" -ForegroundColor Red
|
||||
$allChecksPassed = $false
|
||||
} else {
|
||||
# Count commits (should be 3: Initial + utilities + helper C, bad commit removed)
|
||||
$commitCount = [int](git rev-list --count HEAD 2>$null)
|
||||
|
||||
if ($commitCount -eq 3) {
|
||||
Write-Host "[PASS] Commit count is 3 (broken commit was reset)" -ForegroundColor Green
|
||||
} else {
|
||||
Write-Host "[FAIL] Expected 3 commits, found $commitCount" -ForegroundColor Red
|
||||
Write-Host "[HINT] Use: git reset --hard HEAD~1" -ForegroundColor Yellow
|
||||
$allChecksPassed = $false
|
||||
}
|
||||
|
||||
# Check that there are NO staged changes
|
||||
$stagedChanges = git diff --cached --name-only 2>$null
|
||||
if (-not $stagedChanges) {
|
||||
Write-Host "[PASS] No staged changes (--hard discards everything)" -ForegroundColor Green
|
||||
} else {
|
||||
Write-Host "[FAIL] Found staged changes (--hard should discard all)" -ForegroundColor Red
|
||||
$allChecksPassed = $false
|
||||
}
|
||||
|
||||
# Check that there are NO unstaged changes
|
||||
$unstagedChanges = git diff --name-only 2>$null
|
||||
if (-not $unstagedChanges) {
|
||||
Write-Host "[PASS] No unstaged changes (--hard discards everything)" -ForegroundColor Green
|
||||
} else {
|
||||
Write-Host "[FAIL] Found unstaged changes (--hard should discard all)" -ForegroundColor Red
|
||||
$allChecksPassed = $false
|
||||
}
|
||||
|
||||
# Check working directory is clean
|
||||
$statusOutput = git status --porcelain 2>$null
|
||||
if (-not $statusOutput) {
|
||||
Write-Host "[PASS] Working directory is completely clean" -ForegroundColor Green
|
||||
} else {
|
||||
Write-Host "[INFO] Working directory has some changes" -ForegroundColor Yellow
|
||||
}
|
||||
|
||||
# Verify the file doesn't have the broken code
|
||||
if (Test-Path "utils.py") {
|
||||
$utilsContent = Get-Content "utils.py" -Raw
|
||||
if ($utilsContent -notmatch "helper_d") {
|
||||
Write-Host "[PASS] Broken helper_d function is gone" -ForegroundColor Green
|
||||
} else {
|
||||
Write-Host "[FAIL] Broken helper_d still exists (wasn't reset)" -ForegroundColor Red
|
||||
$allChecksPassed = $false
|
||||
}
|
||||
|
||||
if ($utilsContent -match "helper_c") {
|
||||
Write-Host "[PASS] Good helper_c function is preserved" -ForegroundColor Green
|
||||
} else {
|
||||
Write-Host "[FAIL] Good helper_c function missing" -ForegroundColor Red
|
||||
$allChecksPassed = $false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Set-Location $originalDir
|
||||
|
||||
# Final summary
|
||||
Write-Host ""
|
||||
if ($allChecksPassed) {
|
||||
Write-Host "==========================================" -ForegroundColor Green
|
||||
Write-Host " CONGRATULATIONS! ALL SCENARIOS PASSED!" -ForegroundColor Green
|
||||
Write-Host "==========================================" -ForegroundColor Green
|
||||
Write-Host "`nYou've mastered git reset!" -ForegroundColor Cyan
|
||||
Write-Host "You now understand:" -ForegroundColor Cyan
|
||||
Write-Host " ✓ Resetting commits with --soft (keep staged)" -ForegroundColor White
|
||||
Write-Host " ✓ Resetting commits with --mixed (unstage)" -ForegroundColor White
|
||||
Write-Host " ✓ Resetting commits with --hard (discard all)" -ForegroundColor White
|
||||
Write-Host " ✓ The DANGER of reset on shared history" -ForegroundColor White
|
||||
Write-Host "`n⚠️ CRITICAL REMINDER ⚠️" -ForegroundColor Red
|
||||
Write-Host "NEVER use 'git reset' on commits you've already PUSHED!" -ForegroundColor Red
|
||||
Write-Host "Always use 'git revert' (Module 05) for shared commits!" -ForegroundColor Yellow
|
||||
Write-Host "`nReady for Module 07: Git Stash!" -ForegroundColor Green
|
||||
Write-Host ""
|
||||
exit 0
|
||||
} else {
|
||||
Write-Host "[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 "[REMINDER] Reset is ONLY for local, un-pushed commits!" -ForegroundColor Yellow
|
||||
Write-Host ""
|
||||
exit 1
|
||||
}
|
||||
Reference in New Issue
Block a user