Get Back Everything You Deleted in Git: A Recovery Guide With git reflog
Ran git reset --hard by mistake, deleted a branch, or had a rebase go wrong? Don't panic: Git almost never deletes anything right away. How to recover lost commits, branches and stashes with git reflog.

Contents 11
It's midnight. You've finished three days of work, decided to "tidy up a bit", typed a command into the terminal and pressed Enter:
git reset --hard HEAD~3
A second later it hits you: those three commits were three days of work. git log no longer shows them. Your stomach drops.
The good news: your work is very likely still there. Git never deletes anything committed right away. You've only lost the path to it. Finding that path is what git reflog is for.
In short:
- Git keeps a local log (the reflog) of every point
HEADand branches have been. By default these entries are kept for 90 days.- Use
git reflogto find the lost commit's ID, then bring it back withgit resetorgit branch.- Deleted branches, botched rebases and bad merges are recovered the same way.
- The only thing you can't recover: changes that were never committed. Commit often.
Why doesn't Git delete anything right away?
In Git, every commit is stored in the database under a unique ID (hash) derived from its content. Branches and HEAD are just labels pointing at commits. When you run git reset --hard HEAD~3, Git doesn't delete those three commits; it moves the branch label back three steps. The commits stay put; they just don't show in git log because no branch points to them anymore.
These "orphaned" commits live on until Git's garbage collector (git gc) cleans them up. With default settings that's 90 days for commits that still have a reflog entry and 30 days for those that don't.
git reflog: Git's black box
Like an aircraft's black box, the reflog records everywhere HEAD has been in your repository: every commit, checkout, reset, rebase, merge and pull.
git reflog
The output looks like this:
a1b2c3d HEAD@{0}: reset: moving to HEAD~3
f9e8d7c HEAD@{1}: commit: Add payment screen tests
b4c5d6e HEAD@{2}: commit: Payment API integration
e7f8a9b HEAD@{3}: commit: Fix cart calculation
a1b2c3d HEAD@{4}: checkout: moving from main to payment-feature
The top line is the disastrous reset you just did. Right below, HEAD@{1} is the state just before the reset: the last commit of your three days of work.
An important note: the reflog is local. It lives only in the repository on your machine and is never pushed to a remote. You can't see a state from someone else's computer or from GitHub in your own reflog.
Scenario 1: commits lost after git reset --hard
To return to the state before the reset:
git reset --hard HEAD@{1}
Or directly by commit ID:
git reset --hard f9e8d7c
That's it. git log will show your three commits again.
If you want to be more careful, create a new branch at the recovered point and inspect it there, without touching your current branch:
git branch recovery f9e8d7c
There's a handy shortcut too: commands that move HEAD drastically, like reset, merge and rebase, save the previous position in a special reference called ORIG_HEAD. If you notice right away, git reset --hard ORIG_HEAD does the same job.
Scenario 2: an accidentally deleted branch
git branch -D payment-feature
# Deleted branch payment-feature (was f9e8d7c).
Git already tells you the branch's last commit ID when deleting it. If that line is still in your terminal:
git branch payment-feature f9e8d7c
If the terminal is gone, go back to the reflog. Find the lines where you last switched to that branch or committed on it:
git reflog | grep payment-feature
Recreate the branch with the commit ID you find.
Scenario 3: a messed-up rebase
You resolved conflicts wrongly during a rebase and the result is a mess. If the rebase isn't finished yet, the easiest way out is:
git rebase --abort
If it's finished, look in the reflog for the line before the rebase started. It's usually the entry just below the "rebase (start)" line:
c3d4e5f HEAD@{5}: rebase (finish): returning to refs/heads/payment-feature
...
9a8b7c6 HEAD@{9}: rebase (start): checkout main
f9e8d7c HEAD@{10}: commit: Add payment screen tests
git reset --hard HEAD@{10}
The branch goes back to how it was before the rebase.
Scenario 4: a dropped stash
You ran git stash drop, or git stash clear by mistake. Stashes are actually commits too, but they don't show up in the normal reflog. To find them, use Git's tool for scanning orphaned objects:
git fsck --unreachable | grep commit
Look at each commit ID's contents with git show <id>, and when you find the right stash:
git stash apply <id>
What you can't recover
The reflog is powerful but not magic. Recovery is hard or impossible when:
- Changes were never committed. If you wipe uncommitted changes in your working directory with
git reset --hardorgit checkout -- ., Git never saved them and can't bring them back. The one exception: files you added to the staging area withgit addwere written to Git's database and can be found withgit fsck --lost-found. But the file names are lost, and you'll have to inspect contents one by one. - Commits cleaned up by the garbage collector. Once the time is up and
git gchas run, there's no way back. - State on another computer. A fresh copy of the repository (
git clone) has an empty reflog.
A remote branch overwritten by a force push
If someone overwrote commits on a remote branch with git push --force, the fix is usually a local copy that still has them: the repository of any teammate who pulled those commits earlier. That person can find the old state in their own reflog or branch and push it again.
To prevent this accident, use this instead of --force:
git push --force-with-lease
It refuses the push if the remote branch differs from what you last knew, that is, if someone pushed a new commit you haven't seen. It keeps you from wiping out someone else's work.
Good habits
- Commit small and often. Anything committed can be recovered. You can make a "WIP" commit before a task is done and tidy it up later.
- Create a backup branch before risky operations.
git branch backupbefore a big rebase takes one second. - Use
--force-with-lease, not bare--force. - Type
git reflogbefore you panic. What you think you've lost is most likely there.
Frequently asked questions
What's the difference between git reflog and git log?
git log shows commit history backward from a branch; it only sees commits reachable from that branch. git reflog shows every point HEAD has been locally, in time order, including commits no branch points to anymore.
How long are reflog entries kept?
By default, reflog entries are kept for 90 days, and entries for commits no longer reachable from any branch for 30 days. You can change these with the gc.reflogExpire and gc.reflogExpireUnreachable settings.
Can I fix a mistake on GitHub with the reflog?
If those commits once existed in your own local repository, yes: find them in your local reflog and push them again. But the reflog doesn't keep history from the remote server.
Do my IDE's Git tools show the reflog?
Many IDEs and Git GUIs (e.g. the Git window in JetBrains IDEs) offer a reflog-like history or a "local history" feature. But the most reliable and universal way is git reflog in the terminal.
Using version control well determines both a software team's speed and its safety. If you want to grow your projects with solid Git workflows, CI/CD and development infrastructure, reach us through our web application development page.


