Kokil Thapa - Professional Web Developer in Nepal
Freelancer Web Developer in Nepal with 15+ Years of Experience

Kokil Thapa is an experienced full-stack web developer focused on building fast, secure, and scalable web applications. He helps businesses and individuals create SEO-friendly, user-focused digital platforms designed for long-term growth.

Recover Lost Commits with git reflog

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.

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).

Git Reflog TimelineHEAD@0AHEAD@1BHEAD@2CHEAD@3Dreset --hardHEAD@4BHEAD@5EreflogLost commit Dstill in refloguntil GC runs
Git reflog tracks every HEAD movement. Commit D is lost after 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.

Git Recovery CommandsFound lost commit SHA?NoCheck reflog againYesNeed all history?Need only changes?Need to keep later work?git reset --hard <SHA>git reset --soft <SHA>git cherry-pick <SHA>
Decision tree for choosing the right Git recovery command based on your needs.

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:

  1. List the reflog to find the last commit on the deleted branch:
    git reflog show --date=iso | grep "feature/payment"
  2. Identify the SHA of the last commit on the branch (e.g., i7j8k9l).
  3. Recreate the branch at that commit:
    git branch feature/payment i7j8k9l
  4. 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 as main@{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 gc prematurely. Git’s garbage collector removes unreachable commits. Avoid running git gc or git prune until 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.

SettingDefault ValueRecommended ValueUse Case
gc.reflogExpire90.days.ago180.days.agoLong-term projects where you may need to recover old commits
gc.reflogExpireUnreachable30.days.ago60.days.agoFrequent rebases or resets where commits may become unreachable
gc.auto670010000Delay 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:

Featuregit refloggit fsck
ScopeTracks HEAD movements (commits, resets, checkouts, rebases)Scans the entire object database for dangling commits
SpeedFast (O(1) lookup)Slow (O(n) scan)
OutputHuman-readable list of HEAD changesRaw list of dangling objects (SHA only)
Use caseRecovering recent lost commits after resets or rebasesRecovering commits lost due to git gc or long-term unreachability
Commandgit refloggit fsck --lost-found
Recovery commandgit 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 fsckgit reflogFast, human-readableTracks HEAD movementsBest for recent lossesUse firstgit fsckSlow, raw outputScans object DBBest for GC'd commitsUse as fallback
When to use 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:

  1. Commit early, commit often. Small, frequent commits reduce the risk of losing large chunks of work. Use git add -p to stage changes incrementally.
  2. Use feature branches. Never work directly on main or develop. Create a branch for every feature or bugfix:
    git checkout -b feature/user-uploads
  3. 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
  4. Avoid git reset --hard on shared branches. If you must reset, use git reset --soft or git revert instead.
  5. Use git stash for 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"
  6. Enable Git’s autosetuprebase. This ensures git pull uses rebase instead of merge, reducing merge commits:
    git config --global pull.rebase true
  7. 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 reflog immediately when you realize commits are lost—don’t wait.
  • Identify the lost commit’s SHA, then choose git reset --hard, git reset --soft, or git cherry-pick based 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 gc prematurely.
  • Extend reflog retention with git config --global gc.reflogExpireUnreachable "60.days.ago" for longer recovery windows.
  • Use git fsck only 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 --hard on 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.

Frequently Asked Questions

git reflog is a local log of every HEAD movement in your repository—commits, resets, checkouts, merges. It records the SHA-1, action, and timestamp. When you lose a commit (e.g., after a hard reset or rebase), reflog lets you find the orphaned SHA and restore it with git checkout or git reset. Unlike git log, reflog tracks all reference changes, including those no longer reachable from any branch or tag.

Run git reflog in your terminal. The output lists recent HEAD movements with entries like "abc1234 HEAD@{2}: commit: message". Each entry shows the commit hash, reflog index (HEAD@{n}), action, and message. Use git reflog show branch-name to filter for a specific branch. For older entries, add --date=iso to see timestamps, or pipe to less for pagination.

After locating the SHA (e.g., abc1234) in git reflog, run git checkout abc1234 to inspect the commit. To restore it to your current branch, use git reset --hard abc1234. If the commit was part of a deleted branch, create a new branch first: git branch recovered-branch abc1234. Always verify with git log afterward to confirm the recovery.

Yes. A git reset --hard moves HEAD but doesn’t delete commits immediately. The reflog retains the pre-reset SHA (e.g., HEAD@{1}). Run git reflog to find it, then git reset --hard abc1234 to restore. Commits remain in reflog for 30 days by default (configurable via gc.reflogExpire), so act quickly if disk space is low.

Yes. Rebases rewrite history, but reflog tracks every step. After a rebase, run git reflog to see entries like "HEAD@{3}: rebase finished: returning to refs/heads/main". The pre-rebase commits appear earlier in the log. Use git reset --hard HEAD@{5} to revert to the state before the rebase. For interactive rebases, reflog entries include "pick" or "squash" actions.

Git retains reflog entries for 30 days by default for unreachable commits (90 days for reachable ones). This is controlled by gc.reflogExpire and gc.reflogExpireUnreachable settings. To extend it, run git config --global gc.reflogExpire "60.days". Note that git gc (garbage collection) may prune old entries sooner if disk space is constrained.

Yes. reflog is purely local and tracks all HEAD movements, including commits never pushed. Run git reflog to find the SHA, then restore it with git reset --hard abc1234. If the commit was part of a local branch later deleted, create a new branch from the SHA: git branch recovered abc1234. Remote repositories are irrelevant here—reflog only cares about your local repo.

git log shows the commit history reachable from the current HEAD, while git reflog tracks every HEAD movement, including orphaned commits. For example, after a hard reset, git log won’t show the lost commit, but reflog will. reflog entries include actions like "reset" or "checkout", making it easier to trace how commits were lost. Use reflog to find the SHA, then inspect it with git show abc1234.

Run git reflog to find the last commit of the deleted branch (look for entries like "branch-name@{1}: commit: message"). Note the SHA (e.g., abc1234), then recreate the branch: git branch branch-name abc1234. If unsure which entry corresponds to the branch, use git reflog show branch-name before deletion. Verify with git log branch-name afterward.

Yes. Pipe the reflog output to grep: git reflog | grep "your message". For case-insensitive searches, add -i: git reflog | grep -i "message". To see the full reflog entry (including SHA and action), use git reflog --grep="message". This is faster than manually scanning hundreds of entries, especially in large repositories.

git gc (garbage collection) may prune unreachable commits older than the reflog expiry period (default 30 days). If you run git gc --prune=now, it removes all unreachable objects immediately, including those still in reflog. To prevent this, recover the commit first, or set gc.reflogExpire to a longer period (e.g., 90.days) before running gc.

Yes. reflog records merge and cherry-pick actions. After a merge, run git reflog to find the pre-merge state (e.g., HEAD@{1}). Undo the merge with git reset --hard HEAD@{1}. For cherry-picks, look for "cherry-pick" in the reflog and reset to the entry before it. Always check git status afterward to confirm the undo.

reflog tracks stash operations. Run git reflog and look for entries like "stash@{0}: WIP on branch: abc1234 message". If the stash pop failed or lost commits, find the pre-pop SHA (e.g., HEAD@{2}) and reset to it: git reset --hard HEAD@{2}. Alternatively, use git stash list to see remaining stashes and reapply them.

Most GUI clients expose reflog, but the interface varies. In GitKraken, open the "Reflog" tab in the left panel. In Sourcetree, go to Repository > View Reflog. CLI commands (git reflog) are universal and work regardless of GUI. For recovery, CLI is often faster—GUIs may hide reflog entries or limit search functionality.

Create a backup branch before recovery: git branch backup-before-recovery. Alternatively, clone the repo to a temporary directory and test reflog commands there. Use git reflog --dry-run (if available) or inspect commits with git show abc1234 before resetting. Avoid git reset --hard until you’re certain of the target SHA.

Share this article

Quick Contact Options
Choose how you want to connect me: