How to Recover Lost Git Commits Using Reflog and Fsck

How to Recover Lost Git Commits Using Reflog and Fsck EduTechBuddy.com © edutechbuddy.com
How to Recover Lost Git Commits Using Reflog and Fsck © edutechbuddy.com
Learn how to restore lost commits in Git after a hard reset, deleted branch, or rebase error using reflog and fsck. This guide explains step-by-step recovery methods for typical mistakes, with real command examples and practical advice for beginners.

When you erase work in Git by mistake, it can seem like a disaster. Still, most local errors can be fixed if you know where to look. If you ran git reset --hard and lost recent commits, deleted a branch, or made changes on a detached HEAD, Git's internal logs and object storage can help you recover—if you act before the data expires. Git’s reflog tracks every update to references like HEAD and local branches. This lets you find commits that are no longer reachable after a reset, rebase, or branch deletion. The reflog stays local to your repository and does not transfer when cloning, so a new clone cannot reproduce the original reflog history (Git reflog documentation).

Understanding Git's Reflog and Recovery Window

Git keeps a private log called the reflog, which records every position your HEAD and branch tips have held. This log is crucial for restoring commits that seem lost after a reset, branch deletion, or rebase. To see the reflog, run:

git reflog

Each entry lists a commit hash and a description of the action that moved HEAD. By default, reflog entries for reachable commits last 90 days. Entries for unreachable commits (those not referenced by any branch or tag) last 30 days. You can change these periods with the gc.reflogExpire and gc.reflogExpireUnreachable settings (Git config documentation). Unreachable objects in the Git object database are subject to garbage collection and usually get pruned after two weeks, as set by gc.pruneExpire. Since the reflog is local, cloning a repository starts a new log with only the clone event recorded.

Step-by-Step Fixes for Common Git Mistakes

Here are practical solutions for frequent Git errors, each with the relevant command and context:

  • Committed on the wrong branch: Create a new branch at the current commit, then move the original branch back:
  • git switch -c feature
    git switch main
    git reset --hard HEAD~1
  • Using git switch -c <branch> creates a new branch at the current commit and switches to it. This makes the commit reachable and protects your work.
  • Last commit was too early: Remove the last commit but keep changes staged:
  • git reset --soft HEAD~1
  • This keeps the reverted commit’s changes as staged content. Unlike --hard, it does not discard them.
  • Typo in the last commit message: Amend the message:
  • git commit --amend -m "new message"
  • Amending a commit rewrites history and creates a new commit object. Use this for local commits that have not been published, as recommended in the official documentation.
  • Staged the wrong file: Unstage it:
  • git restore --staged <file>
  • Ran git reset --hard: Use the reflog to find the previous commit and reset:
  • git reflog
    git reset --hard HEAD@{1}
  • After a hard reset, the reflog still records the previous commit. You can recover lost work if you act before garbage collection prunes unreachable objects.
  • Deleted a branch: The deletion message prints the last commit hash. Recreate the branch at that hash:
  • git branch feature c67023a
  • If you missed the message, search the reflog for the branch’s last commit.
  • Committed on a detached HEAD: Find the commit hash in the warning or reflog, then create a branch:
  • git switch -c rescue f449b13
  • Creating a branch at the commit makes it reachable and keeps it from being pruned.
  • A merge or rebase went wrong: Abort the operation:
  • git merge --abort
    git rebase --abort
  • Or, after completion, reset to ORIG_HEAD:
  • git reset --hard ORIG_HEAD
  • Pushed a bad commit: Revert it with:
  • git revert --no-edit HEAD
    git push origin main
  • Dropped a stash: The drop command prints the stash's commit hash. Apply it directly:
  • git stash apply 82f6bc5f139abbd879ec42fc05a93581470fccb0
  • Lost staged changes: Use git fsck --lost-found to find dangling blobs and recover file contents. The git fsck command checks the validity of objects in the database and can help identify unreachable commits, trees, and blobs. The --lost-found option writes these objects into .git/lost-found for inspection.

How to Use Reflog for Commit Recovery

When a hard reset removes recent commits from git log, the reflog still records their hashes. For example, after running git reset --hard HEAD~2, you can restore the previous state with:

git reflog
git reset --hard HEAD@{1}

If you do not want to move your current branch, create a new branch at the desired commit:

git branch rescue <hash>

This method is also described in the Pro Git data recovery guide. Creating a branch at a recovered commit is a recommended way to make the commit reachable again and prevent it from being lost during garbage collection.

