Git rescue moves
Status: 🟩 COMPLETE Last updated: 2026-06-20 Plain-English tagline: “Oh no, what did I just do?” — the recovery toolkit. Most Git mistakes are reversible if you know the moves.
In plain English
Git has a reputation for being scary because mistakes feel irreversible. They’re almost never irreversible. Git keeps a hidden log of every change you make to refs (reflog) for ~90 days; commits aren’t deleted until they’re truly orphaned for that long.
This entry is the panic checklist: common “oh no” moments and the recovery move for each. Bookmark it.
Why it matters
When something breaks at 2am before a deploy, you don’t want to be Googling. You want to know the move. Having this list internalized turns “everything is on fire” into “right, I do this.”
The most useful rescue command: git reflog
git reflogShows the recent history of where HEAD has been — every commit, branch switch, rebase, reset. Even commits you “deleted” are usually here.
Output looks like:
abc1234 HEAD@{0}: commit: Add dark mode
def5678 HEAD@{1}: checkout: moving from main to feature/dark-mode
9abc012 HEAD@{2}: pull: Fast-forward
3def456 HEAD@{3}: commit: Fix typo
If you’ve lost commits, find them in reflog and restore:
git reset --hard <hash>“I made a commit I want to undo (locally, not pushed yet)”
# Soft undo — uncommit, keep changes staged:
git reset --soft HEAD~1
# Default — uncommit, keep changes unstaged (in working dir):
git reset HEAD~1
# Hard undo — uncommit AND throw away changes (DANGEROUS):
git reset --hard HEAD~1Use --soft if you committed too early. Use --hard if the changes are wrong.
”I want to throw away my uncommitted changes”
# Throw away changes in one file:
git restore <file>
# Or older syntax: git checkout -- <file>
# Throw away ALL uncommitted changes (DANGEROUS):
git reset --hard
git clean -fd # also remove untracked files/foldersgit clean -fd is one of the most dangerous Git commands. It deletes files you haven’t tracked. Run git clean -nd first (dry run) to see what would go.
”I committed to the wrong branch”
You’re on main; you meant to commit to feature/x. The commit is on main.
# Create the branch you meant to be on:
git branch feature/x
# Move main back one commit:
git reset --hard HEAD~1
# Switch to your new branch (which still has the commit):
git switch feature/xThe commit is now on feature/x only. Main is clean.
”I changed my mind about a commit message”
If it’s the most recent commit and not yet pushed:
git commit --amend -m "New message"If you already pushed it:
git commit --amend -m "New message"
git push --force-with-lease(Beware of force-push — see “Golden rule” in Rebase vs merge.)
If it’s an older commit, use interactive rebase:
git rebase -i HEAD~5
# Mark the commit as "reword"
# Save, then edit the message in the next editor“I pushed the wrong thing — including secrets”
Bad news: it’s effectively public the moment it’s on a public remote. Mitigation:
- Immediately rotate the leaked credentials. Whatever was in those secrets, revoke and replace.
- Use
git-filter-repoor BFG Repo-Cleaner to remove the file from history:git filter-repo --invert-paths --path .env git push --force --all - Contact GitHub support if it was on a popular public repo — they can purge caches.
But really, the secret is compromised. Rotation is the actual fix; cleaning history is window-dressing.
For the future: aggressive .gitignore, gh secret scan warnings, pre-commit hooks that detect secrets.
”I deleted a branch I shouldn’t have”
git reflog
# Find the commit at the tip of the deleted branch
git switch -c <branch-name> <hash>The branch is back. Push if it was on a remote.
”I rebased and now my work looks gone”
Rebase rewrites commits — old ones are orphaned but still in reflog for ~90 days.
git reflog
# Find the commit that was the tip BEFORE the rebase
git reset --hard <hash>You’re back to the pre-rebase state.
”I merged main and want to undo just the merge”
git reset --hard ORIG_HEADORIG_HEAD is Git’s automatic bookmark of where you were just before the merge.
If ORIG_HEAD isn’t set anymore, use git reflog to find the pre-merge state and reset to it.
”I pushed a broken commit to main and it deployed”
In Vercel: click the previous deploy → Promote. Production is back instantly. Now fix locally:
# Revert the bad commit on main (creates a NEW commit that undoes it):
git revert <bad-commit-hash>
git pushgit revert is the safe undo for pushed commits — it doesn’t rewrite history; it adds an “undo” commit. Safe for shared branches.
”I committed something to the wrong repo / wrong remote”
# See what's pushed where:
git remote -v
# Remove the wrong remote:
git remote remove origin
# Add the right one:
git remote add origin <correct-url>
# Push:
git push -u origin mainIf the wrong commit is already on the wrong remote, force-push removal — or for sensitive content, contact that remote’s admins.
”Detached HEAD — help”
You ran git checkout <hash> and now you’re “detached.” This means you’re not on a branch.
# To stay on this commit but be on a branch:
git switch -c new-branch
# To go back to where you were:
git switch main # or whatever branch you came fromAny commits made while detached are NOT lost — they’re in git reflog. Recover with the same git reset move above.
”I git reset --hard and lost work”
git reflog
# Find the commit BEFORE the reset
git reset --hard <hash>git reset --hard doesn’t delete commits — it moves a branch pointer. The commits are still there in reflog until Git’s garbage collector decides they’re truly orphaned (default ~90 days).
”I want to recover a specific deleted file”
# See history of the file (including its deletion):
git log --all -- <path>
# Find the commit BEFORE deletion, then:
git checkout <hash> -- <path>The file is back in your working directory. Commit it.
”I want to see what a commit changed in a specific file"
git log -p -- <file> # full history of changes to this file
git show <hash> -- <file> # the change from this specific commit
git blame <file> # who last changed each line"Stash got weird”
git stash list # see what's stashed
git stash show -p stash@{0} # see the contents of stash 0
git stash pop # apply the most recent stash (and remove it from stash)
git stash apply stash@{2} # apply a specific stash without removing it
git stash drop stash@{0} # delete a stash
git stash clear # delete all stashesA common confusion: git stash pop applies + removes; git stash apply applies but keeps the stash around.
The escape hatch: clone a fresh copy
If everything is broken and you can’t figure out how to fix it:
- Make sure your unique work is somewhere safe (push to a branch, copy files to your desktop).
- Delete your local clone of the repo.
git cloneit fresh from GitHub.- Bring your work back manually.
This costs you the local Git history of your work, but it’s a real escape hatch when everything else fails. Use sparingly.
Common gotchas
-
reflogis local-only. It tracks your local actions. Other people’s reflogs are separate. -
Reflog isn’t forever. After ~90 days, abandoned commits get garbage-collected and are truly gone. Recover before then.
-
resetmoves a branch pointer; it doesn’t destroy commits unless they’re truly orphaned. Distinction matters when calculating “what’s recoverable.” -
git reset --harddiscards uncommitted changes in your working directory. Unrecoverable. Commit or stash first if uncertain. -
git clean -fddeletes untracked files. Often desirable to clean a workspace; sometimes catastrophic if you had work-in-progress that wasn’t yet committed. -
git revertcreates a new commit;git resetmoves a pointer. Revert is safe for shared branches; reset is for your local state. -
Force-push is dangerous on shared branches.
--force-with-leaseis much safer; refuses if the remote has changed since your last fetch. -
git rebase --abortandgit merge --abortget you back to safety. Don’t be afraid to bail out of a bad operation. -
You can’t recover what was never committed. Save early, save often. If you’re about to do something risky, commit a checkpoint first.
-
Some platforms have a recycle bin for repos. GitHub keeps deleted repos for ~90 days under “Settings → Restore.” Don’t panic if you delete a repo by mistake.
See also
- Git basics đźź©
- Branches & merging đźź©
- Resolving merge conflicts đźź©
- Rebase vs merge đźź©
- Git gotchas 🟥
Sources
- Oh Shit, Git!?! — the canonical “I broke Git” reference
- Pro Git book — Tools: Reset Demystified
- Atlassian — Undoing things
- git-filter-repo — for serious history rewriting
- BFG Repo-Cleaner — faster alternative to filter-repo