HomeProjectsBlogContact

Undo Almost Any Git Mistake: reset, revert, reflog and Friends

Committed to the wrong branch? Deleted work? Pushed something you shouldn't have? A calm, copy-paste guide to undoing the Git mistakes everyone makes, without making them worse.

Undo Almost Any Git Mistake: reset, revert, reflog and Friends

Git has a reputation for being scary, mostly because the first time something goes wrong, people panic and type commands they found in a hurry. Here's a secret that takes the fear away: Git almost never deletes anything for real. If you committed it at some point, it's very likely still recoverable.

Below are the most common Git mistakes and the exact commands to undo them. Before running anything, check git status. It tells you more than people give it credit for.

"I want to throw away changes in a file"

You edited a file and want it back the way it was at the last commit:

git restore path/to/file.js

Careful: uncommitted changes discarded this way are truly gone. This is one of the few commands in this list with no safety net.

"I staged something by accident"

git restore --staged path/to/file.js

The changes stay in your working directory; they're just no longer staged.

"My last commit message has a typo" (or I forgot a file)

If you haven't pushed yet:

git add forgotten-file.js
git commit --amend -m "Better message"

Amending rewrites the last commit. That's fine locally, but don't amend commits others have already pulled.

"Undo my last commit but keep the changes"

git reset --soft HEAD~1

The commit disappears, and its changes go back to being staged, ready to recommit. Use --mixed (the default) if you want them unstaged instead.

The one to be careful with:

git reset --hard HEAD~1

This removes the commit and discards the changes from your working directory. (Still recoverable via reflog, below, but don't make it a habit.)

"I already pushed a bad commit"

Once a commit is on a shared branch, don't rewrite history. Make a new commit that undoes it:

git revert <commit-sha>
git push

revert is the polite undo: history stays intact and teammates don't get broken branches. Here's the rule of thumb: reset for local mistakes, revert for shared ones.

"I committed to main instead of a feature branch"

If you haven't pushed yet:

git switch -c my-feature     # new branch that keeps the commits
git switch main
git reset --hard origin/main  # put main back where the remote is

Your commits now live on my-feature, and main is clean.

"I need to grab one commit from another branch"

git cherry-pick <commit-sha>

It copies that commit onto your current branch. Handy for hotfixes.

"I lost commits after a reset / rebase / deleted branch"

Meet your new best friend:

git reflog

The reflog records where HEAD has been, including commits that no branch points to anymore. Find the entry from before the mistake, then:

git branch rescue <sha-from-reflog>

Now your work lives on the rescue branch. Entries stick around for a good while by default (weeks to months), so this works long after the "oh no" moment.

"A merge or rebase went sideways"

While it's still in progress:

git merge --abort
git rebase --abort

Both put you back exactly where you started. Already finished? Use the reflog to find the pre-merge state.

"I need to switch branches but I'm mid-change"

git stash push -m "half-done navbar"
git switch other-branch
# ...later
git switch -
git stash pop

Name your stashes. Future you will not remember what stash@{3} was.

"I have to force push"

Sometimes you do (after cleaning up a feature branch, for instance). Use the safer version:

git push --force-with-lease

It refuses to overwrite the remote if someone else pushed in the meantime. Plain --force would wipe their work without asking.

"I committed a password or API key"

Removing it in a new commit is not enough. It's still in history, and bots scan public repos constantly. Rotate the key first, then clean up. Full steps here: leaked an API key? do this next.

Habits that prevent most of this

  • Commit small and often. Small commits are easy to revert and easy to understand.
  • Branch for everything. Branches are free. Mistakes on a branch are cheap.
  • Run git status and git diff --staged before committing. Thirty seconds that saves hours.
  • Pull before you push, and prefer git pull --rebase on personal branches for a tidy history.

Cheat sheet

Situation Command
Discard file changes git restore <file>
Unstage a file git restore --staged <file>
Fix last commit (unpushed) git commit --amend
Undo last commit, keep changes git reset --soft HEAD~1
Undo a pushed commit git revert <sha>
Find "lost" commits git reflog
Abort a merge/rebase git merge --abort / git rebase --abort
Force push safely git push --force-with-lease

FAQ

What's the difference between git reset and git revert?

reset moves your branch pointer backwards, effectively rewriting history. revert adds a new commit that undoes an old one. Reset suits local, unpushed work; revert is for anything already shared.

Can I recover a deleted Git branch?

Usually, yes. Run git reflog, find the last commit of that branch, and recreate it with git branch <name> <sha>.

Is git reset --hard dangerous?

It discards uncommitted changes permanently. Committed work can still be recovered through the reflog, but anything you never committed is gone.

Keep reading

More from the workbench

All articles →