Git Recovery Guide
Fix common Git mistakes and recover from disasters
Even experienced developers make Git mistakes. This guide covers common scenarios and step-by-step solutions to recover from them.
Critical Recovery Scenarios
git reset --hard HEAD~3
You did a hard reset but later realized you needed changes from those commits.
Solution: Use git reflog to find the lost commits and restore files from them.
# Find the lost commits
git reflog
abc1234 HEAD@{0}: reset: moving to HEAD~3
def5678 HEAD@{1}: commit: Important feature
ghi9012 HEAD@{2}: commit: Bug fixes
# Restore files from specific commit
git restore --source=def5678 path/to/important-file.txt
git reset --hard HEAD~1 # Accidentally wiped new feature
git reflog | grep "Add login" # Find commit hash (e.g., abc1234)
git restore --source=abc1234 src/login.js # Recover the file
git push origin main
You pushed API keys, passwords, or other sensitive data to a remote repository.
Solution: Use git filter-repo to completely remove the file from history.
# 1. Remove file from history (install git-filter-repo first)
git filter-repo --path secrets.txt --invert-paths
# 2. Force push (warn your team first!)
git push --force
# 3. Everyone else must reclone or reset their repos
git fetch origin
git reset --hard origin/main
# After pushing config.json with passwords:
git filter-repo --path config.json --invert-paths
git remote add origin <url> # Required after filter-repo
git push --force
git push origin main
You pushed API keys, passwords, or other sensitive data to a remote repository.
Solution: Use git filter-repo to completely remove the file from history.
Use git filter-repo to safely and permanently remove
sensitive files from Git history. This version includes backup,
selective path removal, and team-safe practices.
# 0. Backup your repo first
git clone --mirror . ../repo-backup.git
# 1. Remove one or more files/folders from history
git filter-repo \ --path secrets.txt \ --path passwords.json \
--invert-paths
# 2. Optional: Remove files by regex pattern (e.g., all *.env
files)
git filter-repo --invert-paths --path-glob '*.env'
# 3. Clean references and reflog (safeguard for old objects)
git reflog expire --expire=now --all git gc --prune=now
--aggressive
# 4. Force push rewritten history to remote
git push --force --all git push --force --tags
# 5. Everyone else must reclone or hard-reset
git fetch origin git reset --hard origin/main
git filter-repo --path config.json --path secret.env
--invert-paths
git reflog expire --expire=now --all git gc --prune=now
--aggressive
git push --force --all git push --force --tags
# Team members must reclone to avoid conflicts
git add .
You added everything including debug logs or files that shouldn't be committed.
Solution: Unstage the unwanted files and make a clean commit.
# Unstage specific files
git restore --staged *.log
git restore --staged temp.txt
# Now commit only intended files
git commit -m "Real changes"
git reset --soft HEAD~1 # Undo commit but keep changes
git restore --staged unwanted_file.txt # Unstage the file
git commit -m "Clean commit" # Recommit
git push origin main
You pushed a commit that has bugs or issues and need to undo it.
Solution: Use git revert to create a new commit that undoes the changes.
# Revert the last commit
git revert HEAD
# Revert a specific commit
git revert abc1234
# Push the revert
git push origin main
# After bad commit abc123:
git revert abc123 # Creates new revert commit
git push # Safe for shared branches
git merge feature
Conflict resolution went wrong and you lost important changes.
Solution: Use ORIG_HEAD to revert to pre-merge state.
# Revert to pre-merge state
git reset --merge ORIG_HEAD
# Alternatively, if you've done other operations since
git reflog
git reset --hard HEAD@{1}
git merge feature # Conflicts appear
# Accidentally accepted wrong changes
git reset --merge ORIG_HEAD # Back to square one
git checkout main
git commit -m "Feature X"
You made commits to the wrong branch and need to move them.
Solution: Use cherry-pick to move the commit, then reset the original branch.
# Move commit to correct branch
git checkout feature
git cherry-pick main
# Remove from wrong branch
git checkout main
git reset --hard HEAD~1
# Commit made on main instead of feature-branch:
git branch feature-branch # Create if doesn't exist
git checkout feature-branch
git cherry-pick main
git checkout main
git reset --hard HEAD~1
git branch -D feature
You deleted a branch that hadn't been merged yet.
Solution: Use reflog to find the last commit on the deleted branch.
# Find the last commit on the deleted branch
git reflog
abc1234 HEAD@{0}: checkout: moving from feature to main
def5678 HEAD@{1}: commit: Finalize feature
# Recreate the branch
git branch feature def5678
# Find the commit where the branch last existed
git reflog | grep "feature"
abc1234 HEAD@{2}: commit: Feature implementation
# Recreate the branch from that commit
git branch feature abc1234
Nuclear Scenarios
git reset --hard origin/main
You lost days of uncommitted work after a hard reset.
Solution: Use git's internal file system check to find lost blobs.
# Search for lost data
git fsck --lost-found
# Look for blobs (file contents)
git show [blob-hash]
# Search for specific content
git fsck --lost-found | grep "blob" | xargs -I{} sh -c 'git show {} | grep -q "unique string" && echo {}'
You pushed API keys or credentials to a public repository.
Solution: Use filter-repo to purge the file and rotate all exposed keys.
# Purge file from all history
git filter-repo --path .env --invert-paths
# Force push to all branches
git push --force --all
# Then rotate all exposed keys immediately!
# Notify anyone who cloned the repository
git push --force
You force pushed and overwrote teammate's work.
Solution: Use reflog to find pre-force-push state and restore it.
# Find pre-force-push state
git reflog
abc1234 HEAD@{0}: push --force
def5678 HEAD@{1}: pull origin main
# Reset to before the force push
git reset --hard HEAD@{1}
# Force push again to restore
git push --force
Your repository has become corrupted with file system errors.
Solution: Use git's built-in repair tools to attempt recovery.
# Check repository integrity
git fsck --full
# Attempt to repair
git gc --prune=now
# Reclone from remote if all else fails
cd ..
git clone [repository-url] new-repo
cp -R new-repo/.git old-repo/
git rebase main
Your rebase went wrong and you lost commits or have conflicts you can't resolve.
Solution: Abort the rebase and restore from the original branch.
# Abort the rebase
git rebase --abort
# If that doesn't work, reset to original state
git reflog
git reset --hard ORIG_HEAD
# Or restore from a backup branch if you made one
git checkout -b recovered-feature backup/feature-branch
git stash drop
You accidentally dropped a stash that contained important changes.
Solution: Use git fsck to find dangling commits, then recover from them.
# Find dangling commits (including stashes)
git fsck --unreachable | grep commit | cut -d' ' -f3
# Check each commit to see if it's your stash
git show <commit-hash>
# Once found, create a branch from it
git branch recovered-stash <commit-hash>
# Or apply it directly
git merge <commit-hash>
Undo & Rewrite History
git commit -m "Broken feature"
You made a commit that introduced bugs and want to undo it.
Solution: Use git reset to remove the commit while keeping changes.
# Keep changes in working directory
git reset --soft HEAD~1
# Discard changes completely
git reset --hard HEAD~1
# If already pushed, use revert instead
git revert HEAD
git commit -m "Multiple changes"
You made a commit with multiple unrelated changes and want to split it.
Solution: Use interactive rebase to edit the commit.
# Start interactive rebase
git rebase -i HEAD~5
# Mark the commit to split with 'edit'
# When rebase pauses at that commit:
git reset HEAD~1
# Add changes incrementally and commit
git add file1.txt
git commit -m "First change"
git add file2.txt
git commit -m "Second change"
# Continue the rebase
git rebase --continue
You want to change the order of commits in your history.
Solution: Use interactive rebase to reorder commits.
# Start interactive rebase
git rebase -i HEAD~5
# In the editor, reorder the commit lines as desired
# Save and exit - Git will replay commits in new order
# Resolve any conflicts that arise
git add [conflicted-files]
git rebase --continue
You have multiple small commits that should be combined into one.
Solution: Use interactive rebase to squash commits.
# Start interactive rebase
git rebase -i HEAD~4
# Mark commits with 'squash' or 'fixup' to combine them
# Save and exit, then edit the final commit message
# Force push if already on remote
git push --force-with-lease
Branching Issues
You want to rename a local or remote branch.
Solution: Use git branch -m for local, and push changes for remote.
# Rename local branch
git branch -m old-name new-name
# Rename remote branch
git push origin :old-name new-name
git push origin -u new-name
You need to identify which commit introduced a bug.
Solution: Use git bisect to perform a binary search through history.
# Start bisect session
git bisect start
# Mark current commit as bad
git bisect bad
# Mark a known good commit
git bisect good abc1234
# Git will checkout middle commit - test it
# Mark as good or bad, repeat until found
# End bisect session
git bisect reset
You deleted a file and want to restore it from history.
Solution: Use git checkout to restore from a specific commit.
# Find when the file existed
git log -- path/to/file
# Restore from last known commit
git checkout abc1234 -- path/to/file
# Or restore from branch before deletion
git checkout HEAD~1 -- path/to/file
You want to review what changes will come in before pulling.
Solution: Use git fetch followed by git log to see incoming changes.
# Fetch remote changes without merging
git fetch origin
# See what's changed
git log HEAD..origin/main --oneline
# See actual changes
git diff HEAD origin/main
Advanced Scenarios
git revert abc123
You need to undo changes from a specific commit but with more control.
Solution: Use advanced revert options for different scenarios.
# Revert a merge commit
git revert -m 1 MERGE_COMMIT_HASH # -m 1 keeps main branch's changes
# Revert a range of commits
git revert OLDER_COMMIT..NEWER_COMMIT # Reverts range (excludes OLDER_COMMIT)
# Revert without committing immediately
git revert -n abc123 # Changes staged but not committed
# Partial revert
git revert -n abc123
git reset # Unstage changes if needed
git add -p # Selective staging
git commit -m "Partial revert"
# Revert multiple commits in one go:
git revert --no-commit abc123 def456
git commit -m "Revert two problematic commits"
# View revert changes before committing:
git revert -n abc123 && git diff --cached
git merge feature
You encounter merge conflicts that need to be resolved.
Solution: Step-by-step conflict resolution process.
# Step 1: Pull latest changes (you may see the conflict message)
git pull
# Step 2: Open the conflicted file, look for:
# <<<<<<< HEAD
# your changes
# =======
# their changes
# >>>>>>> branch-name
# Step 3: Manually edit & resolve, remove the conflict markers.
# Step 4: Add the resolved file
git add file.txt
# Step 5: Commit the resolution
git commit -m "Resolved merge conflict in file.txt"
git push origin main
You get a "non-fast-forward" error when trying to push.
Solution: Pull and merge remote changes before pushing.
# Step 1: Pull and merge remote changes
git pull origin main
# Step 2: Resolve any merge conflicts if needed
# Step 3: Push again
git push origin main
# Alternative (if rebasing):
git pull --rebase origin main
git push origin main
git add .
You committed a large file, secret keys, .env, or wrong files.
Solution: Remove the file from history and prevent future commits.
# Step 1: Unstage specific file
git reset HEAD path/to/file
# Step 2: Or remove from commit history (if committed)
git rm --cached path/to/file
# Step 3: Commit the removal
git commit -m "Removed sensitive file"
# Step 4: Push the change
git push origin branch-name
# If already pushed:
# Step 1: Remove the file from history
git filter-branch --force --index-filter \
"git rm --cached --ignore-unmatch path/to/file" \
--prune-empty --tag-name-filter cat -- --all
# Step 2: Force push (team must re-clone or reset)
git push origin --force --all
git commit -m "Fix bug"
You made a typo or wrong message in the last commit.
Solution: Amend the commit to fix the message or author.
# Step 1: Edit last commit message
git commit --amend -m "Corrected commit message"
# Step 2: Push (if already pushed, use force)
git push --force origin branch-name
# For Author:
git commit --amend --author="New Name "
git checkout main
You worked on main or the wrong branch instead of a feature branch.
Solution: Move commits to correct branch and reset the original.
# Step 1: Create a new branch from current state
git checkout -b feature-branch
# Step 2: Reset main back (keep it clean)
git checkout main
git reset --hard origin/main
# Step 3: Push your new feature branch
git push origin feature-branch
Emergency Recovery Scenarios
git reset --hard HEAD~5
You did a hard reset but later realized you needed those commits!
Solution: Use git reflog to find and recover lost commits.
# Find lost commits
git reflog
# Look for entries like:
# abc1234 HEAD@{2}: commit: Add payment gateway
# Recover specific files
git checkout abc1234 -- src/payment.js # Get single file
# Recover entire commit
git branch temp-recovery abc1234
git cherry-pick abc1234..abc1234 # Apply to current branch
# Verify changes
git diff temp-recovery # Compare with recovered branch
git push origin main
You later found API keys in config.yml after pushing to remote.
Solution: Use git-filter-repo to completely purge the file from history.
# Install git-filter-repo (more powerful than BFG)
brew install git-filter-repo # macOS
# Purge file from all history
git filter-repo --path config.yml --invert-paths
# Force push to all branches
git push origin --force --all
git push origin --force --tags
# Team cleanup (everyone must):
git fetch origin
git reset --hard origin/main
git commit -m "Everything"
You made a commit with mixed features and bugfixes that should be separate.
Solution: Use interactive rebase to split the commit into logical pieces.
# Interactive rebase
git rebase -i HEAD~5
# Mark commit with "edit":
edit abc1234 Everything
pick def5678 Other commit
# Reset and recommit
git reset HEAD~1
git add -p # Stage changes piecemeal
git commit -m "Feature A"
git commit -m "Bugfix B"
# Continue rebase
git rebase --continue
git checkout main
git merge feature
You merged a feature branch into main instead of the development branch.
Solution: Undo the merge and redo it properly on the correct branch.
# Undo merge
git reset --hard ORIG_HEAD
# Redo properly
git checkout dev
git merge feature
# Cleanup main (if already pushed)
git checkout main
git revert -m 1 abc1234 # Revert merge commit
git branch -D experimental
You deleted a branch but later realized it had critical code.
Solution: Use git's file system check to find and recover the deleted branch.
# Find dangling commits
git fsck --lost-found
# Identify the branch head
git show abc1234 # Check likely commits
# Recreate branch
git branch experimental abc1234
git push origin main
You get a "non-fast-forward" error when trying to push changes.
Solution: Understand why it's happening and resolve properly.
# Understand why:
git fetch origin
git log --graph --oneline origin/main..main
# Rebase properly:
git rebase -i origin/main
# Force push safely:
git push --force-with-lease
Before doing any destructive operations, create a backup branch:
git branch backup/before-dangerous-operation.
This gives you a safe point to return to if things go wrong.
Always use git push --force-with-lease instead of --force.
It will fail if the remote has new commits that you haven't fetched,
preventing you from overwriting your teammates' work.