
August 24, 2026
10 min read
Table of Contents
By Kokil Thapa | Last reviewed: August 2026
You’ve just run git reset --hard or git rebase and realized—too late—that you’ve lost commits you still need. The panic sets in: hours of work gone. In practice, Git doesn’t actually delete commits immediately; it keeps them in a hidden log called the reflog. Laravel developers and full-stack engineers alike regularly use git reflog to recover lost commits, but many don’t know the exact steps to make it work reliably. This guide gives you the concrete commands, visual workflows, and real-world gotchas to recover lost commits with git reflog in 2026.
git reflog to list all recent Git actions, find the lost commit’s SHA, then restore it with git reset --hard <SHA> or git cherry-pick <SHA>. The reflog tracks every HEAD change for 30–90 days, letting you recover commits even after resets, rebases, or branch deletions.What is git reflog and how does it track lost commits?
Git’s reflog (reference log) is a local, time-ordered log of every action that changes HEAD—commits, resets, checkouts, rebases, merges, and branch creations. Each entry records the old SHA, the new SHA, the action, and a timestamp. Unlike the commit history, the reflog is not shared between repositories; it’s purely local and survives even after you delete branches or force-push.
In practice, the reflog is your safety net. When you run git reset --hard HEAD~3, the three most recent commits aren’t deleted—they’re just orphaned. The reflog still lists them, and you can restore them until Git’s garbage collector runs (default: 30 days for unreachable commits, 90 days for reflog entries).
reset --hard but remains in the reflog until garbage collection.How do you list lost commits with git reflog?
Run git reflog in your repository root. The output lists every HEAD change in reverse chronological order, with each line showing the SHA, the action, and a descriptive message:
a1b2c3d (HEAD -> main) HEAD@{0}: reset: moving to HEAD~3
e4f5g6h HEAD@{1}: commit: Fix payment gateway timeout
i7j8k9l HEAD@{2}: commit: Add user profile upload
m1n2o3p HEAD@{3}: commit: Refactor checkout controller
q4r5s6t HEAD@{4}: checkout: moving from feature/payment to main
Each HEAD@{n} is a reflog selector you can use in Git commands. The SHA e4f5g6h is the lost commit you want to recover.
To filter the reflog for a specific branch or time window, use:
git reflog show main --since="2 days ago"
git reflog show feature/payment --grep="checkout"
On a real client project, I once recovered a lost Laravel migration by running git reflog show main --since="1 week ago" and spotting the exact SHA before a mistaken git reset --hard.
What are the exact commands to recover a lost commit?
Once you’ve identified the lost commit’s SHA from the reflog, you have three practical recovery options:
1. Hard reset to the lost commit
Use this when you want to completely restore the repository state to the lost commit, discarding any later changes:
git reset --hard e4f5g6h
This moves HEAD and the current branch pointer to the lost commit. All changes after e4f5g6h are lost, so use this only if you’re certain.
2. Soft reset to the lost commit
Use this when you want to keep the working directory and staging area intact, allowing you to re-commit the lost changes:
git reset --soft e4f5g6h
After running this, git status shows all changes from the lost commit staged and ready to commit again. This is safer than a hard reset and is my default choice when recovering lost work.
3. Cherry-pick the lost commit
Use this when you only need the changes from the lost commit, not the entire history. This is ideal if you’ve already committed other work on top and don’t want to discard it:
git cherry-pick e4f5g6h
If the cherry-pick fails due to conflicts, resolve them as you would with a normal merge, then run git cherry-pick --continue.
How do you recover a lost branch with git reflog?
When you delete a branch with git branch -D feature/payment, the commits aren’t immediately lost—they’re still in the reflog. To recover the branch:
- List the reflog to find the last commit on the deleted branch:
git reflog show --date=iso | grep "feature/payment" - Identify the SHA of the last commit on the branch (e.g.,
i7j8k9l). - Recreate the branch at that commit:
git branch feature/payment i7j8k9l - Verify the branch contains the expected commits:
git log feature/payment --oneline
On a production Laravel project, I once recovered a deleted feature/subscription branch this way after a teammate accidentally ran git branch -D. The reflog showed the last commit SHA, and recreating the branch took less than a minute.
What are the common mistakes when using git reflog?
Even experienced developers make these mistakes when recovering lost commits:
- Not checking the reflog immediately. The reflog is local and time-limited. If you wait weeks, the lost commits may be garbage-collected.
- Using the wrong reflog selector.
HEAD@{5}is not the same asmain@{5}. Always verify which branch’s reflog you’re inspecting. - Assuming the reflog is shared. The reflog is local to your repository. If you clone a fresh copy, the reflog won’t contain your lost commits.
- Running
git gcprematurely. Git’s garbage collector removes unreachable commits. Avoid runninggit gcorgit pruneuntil you’re certain you’ve recovered everything. - Not verifying the commit before resetting. Always run
git show <SHA>to confirm the commit contains the changes you expect before resetting or cherry-picking.
In practice, the most common mistake I see is developers running git reflog in the wrong directory. The reflog is tied to the repository root, so if you’re in a subdirectory, the output may not show the commits you expect. Always run git reflog from the repository root.
How do you configure Git to keep reflog entries longer?
Git’s default reflog expiration is 90 days for reachable commits and 30 days for unreachable ones. To extend this, configure Git’s gc.reflogExpire and gc.reflogExpireUnreachable settings:
git config --global gc.reflogExpire "180.days.ago"
git config --global gc.reflogExpireUnreachable "90.days.ago"
To disable reflog expiration entirely (not recommended for most workflows), use:
git config --global gc.reflogExpire "never"
git config --global gc.reflogExpireUnreachable "never"
For repositories where you frequently recover lost work, I recommend setting gc.reflogExpireUnreachable to 60 days. This gives you a longer window to recover lost commits without significantly increasing repository size.
| Setting | Default Value | Recommended Value | Use Case |
|---|---|---|---|
gc.reflogExpire | 90.days.ago | 180.days.ago | Long-term projects where you may need to recover old commits |
gc.reflogExpireUnreachable | 30.days.ago | 60.days.ago | Frequent rebases or resets where commits may become unreachable |
gc.auto | 6700 | 10000 | Delay garbage collection to give more time for recovery |
How does git reflog compare to git fsck for commit recovery?
Both git reflog and git fsck can recover lost commits, but they work differently and have distinct use cases:
| Feature | git reflog | git fsck |
|---|---|---|
| Scope | Tracks HEAD movements (commits, resets, checkouts, rebases) | Scans the entire object database for dangling commits |
| Speed | Fast (O(1) lookup) | Slow (O(n) scan) |
| Output | Human-readable list of HEAD changes | Raw list of dangling objects (SHA only) |
| Use case | Recovering recent lost commits after resets or rebases | Recovering commits lost due to git gc or long-term unreachability |
| Command | git reflog | git fsck --lost-found |
| Recovery command | git reset --hard <SHA> | git show <SHA> then git branch <name> <SHA> |
In practice, git reflog is the first tool you should reach for. It’s faster, more readable, and covers 95% of recovery scenarios. Use git fsck only when the reflog doesn’t contain the lost commit—typically after garbage collection or when the commit was never referenced by HEAD.
git reflog vs git fsck for commit recovery.How do you prevent lost commits in the first place?
While git reflog is powerful, prevention is better than recovery. Here are the practical patterns I use on every project to avoid lost commits:
- Commit early, commit often. Small, frequent commits reduce the risk of losing large chunks of work. Use
git add -pto stage changes incrementally. - Use feature branches. Never work directly on
mainordevelop. Create a branch for every feature or bugfix:git checkout -b feature/user-uploads - Push branches regularly. Even if the work isn’t finished, push your branch to the remote to create a backup:
git push origin feature/user-uploads - Avoid
git reset --hardon shared branches. If you must reset, usegit reset --softorgit revertinstead. - Use
git stashfor WIP changes. If you need to switch branches but aren’t ready to commit, stash your changes:git stash push -m "WIP: user upload validation" - Enable Git’s autosetuprebase. This ensures
git pulluses rebase instead of merge, reducing merge commits:git config --global pull.rebase true - Use Git hooks for safety checks. A pre-commit hook can run tests or linting before allowing a commit. Example
.git/hooks/pre-commit:#!/bin/sh php artisan test || exit 1
For Laravel projects, I also recommend using Laravel’s built-in testing tools in pre-commit hooks. This catches errors before they’re committed, reducing the need for later resets.
Recover lost commits with git reflog—next steps
You now have the exact commands, visual workflows, and real-world patterns to recover lost commits with git reflog in 2026. The key takeaways:
- Run
git reflogimmediately when you realize commits are lost—don’t wait. - Identify the lost commit’s SHA, then choose
git reset --hard,git reset --soft, orgit cherry-pickbased on your needs. - Recover deleted branches by recreating them at the last commit SHA from the reflog.
- Avoid common mistakes: check the reflog in the repository root, verify commit contents before resetting, and don’t run
git gcprematurely. - Extend reflog retention with
git config --global gc.reflogExpireUnreachable "60.days.ago"for longer recovery windows. - Use
git fsckonly as a fallback when the reflog doesn’t contain the lost commit. - Prevent lost commits by committing early, using feature branches, pushing regularly, and avoiding
git reset --hardon shared branches.
If you’re working on a Laravel, Symfony, or eCommerce project and need help with Git workflows, reach out for a consultation. I’ve recovered lost commits on production systems for clients in Nepal and worldwide, and I can help you implement robust Git practices tailored to your workflow.
For more practical Git and development tips, check out my guide on Laravel API best practices or learn how to optimize your website’s technical SEO.

