Git makes it hard to truly lose work, but it is easy to panic when something goes wrong. This guide covers the most common "how do I undo" situations, from safest to most powerful.
Rule of thumb: if the commits are already pushed and shared, prefer commands that add new history (revert) over commands that rewrite it (reset, rebase).
Discard uncommitted changes to a file
git restore path/to/file.ts # discard working changes
git restore --staged path/to/file.ts # unstage, keep changesFix the last commit message or add a forgotten file
git add forgotten-file.ts
git commit --amend -m "Better message"Only amend commits that have not been pushed, or you will need to force-push.
Undo the last commit but keep the changes
git reset --soft HEAD~1 # changes stay staged
git reset HEAD~1 # changes stay, unstagedThrow away the last commit completely
git reset --hard HEAD~1This discards the changes. If you regret it, see the reflog section below.
Undo a commit that is already pushed
Create a new commit that reverses it. History stays intact for everyone.
git revert <commit-sha>
git pushCommitted to the wrong branch
Move the commit to a new branch and remove it from the current one:
git branch feature/my-work # new branch pointing at your commit
git reset --hard HEAD~1 # remove it from the current branch
git switch feature/my-workTo move it to an existing branch instead, use git cherry-pick <sha> on that branch.
Recover "lost" commits with the reflog
The reflog records where HEAD has been, including commits you reset away.
git reflog
# a1b2c3d HEAD@{0}: reset: moving to HEAD~1
# 9f8e7d6 HEAD@{1}: commit: Add payment retry logic
git reset --hard 9f8e7d6 # or: git branch recovered 9f8e7d6Unreachable commits are kept for a while before garbage collection, so recovery is usually possible for weeks.
Undo a bad merge or rebase
Right after a merge or rebase, ORIG_HEAD points to where you were before:
git reset --hard ORIG_HEADFor a merge commit that is already pushed, revert it with the parent you want to keep: git revert -m 1 <merge-sha>.
Force-pushing safely
If you must rewrite pushed history on your own branch, use:
git push --force-with-leaseIt refuses to overwrite commits someone else pushed in the meantime.
Key takeaways
restorefor files,resetfor local commits,revertfor shared commits.- The reflog can recover almost any commit you reset away.
- Avoid rewriting shared history; when necessary, use
--force-with-lease.