Recovering Commits from a Deleted Branch

When deleting a branch with git branch -D, Git prints the last commit hash. Use this hash to recreate the branch. If you missed the message, search the reflog for the branch's last commit message and use that hash to restore the branch. The reflog records updates to branch tips, so you can recover deleted branches as long as the relevant entries have not expired or been pruned.

Detached HEAD and Lost Commits

Committing on a detached HEAD leaves the new commit unconnected to any branch. Git warns you and shows the commit hash. Copy this hash or find it in the reflog, then create a new branch at that commit to recover your work. The git switch -c <branch> <hash> command is designed for this, as documented in the official git-switch documentation.

Undoing Merges and Rebases

During a merge or rebase conflict, abort the operation to return to the previous state. If the operation has already finished, ORIG_HEAD points to the tip before the change. Resetting to ORIG_HEAD restores the repository to that point. Running another reset will overwrite ORIG_HEAD, but the reflog still tracks earlier positions. Always commit or stash uncommitted changes before using reset --hard, since it discards local modifications. The git reset --hard command resets the index and working tree, discarding any changes to tracked files since the specified commit (Git reset documentation).

Recovering After a Push

Once a commit is pushed to a shared repository, rewriting history can disrupt collaboration. Instead, use git revert to create a new commit that undoes the changes. This keeps the shared history intact and avoids the need for force-pushing.

Finding Lost Work with Fsck

If the reflog no longer contains the lost commit, git fsck --lost-found can help find dangling objects. For example, if you dropped a stash, the command prints the stash's commit hash, which you can apply directly. If you lost staged changes to a hard reset, git fsck --lost-found lists dangling blobs. These appear in .git/lost-found/other/ and can be recovered manually, though file names are not preserved. Inspect these objects before running aggressive cleanup or garbage collection, since object reachability can change and recovery may become impossible after pruning (Git fsck documentation).

What Git Cannot Restore

Edits that were never staged or committed cannot be recovered by Git. In these cases, check your code editor's local history. Commits and objects beyond the reflog and garbage collection expiry windows are also at risk, as is any repository that has been deleted. The default recovery window is 90 days for reachable reflog entries, 30 days for unreachable entries, and two weeks for loose unreachable objects, unless configured otherwise.

Frequently Asked Questions

  • How long can I recover lost commits? By default, reflog entries last 90 days for reachable commits and 30 days for unreachable commits. Unreachable objects are pruned after two weeks unless configured otherwise. You can change these settings in your Git configuration.
  • Does the reflog survive a clone? No. Each clone starts with its own reflog, containing only the clone event. The reflog is repository-local and not part of the commit history transferred through cloning.
  • Can I recover uncommitted changes? Only if they were staged with git add. Use git fsck --lost-found to find blobs. Unstaged edits are not recoverable by Git.
  • What is the difference between git reset --hard and git revert? reset --hard moves the branch and discards changes, suitable for local work. revert creates a new commit that undoes a previous one, which is safer after pushing.
  • What is ORIG_HEAD? It is a pointer to the previous tip before a merge, rebase, or reset. Each new reset overwrites it, but earlier positions are still tracked in the reflog.

Practical Tips for Git Recovery

  • Start with git reflog to find lost commits. The reflog records every update to HEAD and branch tips, making it the main tool for commit recovery.
  • Use git reset --hard HEAD@{1} or create a rescue branch at the desired hash to restore lost work.
  • After deleting a branch, use the printed hash to recreate it, or search the reflog for the last commit.
  • Abort merges and rebases during conflicts to restore the previous state, or reset to ORIG_HEAD after completion.
  • After a push, use git revert to undo changes without rewriting history, keeping collaboration safe.
  • Use git fsck --lost-found for staged changes lost to a hard reset, and check .git/lost-found for recoverable objects before running garbage collection.

For a deeper look at how Git stores data and why these recovery methods work, see the earlier breakdown on Git fundamentals. For more technical details, check the official Git reflog documentation.

Learning to use these recovery tools is a valuable digital skill for students, educators, and professionals working with code or digital projects. Understanding Git’s internal mechanisms helps prevent data loss and builds confidence in managing version control in educational and collaborative environments.

Camila Ferreira Editor EduTechBuddy.com
Co-Founder

Camila Ferreira

Camila Ferreira is the Co-Founder of EduTechBuddy, where her editorial focus is programming education and practical software development skills. Her primary subjects include Python programming, Git version control, and the fundamental concepts beginners need to understand when working with code.