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 reflog

Shows 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~1

Use --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/folders

git 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/x

The 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:

  1. Immediately rotate the leaked credentials. Whatever was in those secrets, revoke and replace.
  2. Use git-filter-repo or BFG Repo-Cleaner to remove the file from history:
    git filter-repo --invert-paths --path .env
    git push --force --all
  3. 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_HEAD

ORIG_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 push

git 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 main

If 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 from

Any 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 stashes

A 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:

  1. Make sure your unique work is somewhere safe (push to a branch, copy files to your desktop).
  2. Delete your local clone of the repo.
  3. git clone it fresh from GitHub.
  4. 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

  • reflog is 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.

  • reset moves a branch pointer; it doesn’t destroy commits unless they’re truly orphaned. Distinction matters when calculating “what’s recoverable.”

  • git reset --hard discards uncommitted changes in your working directory. Unrecoverable. Commit or stash first if uncertain.

  • git clean -fd deletes untracked files. Often desirable to clean a workspace; sometimes catastrophic if you had work-in-progress that wasn’t yet committed.

  • git revert creates a new commit; git reset moves a pointer. Revert is safe for shared branches; reset is for your local state.

  • Force-push is dangerous on shared branches. --force-with-lease is much safer; refuses if the remote has changed since your last fetch.

  • git rebase --abort and git merge --abort get 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


Sources