Case Study: The Git Disaster Recovery Guide
The Scenario
It's Thursday evening. You've been working on your CS project for three hours. You've made several commits. And then — something goes wrong. Maybe you committed the wrong file. Maybe you accidentally deleted a branch. Maybe you made a mess of a merge and your code looks like alphabet soup.
Don't panic. Git is designed so that almost nothing is truly lost. This case study walks through the most common Git disasters and shows you exactly how to recover from each one.
Disaster 1: "I committed but the message has a typo"
You just ran:
git commit -m "Add seach function to task manager"
And immediately noticed: "seach" should be "search." The commit happened half a second ago, you haven't pushed, and nobody else has seen it.
The Fix
git commit --amend -m "Add search function to task manager"
--amend replaces your most recent commit with a new one. The old commit is rewritten with the corrected message. The code changes are identical — only the message is fixed.
When This Is Safe
Only amend commits you haven't pushed yet. Once a commit has been pushed to a remote and other people may have pulled it, amending rewrites history — which causes problems for everyone else. If you've already pushed, just make a new commit.
Disaster 2: "I modified a file and want to undo my changes"
You've been editing display.py for twenty minutes, and now everything is worse than when you started. The file was fine before you touched it, and you want to go back to the last committed version.
Check What Changed First
git diff display.py
This shows you exactly what you changed. Maybe the changes aren't as bad as you thought.
The Fix (Unstaged Changes)
If you haven't run git add yet:
git restore display.py
This replaces the file with the version from the last commit. Your changes are gone — this is not reversible, so make sure you really want to discard them.
The Fix (Staged Changes)
If you already ran git add display.py:
# Step 1: Unstage the file (move it back to "modified but not staged")
git restore --staged display.py
# Step 2: Discard the changes
git restore display.py
Disaster 3: "I committed a file I shouldn't have"
You accidentally committed secrets.env containing your API keys, or a 500 MB data file, or your personal notes.
If You Haven't Pushed Yet
Remove the file from the most recent commit:
# Remove the file from Git's tracking (but keep it on disk)
git rm --cached secrets.env
# Add it to .gitignore so it doesn't happen again
echo "secrets.env" >> .gitignore
# Amend the commit to exclude the file
git add .gitignore
git commit --amend -m "Initial commit (remove secrets.env)"
If You've Already Pushed
The file is now in the remote history. Even if you delete it in a new commit, it's still accessible in the old commit. For passwords and API keys:
- Treat the secret as compromised immediately — change the password or rotate the API key
- Remove the file from tracking:
bash git rm --cached secrets.env echo "secrets.env" >> .gitignore git add .gitignore git commit -m "Remove secrets.env from tracking" git push - For truly sensitive data, look into
git filter-branchor theBFG Repo Cleanertool, which can rewrite history to purge a file from all commits. This is an advanced operation — see the Further Reading section for resources.
⚠️ Security Rule: If a secret was ever in a public repository, even for one second, consider it compromised. Automated scanners constantly crawl GitHub for exposed credentials.
Disaster 4: "I'm in the middle of a merge conflict and everything is a mess"
You ran git merge feature-branch, got conflicts in five files, and now you're confused and overwhelmed. You haven't resolved anything yet, and you just want to go back to before the merge started.
The Fix: Abort the Merge
git merge --abort
This undoes the merge attempt entirely and returns your working directory to the state it was in before you ran git merge. You're back on your branch with clean files. The feature branch is still there, unchanged. You can try the merge again later when you're ready.
If You Want to Try Again More Carefully
After aborting, look at what will conflict before merging:
# See which files differ between the two branches
git diff main..feature-branch --name-only
Then merge and tackle conflicts one file at a time:
git merge feature-branch
# Check which files have conflicts
git status
# Open and resolve each one
# After each file is resolved:
git add <resolved-file>
# When all conflicts are resolved:
git commit
Disaster 5: "I deleted a branch with work I needed"
You ran git branch -d experiment (or even -D to force-delete), and then realized you needed the commits on that branch.
The Fix: Git Reflog
Git keeps a log of every place HEAD has pointed to — even on deleted branches. This log survives branch deletion for at least 30 days (by default).
# See the reflog — a history of every checkout, commit, and merge
git reflog
Output:
a1b2c3d HEAD@{0}: checkout: moving from experiment to main
f4e5d6c HEAD@{1}: commit: Add experimental parser
b7c8d9e HEAD@{2}: checkout: moving from main to experiment
Find the commit hash from the deleted branch (in this case, f4e5d6c), and recreate the branch:
git branch experiment-recovered f4e5d6c
Your commits are back. The reflog is Git's safety net — it's why people say "Git never forgets."
💡 Key Insight:
git reflogis the most underappreciated Git command. It's your ultimate undo button. If you can describe what you did ("I committed, then checked out, then deleted"), the reflog can help you find where you were.
Disaster 6: "I committed to the wrong branch"
You've been working on main when you should have been on a feature branch. You've made two commits that shouldn't be on main.
The Fix: Move Commits to a New Branch
# Step 1: Create a new branch at the current position (capturing your commits)
git branch my-feature
# Step 2: Reset main back to where it should be (2 commits ago)
git reset --hard HEAD~2
# Step 3: Switch to your feature branch — your commits are there
git switch my-feature
The HEAD~2 notation means "two commits before the current HEAD." After the reset, main is back where it was, and my-feature has your two commits.
⚠️ Caution:
git reset --hardis a destructive command — it discards changes. Only use it when you're sure you know what you're doing. In this case, it's safe because we already saved the commits onmy-feature.
Disaster 7: "I want to undo a specific old commit without rewriting history"
You realize that a commit from three days ago introduced a bug, but you've made ten commits since then. You don't want to undo all ten commits — just that one specific commit.
The Fix: Git Revert
# Find the hash of the problematic commit
git log --oneline
# Revert it — this creates a NEW commit that undoes the changes
git revert a1b2c3d
git revert doesn't erase the old commit — it creates a brand-new commit that applies the inverse of the old changes. This is history-safe: it works even on shared branches because it adds to history rather than rewriting it.
The Recovery Cheat Sheet
| Disaster | Command | Safe After Push? |
|---|---|---|
| Typo in last commit message | git commit --amend -m "..." |
No |
| Undo unstaged file changes | git restore <file> |
N/A |
| Unstage a file | git restore --staged <file> |
N/A |
| Remove file from last commit | git rm --cached <file> + amend |
No |
| Abort a messy merge | git merge --abort |
N/A |
| Recover a deleted branch | git reflog + git branch <name> <hash> |
N/A |
| Commits on wrong branch | git branch <new> + git reset --hard |
No |
| Undo an old commit safely | git revert <hash> |
Yes |
Discussion Questions
-
Why is
git revertsafe to use on shared branches butgit commit --amendandgit reset --hardare not? What's the fundamental difference between "rewriting history" and "adding to history"? -
The reflog saves you from many disasters, but it only exists locally. What implications does this have for backup strategies? How does pushing to a remote provide an additional safety net?
-
Disaster 3 (accidentally committing secrets) is particularly dangerous. What practices could prevent this from happening in the first place? Think about both technical solutions (
.gitignore, pre-commit hooks) and human habits. -
Some developers use
git stash(not covered in this chapter) to temporarily save uncommitted changes. Based on the disaster scenarios above, can you guess whatgit stashmight do and when it would be useful?
Mini-Project
Practice each disaster recovery technique in a safe, throwaway repository:
- Create a new repo with at least three commits
- Practice Disaster 1: amend a commit message
- Practice Disaster 2: modify a file, then restore it
- Practice Disaster 4: create two branches that conflict, start a merge, abort it, then successfully resolve the conflict
- Practice Disaster 5: delete a branch, find it in the reflog, recover it
- Document each step you took and the output you saw
This is the kind of practice that pays off enormously when a real disaster strikes during a deadline.