How to rescue a broken Git branch
Status: 🟩 COMPLETE Last updated: 2026-06-19 Plain-English tagline: “Oh no, I broke it.” Five panic scenarios, five recovery moves: undoing the last commit, restoring a deleted file, ditching all changes, rescuing work from a wrong branch, finding a commit you “lost.”
Goal
When git feels like it’s eaten your work, this guide walks through the calm path back. Almost nothing in git is genuinely lost — git’s reflog keeps everything for ~90 days. The trick is knowing the right command for the situation.
By the end of this guide: you can recover from the five most common “I broke git” scenarios in under 10 minutes, without losing real work.
Why it matters
Git is powerful and unforgiving. A misclick of git reset --hard, a confident git push --force, or an accidental commit on the wrong branch can FEEL like catastrophe. They almost never are — but only if you know the recovery moves.
For Bible Quest-style projects: a botched branch can hold up an important fix. Five-minute recovery vs. an hour of stress changes the working day.
This guide assumes you understand git basics. See Git, Branches & merging, Git rescue moves for foundations.
Prerequisites
- A git repository where things went wrong
- You’ve committed at least once (the reflog exists from there)
- You haven’t run
git gc --prune=nowor similar (which can delete reflog entries) - You have terminal access to the project folder
The panic checklist (read first, breathe)
Before doing ANYTHING that modifies git state:
- Stop. Don’t run more commands in panic. Each can make recovery harder.
- Don’t
git push --force. If anything, push the broken state to a backup branch first. - Check
git status. Know what’s modified, staged, untracked before acting. - Check
git reflog. This shows every HEAD change in the last ~90 days — almost certainly contains the commit you lost.
git status
git reflogreflog shows recent operations like:
abc123 HEAD@{0}: commit: "Fix the navigation"
def456 HEAD@{1}: checkout: moving from main to feature-x
789ghi HEAD@{2}: reset: moving to HEAD~1
...
Each entry has a commit hash on the left. That hash is reachable even if no branch points at it — perfect for recovery.
Scenario 1: “I committed but the commit is wrong”
You just made a commit, but the message is wrong, OR you forgot to include a file, OR the commit shouldn’t have been made at all.
If the wrong commit hasn’t been pushed yet
To fix the commit message (no content change):
git commit --amend -m "New message"To add forgotten files to the last commit:
git add forgotten-file.tsx
git commit --amend --no-edit--no-edit keeps the existing message.
To undo the last commit but keep the changes (so you can re-commit differently):
git reset --soft HEAD~1Now git status shows the files as STAGED. Edit, then commit again with a better message or split into multiple commits.
To undo the last commit AND discard the changes:
git reset --hard HEAD~1⚠️ This is destructive — the work is gone from your working tree. The commit is still in reflog though, so you can recover (scenario 5).
If the wrong commit IS pushed (no one else has pulled yet)
git commit --amend -m "New message"
git push --force-with-lease--force-with-lease is safer than --force — it refuses to overwrite if someone else has pushed since you last pulled. Use it always.
If the wrong commit is pushed and OTHERS have pulled
Don’t amend or force-push. Add a NEW commit that reverses the bad one:
git revert <commit-hash>
git pushgit revert creates a NEW commit that undoes the changes. History is preserved; no one’s local checkout breaks.
Scenario 2: “I deleted a file and I want it back”
If you haven’t committed the deletion
git restore <file>(Or in older git: git checkout -- <file>.) The file comes back as it was at the last commit.
If you’ve staged the deletion (git rm or git add after deleting)
git restore --staged <file>
git restore <file>First unstage, then restore.
If you’ve committed the deletion
Find the commit BEFORE the deletion:
git log --all --oneline -- <file>This shows every commit that touched the file. Pick the last one before deletion. Restore the file from that commit:
git checkout <commit-hash> -- <file>The file is now in your working tree. Commit:
git add <file>
git commit -m "Restore <file>"If the entire commit was a mistake
Use revert (above) on the deleting commit.
Scenario 3: “I have uncommitted changes I want to throw away”
git restore .Discards ALL unstaged changes. Files go back to their last-committed state. Untracked files are NOT removed.
To also remove untracked files (BE CAREFUL — these are not in git history):
git clean -fd # -f = force, -d = also remove directories
# or preview first:
git clean -nfd # -n = dry runTo discard everything including staged changes:
git reset --hard HEAD⚠️ All three of these are destructive. Untracked files cannot be recovered with reflog (they were never committed). Double-check there’s nothing precious in git status first.
Scenario 4: “I committed to the wrong branch”
You made commits on main that should have been on feature-x.
If the commits aren’t pushed yet
Create the right branch from current state:
git branch feature-x # creates feature-x at current commit
git reset --hard origin/main # moves main back to where remote main is
git checkout feature-x # switch to the new branchYour commits are now on feature-x, and main is unchanged.
If the commits ARE pushed to main
This is harder because rewriting public main history breaks teammates. Options:
Option A: Cherry-pick onto the right branch, then revert on main
git checkout feature-x
git cherry-pick <commit-a> <commit-b> # copy the commits over
git checkout main
git revert <commit-a> <commit-b> # revert them from main
git pushHistory on main shows: commit happened, then a revert. feature-x has the commits properly.
Option B: Reset main + force-push (only if you’re the sole user)
git checkout main
git reset --hard <last-good-commit>
git push --force-with-lease
git checkout feature-x
git cherry-pick <commit-a> <commit-b>
git pushOnly do this on a personal branch or main of a personal project. NEVER force-push public branches with active collaborators.
Scenario 5: “I think I lost a commit”
git reflogShows every move HEAD has made. Look for the lost commit:
abc1234 HEAD@{0}: reset: moving to HEAD~5
xyz5678 HEAD@{1}: commit: "the lost commit"
...
Recover it:
git checkout xyz5678 # check out the commit (detached HEAD)
git switch -c rescued # create a new branch from itNow rescued contains the commit. You can merge it back, cherry-pick from it, or just keep it.
Alternative — if you know you wanted to UNDO the previous reset:
git reset --hard xyz5678 # move HEAD back to where it wasScenario 6: “I git pull and now there are conflicts everywhere”
git status # see what's conflicted
git diff # see the conflicts inlineFor each conflicted file:
- Open in your editor; resolve the conflict markers (
<<<<<<<,=======,>>>>>>>) - Stage the resolved file:
git add <file>
When done:
git commit # completes the merge commitIf the merge is too messy to resolve manually:
git merge --abort # back to pre-pull stateThen you can pull differently (with --rebase, or pull into a different branch).
For deep merge-conflict tactics, see Resolving merge conflicts.
Scenario 7: “I pushed something that shouldn’t be public” (secrets, sensitive data)
This is a SECURITY incident, not just a git mistake.
- Immediately rotate any leaked credentials. Generate new API keys, change passwords, invalidate tokens.
- Remove from git history.
# Easiest: install git-filter-repo
pip install git-filter-repo
git filter-repo --invert-paths --path .env.local
# Then force-push
git push --force-with-lease --all- Assume it was scraped. GitHub’s API is constantly scraped by bots looking for leaked credentials. Even a 5-minute window of public exposure is enough.
For Bible Quest: ensure .env* is in .gitignore from day one. See Environment variables.
Verification
After any recovery:
-
git statusshows what you expect -
git log --oneline -10shows the commit history you expect -
git diff(orgit diff --staged) shows what you expect - The files in your working tree look correct
- If pushed: GitHub shows the right state
- If a build was affected: Vercel shows the right deployment
If anything seems off, STOP. Run git reflog, find the state you want, recover to it.
Common failures and fixes
”git reset --hard deleted my work”
Don’t panic. Run git reflog. Find the commit hash from BEFORE the reset (HEAD@{1} is usually the previous state). Recover with:
git reset --hard <commit-hash-from-reflog>Reflog keeps entries for ~90 days. Your work is almost certainly still there.
”I force-pushed and lost commits”
If those commits are referenced by reflog locally, you can recover them. If they ONLY existed on the remote (you never had them locally), they’re gone. Hence: never force-push unless you understand the consequences.
”I closed the merge editor with conflict markers in files”
Git accepts whatever you save, including the markers. If you commit, you’ve committed broken files. Run:
git reset --soft HEAD~1 # undo the bad merge commit
# Now fix the files properly
git add .
git commit“I’m in a detached HEAD state and don’t understand”
“Detached HEAD” means you checked out a specific commit (not a branch). Changes from this state aren’t tracked by any branch — they’ll be garbage-collected if you switch away.
To save your work: create a branch.
git switch -c new-branch-nameNow your changes are anchored.
”git status is empty but I know I changed files”
Two possible causes:
- They’re already committed — check
git log --oneline - You’re in the wrong directory —
pwd(orGet-Locationin PowerShell)
“GitHub says my push was rejected”
Usually: someone else pushed since your last pull, and your local is behind.
git fetch
git rebase origin/main # or git pull --rebase
# Resolve any conflicts, then:
git push”I committed a giant file and now everything’s slow”
Files over 100MB break GitHub pushes. To remove from history:
git filter-repo --invert-paths --path huge-file.bin
git push --force-with-leaseFor very large repos, this can take time. Alternative: use Git LFS for large files.
”I’m scared to do anything”
Two safety nets:
-
Make a backup branch first:
git branch backup-2026-06-19Now whatever you do, this branch points at the current state.
-
Use Claude Code: “I have
. Show me the safest commands to .” Claude can read git status,git log,git reflogand walk you through the recovery.
A concrete example walkthrough
George is working on a feature. He accidentally runs git reset --hard HEAD~3 and panics — three commits of work seemingly gone.
Step 1: git reflog
Output shows:
abc123 HEAD@{0}: reset: moving to HEAD~3
def456 HEAD@{1}: commit: "Polish accessibility labels"
ghi789 HEAD@{2}: commit: "Tune mobile spacing"
jkl012 HEAD@{3}: commit: "Add lesson card hover states"
Step 2: The lost commits are def456, ghi789, jkl012.
He wants to be back at def456.
Step 3: git reset --hard def456
Reflog is preserved; the three commits are now in his branch again.
Step 4: git status
Confirms clean state matching the commits.
Step 5: git log --oneline -5
Confirms def456, ghi789, jkl012 are at the top of history.
Total time: 30 seconds. The panic was theoretical.
What just happened, conceptually
Git is a graph of commits. Every commit has a hash; branches are just labels pointing to specific commits.
Operations like reset --hard don’t DELETE commits — they just move the branch label. The “lost” commits are still in the repository, unreachable by name but reachable by hash. The reflog stores every recent HEAD position so you can find those hashes.
What truly DESTROYS data in git:
git gc --prune=nowfollowed by no reflog → removes unreachable commits- Files that were never committed AND
git clean -fremoves them - A push to a remote that has reflog disabled (rare)
- A
git filter-repofollowed by force-push that removes the original commits from remote
Everything else is recoverable with reflog + patience.
See also
- Git 🟩 — foundational concepts
- Branches & merging đźź©
- Resolving merge conflicts đźź©
- Git rescue moves (encyclopedia entry) 🟩 — fuller treatment of
reset,reflog,cherry-pick - Rebase vs merge đźź©
- Pull requests đźź©
- GitHub đźź©
- Debug a Vercel build failure 🟩 — when the bad commit caused a build failure
- Environment variables 🟩 — preventing secret leaks
- Glossary: Reflog, Reset, Cherry-pick, Force push
Sources
- Pro Git book — Chapters 7.6 (Reset), 7.7 (Rebase), 10 (Internals)
- Git docs — git-reset
- Git docs — git-reflog
- Git docs — git-revert
- Atlassian — Undo changes
- git-filter-repo — modern history rewriting