How to Undo Almost Any Git Mistake

Made a Git mistake? Here's how to undo bad commits, lost branches, force pushes, and more, step by step, without losing your work.

Let's be honest for a second. The moment you realize you just did something bad in Git, your stomach drops a little. Maybe you force pushed over your teammate's work. Maybe you deleted a branch that had two days of unsaved thinking in it. Maybe you just typed git reset --hard without really reading what it does, and now a whole feature is gone.

How to Undo Almost Any Git Mistake

This moment is more common than people admit, the panic search at 1AM for "how to undo git something something please help." So this post exists for that exact moment. Not a Git theory lecture. Just what to do, right now, to get your work back.

Here's the thing most people don't realize until someone tells them: Git almost never actually deletes anything immediately. It hides things. It moves them out of view. But the data is usually still sitting there for weeks, sometimes months, until Git's garbage collector finally cleans it up. That single fact is the reason almost every "mistake" is recoverable if you know where to look. If you ever want the fully technical breakdown of how Git stores its objects internally, the official Git internals documentation is worth a read, though you don't need it to follow along here.

We're going to go through the most common disasters one by one, show you the exact commands, and explain what's actually happening under the hood so you're not just copy pasting blindly.

First, the one command that saves almost everyone: git reflog

Before we get into specific scenarios, you need to know this exists. git reflog is basically Git's private diary. It records every single place your HEAD has pointed to, including commits that are no longer part of any branch. Checkouts, resets, rebases, merges, all of it gets logged.

Run this right now in any repo and see what happens:

git reflog

You'll get something like this:

a1b2c3d (HEAD -> main) HEAD@{0}: commit: fix login bug
e4f5g6h HEAD@{1}: reset: moving to HEAD~1
i7j8k9l HEAD@{2}: commit: add validation logic
m1n2o3p HEAD@{3}: checkout: moving from feature-x to main

Every one of those HEAD@{n} entries is a checkpoint you can jump back to. This is the single most important trick in this entire post, so if you remember nothing else, remember this command exists.

Info: The reflog is local to your machine only. It's not pushed anywhere and your teammates can't see it or use it to recover your work. It's your own personal undo history.

Scenario 1: You committed to the wrong branch

This one is painfully common. You're heads down, you make three commits, and then you notice you never switched off main. Now your commits are sitting where they shouldn't be.

Here's the fix. First, note your recent commit hash (or just count how many commits you need to move), then create the branch you meant to be on, and reset the original branch back.

# Create a new branch at your current point (this keeps the commits)
git branch feature-correct-branch

# Now go back to where main should be, moving those commits off it
git checkout main
git reset --hard HEAD~3

# Switch to your new branch, which still has the commits
git checkout feature-correct-branch

Replace 3 with however many commits you accidentally made. Your work is now living safely on feature-correct-branch, and main is back to where it should be.

Scenario 2: You deleted a branch and now regret it

Someone says "clean up your old branches" in a team meeting and suddenly you're branch-deleting everything in sight, including one that actually had unfinished work. This is where reflog earns its keep again.

Say you deleted a branch called payment-refactor. Run this:

git reflog

Scan through the output for a line that looks like this, usually near where you ran the delete:

a1b2c3d HEAD@{5}: commit: refactor payment gateway logic

That commit hash, a1b2c3d, is your lost branch's last commit. Recreate the branch pointing right at it:

git branch payment-refactor a1b2c3d

And it's back, with every commit intact. This works even if you deleted the branch days ago, as long as Git hasn't run garbage collection since then (which typically happens automatically every couple weeks, not instantly).

Scenario 3: You force pushed and overwrote someone's commits

This is the scary one because it involves the remote, not just your local repo. Someone else's work got overwritten on GitHub or GitLab because of a bad git push --force.

The good news: if the person whose commits got overwritten still has their local repo, their commits are sitting right there safe and sound. They just need to push again. The panic usually comes from not realizing that local copies still have everything.

