Git Recovery Cheat Sheet
Undoing the commit, the push, the rebase and the reset — including how to recover work that looks permanently gone.
Before anything destructive
git status
git stash list
git log --oneline -5
Then take a free escape hatch. A tag costs nothing and makes any mistake below reversible:
git tag backup/before-$(date +%Y%m%d-%H%M%S)
Undo the last commit
git reset --soft HEAD~1 # undo commit, keep changes staged
git reset HEAD~1 # undo commit, keep changes unstaged
git reset --hard HEAD~1 # undo commit AND discard changes — destructive
--soft and mixed are always safe. --hard throws away uncommitted work with
no prompt — the one flag worth pausing on.
Amend
git commit --amend # change message or add staged files
git commit --amend --no-edit # keep message, absorb staged changes
git commit --amend --author="Name <email>"
Amending rewrites the commit. If it was already pushed, you now need a force push — see below.
Unstage and discard
git restore --staged FILE # unstage, keep edits
git restore FILE # discard edits — destructive
git restore . # discard everything unstaged — destructive
git clean -n # DRY RUN: what would be deleted
git clean -fd # delete untracked files and dirs
Always run git clean -n first. It is the only preview you get.
Recovering “lost” commits
Almost nothing is truly lost. Git keeps every commit you had checked out in the reflog for 90 days by default — including after a bad reset, rebase or deleted branch.
git reflog # everything HEAD has pointed at
git reflog show BRANCH # per-branch history
git reset --hard HEAD@{3} # jump back to a reflog entry
git branch recovered HEAD@{3} # safer: recover onto a new branch
Deleted a branch by mistake:
git reflog | grep BRANCHNAME
git branch BRANCHNAME COMMIT_SHA
Commits with no ref at all:
git fsck --lost-found
Force pushing safely
git push --force-with-lease origin BRANCH # refuses if remote moved
git push --force origin BRANCH # overwrites unconditionally
Always prefer --force-with-lease. Plain --force will silently destroy a
colleague’s commits if they pushed while you were rewriting. --force-with-lease
aborts instead.
Rewriting history changes commit SHAs. Anyone else with the branch must
git fetch && git reset --hard origin/BRANCH, not git pull.
Rebase
git rebase main
git rebase --continue # after resolving conflicts
git rebase --skip
git rebase --abort # back to where you started — always safe
If a rebase goes wrong and you have already continued past the point of repair:
git reflog
git reset --hard HEAD@{N} # N = the entry before the rebase began
Reverting a pushed commit
git revert COMMIT # new commit undoing it — safe on shared branches
git revert -m 1 MERGE_SHA # revert a merge, -m 1 keeps the first parent
revert adds history rather than rewriting it, which is why it is the correct
choice for anything already pushed to a shared branch.
Finding what broke
git log --oneline --graph --all -20
git log -S "search string" # commits that added/removed a string
git log -p FILE # full history of one file
git blame FILE
git blame -L 10,20 FILE # just those lines
git bisect start
git bisect bad # current commit is broken
git bisect good v1.2.0 # this one worked
# test, then: git bisect good | git bisect bad
git bisect reset
git log -S is the fastest way to find when a specific line of config or code
appeared — far better than scrolling git log.
Stash
git stash push -m "message"
git stash push -u # include untracked files
git stash list
git stash show -p stash@{0} # view the diff
git stash pop # apply and remove
git stash apply stash@{1} # apply and keep
git stash drop stash@{0}
git stash pop on a conflict leaves the stash in place — you have not lost it,
despite the error message.
Fixing the wrong branch
Committed to main when you meant a feature branch:
git branch feature/work # branch here, keeping the commits
git reset --hard origin/main # move main back — destructive
git checkout feature/work
Fixing author identity
# Just the last commit
git commit --amend --author="Name <email>" --no-edit
# Across a range — rewrites SHAs, needs a force push
git rebase -i HEAD~5 --exec 'git commit --amend --author="Name <email>" --no-edit'
Remotes
git remote -v
git remote set-url origin URL
git fetch --all --prune # drop refs for branches deleted upstream
git branch -vv # local branches and their upstreams