Practice: Undoing things
Self-check questions
Section titled “Self-check questions”Answer each in your own words first, then open the answer to check.
Q1. Without using the command, explain why git restore . (with a period) is dangerous and what you should run before using it.
Show answer
git restore . discards ALL working-directory changes across ALL files in the current directory. This is destructive; the discarded changes are not saved anywhere. Run git status first to see exactly what you’re about to throw away. The two seconds of verification prevents losing an afternoon of work.
Q2. Map each of these scenarios to the correct command:
- (a) “I want to throw away changes I made to one file.”
- (b) “I want to unstage a file but keep my edits.”
- (c) “I committed the wrong message; the commit is still local.”
- (d) “I committed something bad; the commit is already pushed.”
- (e) “I ran
git reset --hardand want my work back.”
Show answer
- (a)
git restore <file> - (b)
git restore --staged <file>(orgit reset HEAD <file>) - (c)
git commit --amend - (d)
git revert <commit-hash> - (e)
git reflog+git reset --hard <hash>
Q3. Explain the difference between git reset --soft HEAD~1, git reset HEAD~1, and git reset --hard HEAD~1. For each, describe what happens to (i) the commit pointer, (ii) the staging area, (iii) the working directory.
Show answer
git reset --soft HEAD~1: commit pointer moves back 1; staging area keeps the files; working directory unchanged. Net: the “undone” commit’s changes are staged, ready for re-commit.git reset HEAD~1(mixed, default): commit pointer moves back 1; staging area is cleared; working directory keeps the changes. Net: the “undone” commit’s changes are in your working files but no longer staged.git reset --hard HEAD~1: commit pointer moves back 1; staging area is cleared; working directory is reset. Net: the “undone” commit’s changes are gone from disk (recoverable via reflog, but the working tree is fresh).
Q4. A teammate pushed a commit and now wants to undo it. They are about to run git reset --hard HEAD~1 and force-push. Without using any command yet, explain why this is wrong and what they should do instead.
Show answer
Running git reset --hard HEAD~1 followed by git push --force rewrites the shared history. Any collaborator who has already pulled the commit will be in conflict the next time they pull. The team’s history becomes inconsistent. The right move is git revert <commit-hash>, which creates a new commit that undoes the previous one. The team’s history grows forward; everyone stays in sync.
Q5. git reflog records HEAD movements for ~90 days. What’s the one operational implication of “90 days” for a developer who realizes a week after the fact that they lost work?
Show answer
The 90-day window means: don’t wait to recover after a destructive operation. Run git reflog while the relevant entries are still there. A week after the fact is fine; three months is probably too late. The discipline: recover quickly, even if you’re not 100% sure you need to, because waiting is the only way to lose the option.
Recovery drill (hands-on, safe)
Section titled “Recovery drill (hands-on, safe)”This drill teaches all six commands through a single guided session. Run it in a sandbox repository so any mistakes are contained.
Setup: create a new sandbox folder, git init, commit a few files so you have at least three commits in history.
Drill 1, Discard working changes:
- Edit one file. Save.
git statusto confirm the file shows as modified.git restore <filename>to discard the changes.- Verify with
git statusthat the file is no longer modified.
Drill 2, Unstage a file:
- Edit a file. Save.
git add <filename>to stage it.git statusto confirm it’s staged.git restore --staged <filename>to unstage.- Verify with
git status; file should be modified but unstaged.
Drill 3, Amend the last commit:
- Make a small change. Stage. Commit with a deliberately mistyped message.
git log --onelineto see the bad message.git commit --amend -m "Better message"to fix it.git log --onelineto verify the fix landed.
Drill 4, Reset modes:
- Make a change, stage, commit. Repeat to have a recent commit you can throw away.
git reset --soft HEAD~1and observe: staged changes appear, working directory unchanged.- Commit again to restore state.
git reset HEAD~1(mixed, default) and observe: staging cleared, working directory keeps the changes.- Re-stage, re-commit.
git reset --hard HEAD~1and observe: everything reset, working files reverted.- Run
git reflogimmediately to see your “lost” commit hash. - Recover with
git reset --hard <hash-from-reflog>. Confirm you are back where you were.
Drill 5, Revert a commit:
- Make a small change, stage, commit (call it
bad-feature). git revert HEAD; git opens an editor with a pre-filled message; save and close.git log --onelineto confirm two commits now: the bad one + the revert.- Both commits appear in history; the file is back to its pre-bad-feature state.
Drill 6, Reflog deep recovery (DELIBERATE DESTRUCTIVE):
- Make a meaningful set of changes across several files. Stage. Commit. Make sure these changes feel real; name a function, add a comment, something you would actually do.
git log --onelineand remember the commit hash of the latest commit.git reset --hard HEAD~3(or however many to “lose” the work).- Feel the panic. The work appears gone.
git reflog. Find the commit hash you remember.git reset --hard <hash>. Everything is back.- Take a moment to appreciate that you have just used the safety net. Your future self will be much calmer about destructive operations because you have done this once.
Scenario reflections
Section titled “Scenario reflections”Scenario A. A teammate runs git reset --hard HEAD~3 to undo three commits. After running it, they realize one of the three commits had a fix that should not have been undone. Walk them through the recovery without using force-push.
Show answer
Recovery procedure:
git reflogto find the commit hashes before the reset- Identify the specific commit that had the fix
git cherry-pick <fix-commit-hash>to bring just that commit forward onto the current branch (we cover cherry-pick in L11; for now, knowing it exists is enough)- Or alternative:
git reset --hard <pre-reset-hash>to get the full state back, then re-do the reset more carefully (drop two of the three commits, keep the one with the fix, then commit/revert as appropriate)
Scenario B. A new developer asks: “Should I always use git revert instead of git reset, just to be safe?” Without writing code, explain the tradeoff and when each is appropriate.
Show answer
Revert is always safe; reset is destructive (rewrites history). For a new developer, “always use revert” is a defensive position that can’t be wrong. But there are real situations where reset is better: cleaning up your own local commits before pushing, abandoning a failed local experiment entirely, etc. The mature rule is “reset for local-only, revert for anything pushed.” But a new developer who only ever uses revert until they understand reset is making a safe choice. They will pick up reset as they encounter situations where it’s clearly the right tool.
Scenario C. A commit has been pushed and merged to main. A teammate wants to undo it. They ask whether to use git reset --hard HEAD~1 followed by git push --force. Without writing code, explain why this approach is dangerous AND why git revert is the right alternative.
Show answer
git reset --hard HEAD~1 + git push --force would rewrite the remote main branch. Any team member who has already pulled the commit will be in conflict on their next pull or fetch. The team’s history becomes inconsistent. The audit trail of “this thing happened and we tried it” disappears. Use git revert <commit-hash> instead; it creates a new commit that undoes the previous one without rewriting history. The original commit stays in history (so the team’s record of “we tried this and reverted it” is preserved), and any collaborator pulling sees both the original and the revert, ending up with a net-zero working tree change.
Flashcards
Section titled “Flashcards”Q. What command discards changes to a file in your working directory?
git restore <file>. The discarded changes are not recoverable.
Q. What command unstages a file without losing your edits?
git restore --staged <file> (modern). Or the older git reset HEAD <file>. Both do the same thing.
Q. What does git commit --amend do?
It rewrites the most recent commit, optionally including new staged changes and/or a new message. Don’t use it on commits that have been pushed.
Q. What is the difference between git reset --soft, git reset --mixed, and git reset --hard?
All three move the commit pointer backward. —soft keeps staged + working. —mixed (default) clears staging, keeps working. —hard clears everything (destructive).
Q. When should you use git revert instead of git reset?
Whenever the commit has been pushed to a shared branch. Revert creates a new inverse commit; reset rewrites local history. Reset on pushed commits causes ugly merge situations for collaborators.
Q. What is git reflog?
Git’s internal log of every HEAD movement over the past ~90 days. Lets you recover commits that “vanished” from a destructive operation.
Q. After a destructive git reset --hard, what is the recovery procedure?
git reflog to find the commit hash you want, then git reset --hard <hash> to restore that state.
Q. Why is 'almost nothing is truly lost' an important psychology to internalize?
Because fear of losing work makes developers avoid experimentation. Knowing that the reflog catches almost every mistake lets you move faster and try riskier things, with recovery being one command away.
Q. What's the rule of thumb for --amend vs revert for fixing a commit?
—amend only if not yet pushed. Revert is the only safe option once pushed.
Q. Why is 'rewrite freely on personal branches, never rewrite on shared branches' the common team norm?
Because rewriting local history is harmless (only you see it), but rewriting shared history breaks anyone who has based their work on the original commits. Convention preserves both flexibility (personal) and audit trail (shared).