If the overwritten commits only ever existed on the remote and nobody has them locally, you have two paths:

  1. Check if the remote platform has its own reflog style feature. GitHub, for instance, keeps orphaned commits reachable for a while and you can sometimes find them through the network graph or by searching commit hashes if anyone mentioned them in Slack, PR descriptions, or CI logs.
  2. If someone had cloned or fetched before the force push, their local .git folder has the old commits even without knowing it. Ask around before assuming it's gone.
Warning: A plain git push --force is dangerous on shared branches because it can overwrite others' work without warning. Use git push --force-with-lease instead. It refuses to push if the remote has commits you haven't seen yet, which stops exactly this kind of accident before it happens.

Here's the safer version you should honestly just default to from now on:

git push --force-with-lease

Scenario 4: git reset --hard wiped out your changes

This is the one that makes people feel actual physical dread. You ran a hard reset, your terminal didn't ask for confirmation, and now your files show none of the work you just did.

If the changes were committed, even just once, reflog has you covered exactly like the branch scenario above:

git reflog
# find the commit before your reset
git reset --hard a1b2c3d

But here's the part that trips people up: if your changes were never committed, not even once, Git generally can't help you through reflog because reflog only tracks commits, not uncommitted file edits. This is genuinely the one case where recovery gets harder.

There's a partial rescue for this specific situation if you'd staged the files at any point with git add, even if you never committed:

git fsck --lost-found

This scans your repository for "dangling" objects, orphaned blobs that Git hasn't cleaned up yet. If you'd staged your files before the reset, there's a real chance the content is sitting in one of these dangling blobs. You'll get a list of hashes, and you can inspect any of them with:

git show <hash>

It's not glamorous, and it won't always work if nothing was ever staged, but it's worth trying before assuming everything is gone for good.

Scenario 5: A bad merge or rebase made a mess

Merges and rebases are where a lot of people get lost, mostly because the terminal starts showing conflict markers and everything feels like it's spiraling. The fix here is refreshingly simple though.

If you're mid-merge and want to bail out completely:

git merge --abort

If you're mid-rebase and want out:

git rebase --abort

Both of these put you back exactly where you were before you started, as if the merge or rebase never happened. No half-resolved files, no weird state. This works as long as you haven't run git rebase --continue and completed it. Once a rebase or merge is finished and committed, you're back to reflog territory.

A quick way to think about it

We built a tiny interactive mental model below to make this click. Try clicking the buttons and watch how your work moves between three "zones" in Git. This is really the whole trick behind every recovery method above: your work rarely disappears, it just moves somewhere less visible.

Where Did My Work Go? (Click a button)

Your Commit

This is your commit, safe and visible right now.

That little demo is obviously simplified, but it captures the real mental shift you need. Git mistakes usually don't destroy data, they just relocate it somewhere you're not currently looking.

Undoing a single file, not the whole commit

Sometimes you don't want to undo an entire commit, just one file that got messed up. This is a smaller, calmer fix and worth knowing separately.

To restore one file to how it looked in the last commit, discarding your current uncommitted edits to it:

git checkout -- filename.js

On newer Git versions, the more explicit and recommended command is:

git restore filename.js

To pull a file's content from a specific older commit without touching anything else in your working directory:

git checkout a1b2c3d -- filename.js

A comparison table for quick reference

Here's a table you can bookmark. It maps the mistake to the command, so next time you're panicking you don't have to scroll back through this whole post.

What happened Command to run Works if
Committed to wrong branch git branch new-branch then git reset --hard HEAD~n on the original Always, before pushing
Deleted a branch git branch name <hash-from-reflog> Before garbage collection runs
Force pushed over teammate's work Ask teammate to push their local copy again They still have it locally
Hard reset with committed changes git reset --hard <hash-from-reflog> Changes were committed at least once
Hard reset with uncommitted changes git fsck --lost-found Files were staged with git add first
Bad merge or rebase, still in progress git merge --abort or git rebase --abort Before it's completed

The one habit that prevents most of this

