Git is the most powerful tool in a developer's toolbox and also the one most likely to cause a 2 AM panic. The good news: Git almost never actually loses your work. Almost every mistake has an undo - you just need to know where to look.
# 1. Committed to the Wrong Branch
# You committed to main instead of your feature branch
# Move the last commit to a new branch without losing changes
git branch feature/my-feature # create the branch with your commit
git reset HEAD~1 --hard # remove commit from main
git checkout feature/my-feature # switch to the new branch# 2. Wrote a Terrible Commit Message
# Only works if you haven't pushed yet
git commit --amend -m "feat: add user authentication with Firebase"
# Already pushed? Amend then force-push (only safe on your own branch, never main)
git push origin feature/my-branch --force-with-lease# 3. Accidental git add . (Staged Files You Didn't Want)
# Unstage everything (keeps changes in working directory)
git reset HEAD
# Unstage a specific file
git restore --staged src/secret-config.js# 4. Pushed Sensitive Data (API Keys, Passwords)
This is the scary one. If you pushed a secret to a public repo, assume it's compromised and rotate it immediately - even after you remove it from Git. The file existed in the public commit history, and bots scrape GitHub constantly.
# Remove file from entire Git history (nuclear option)
git filter-branch --force --index-filter 'git rm --cached --ignore-unmatch path/to/secret-file.env' --prune-empty --tag-name-filter cat -- --all
git push origin --force --allAfter removing secrets from history, immediately rotate/invalidate the exposed credentials at the service provider. GitHub's secret scanning will also alert you if detected keys are found - treat those alerts as urgent.
# 5. Detached HEAD State
# You checked out a specific commit and now HEAD is detached
# Git warns: "You are in 'detached HEAD' state"
# If you made commits in detached HEAD and want to keep them:
git branch recovery-branch # save your commits to a new branch
git checkout main # go back to main
git merge recovery-branch # bring your work in
# If you don't want to keep the commits, just:
git checkout main# 6. Merged Too Early (Need to Undo a Merge)
# If you haven't pushed the merge:
git reset --hard HEAD~1
# If you already pushed (safer - creates a new revert commit instead of rewriting history):
git revert -m 1 HEAD
git push origin main# 7. Deleted a Branch You Needed
# Find the commit hash of the deleted branch's tip
git reflog | grep "branch-name"
# Restore it
git checkout -b recovered-branch abc1234 # replace with actual hash# 8. Merge Conflicts That Won't Resolve
# Abort the merge and start fresh
git merge --abort
# Or, for rebase conflicts:
git rebase --abort
# Use a visual merge tool instead of editing conflict markers manually
git mergetool # opens your configured diff tool (VS Code, vimdiff, etc.)
# VS Code as default merge tool:
git config --global merge.tool vscode
git config --global mergetool.vscode.cmd 'code --wait $MERGED'# 9. Local Branch Is Behind Origin (Can't Push)
# Pull with rebase instead of merge - keeps history clean
git pull origin main --rebase
# If conflicts occur during rebase, fix them then:
git add .
git rebase --continue# 10. Lost Work After Hard Reset
# Git's reflog is your time machine - it tracks every HEAD movement
git reflog
# Find the commit you want to recover (something like HEAD@{3})
git checkout HEAD@{3} # preview the state
git branch recovered HEAD@{3} # save it as a branchReflog only keeps entries for 90 days by default, and it's local - it doesn't push to GitHub. If you lose a commit and more than 90 days pass, it's gone. Develop the habit of creating branches before risky operations.