We're not going to pretend there's a magic setting that makes Git mistake-proof, but there is one habit that cuts down how often this happens. Before doing anything destructive, like a reset, force push, or branch delete, just run this first:

git log --oneline -5

It takes two seconds and shows your last five commits so you actually know what you're about to lose or move. Half of these disasters happen because someone ran a command while thinking they were three commits further along than they actually were.

A short mental checklist we actually use before anything destructive:

  • Run git status so you know exactly what's staged, unstaged, and untracked
  • Run git log --oneline -5 so you know which commit you're actually sitting on
  • If it's a shared branch, use --force-with-lease instead of --force, no exceptions
  • If it's a big rebase, cut a quick backup branch first, it costs nothing
Success: If you develop the habit of checking git log or git status before any destructive command, you'll avoid the majority of the scenarios in this post before they even happen.

That backup branch from the checklist above is worth actually showing. Before a big rebase or reset, just run this:

git branch backup-before-rebase

If everything goes fine, delete it later. If it doesn't, you have an exact snapshot waiting, no reflog digging required.

When reflog itself isn't showing what you need

Occasionally the reflog window has already closed, usually because significant time has passed and garbage collection ran, or the repo was cloned fresh somewhere else (reflog doesn't come with a clone, it's local history only). In that case, your remaining options are the ones we listed for the force push scenario: check with teammates, check CI logs for hashes, check pull request diffs on GitHub or GitLab, since those often retain data independently of your local Git history.

Error: If none of the above turns anything up and enough time has passed for garbage collection, the data may genuinely be gone. This is rare, but it's the honest worst case, and it's exactly why regular pushes to a remote matter so much. A remote copy is a copy Git's local garbage collector can't touch.

Frequently Asked Questions

Is git reflog available by default, or do I need to install something?

It's built into Git itself, no setup needed. It's on by default for any normal repository. The only time it's not available is in a bare repository (the kind used purely as a remote server), which doesn't track a working HEAD the same way.

How long do deleted commits actually stay recoverable?

By default, Git keeps reflog entries for 90 days for reachable commits and 30 days for ones that are already unreachable, before its automatic garbage collection can remove them. In practice, most personal or small team repos rarely run aggressive cleanup, so recovery windows are often longer than people expect.

Can I undo a git push after someone else has already pulled it?

You can undo it on your end and on the remote, but you can't force it to disappear from someone else's machine if they already pulled. If the mistake was something sensitive, like committed credentials, treat it as exposed and rotate the credentials rather than relying on history rewriting alone.

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

git reset moves your branch pointer and can rewrite history, which is risky on shared branches. git revert creates a brand new commit that undoes the changes from a previous one, keeping history intact. On any branch other people are also working on, revert is almost always the safer choice.

Why didn't git warn me before the hard reset destroyed my changes?

Git generally assumes you know what a command does when you type it out fully, it doesn't second guess destructive flags like --hard. This is exactly why building the habit of checking git status first matters so much, since Git itself won't stop you.

Does this recovery process work the same on GitHub Desktop or other GUI tools?

The underlying Git data and reflog are identical no matter what interface you use, since GUI tools are just running the same Git commands behind the scenes. Some GUI tools don't expose reflog directly in their interface though, so for actual recovery work, dropping into the terminal is usually faster and more reliable.

Conclusion

If you take one thing away from this, let it be that Git mistakes feel a lot more permanent than they actually are. The data usually isn't gone, it's just hiding, and now you know the exact commands to go find it.

That "oh no" moment is something most people who use Git run into eventually, and knowing which command to reach for is usually the difference between a two-minute fix and a lost afternoon. Bookmark this page, or better yet, keep that comparison table nearby for the next time your terminal makes your heart skip a beat.

About the author

Suptojit Modak
Hi, I'm Suptojit, a Web Developer and tech enthusiast who loves writing clean code and sharing comprehensive developer guides. I founded BytebaseX to make web development concepts accessible to everyone.

Instagram - GitHub - Facebook

Post a Comment