Skip to content
ExponaBLOG
GIT & GITHUB FOR PROFESSIONAL DEVELOPERS · DAY 020 / 100

Git reflog: recover lost commits — a step-by-step guide

Almost nothing in Git is truly lost.

Expona Admin5 min read

You've just deleted a branch that contained three days of work. Your stomach drops. But before you panic, know this: Git reflog: recover lost commits — a step-by-step guide is the lifeline you need. Almost nothing in Git is truly lost, and the reflog is your safety net.

Understanding reflog: A log of where HEAD and branches pointed

The reflog—short for reference log—is often misunderstood. It's not a record of commits themselves, but rather a chronological history of where your HEAD pointer and branch references have moved over time. Think of it as a detailed breadcrumb trail of your repository's navigational history.

When you check out a branch, rebase, reset, or merge, Git records that movement. Every time you run git checkout main, create a new branch, or force-push, the reflog captures it. This makes reflog invaluable for recovering work that seems to have vanished.

Here's the critical distinction: your commit history (git log) shows the ancestry of reachable commits. Your reflog shows every place your references have been, whether those commits are currently reachable or not. A commit can disappear from git log but still exist in the reflog for 30–90 days.

In practical teams, this distinction has saved us countless times. A developer accidentally force-pushes to a shared branch, a rebase goes wrong, or someone performs an interactive rebase that squashes away intermediate work. The reflog doesn't judge—it just records.

Finding the lost commit using git reflog

The first step in recovery is visibility. Run git reflog to see the recent movements of HEAD:

bash
git reflog

This displays output similar to:

bash
a1b2c3d HEAD@{0}: checkout: switching to main
f4e5d6c HEAD@{1}: commit: add payment gateway integration
2k3l4m5 HEAD@{2}: reset: moving to HEAD~2
7n8o9p0 HEAD@{3}: rebase -i (finish): returning to refs/heads/feature/checkout
q1r2s3t HEAD@{4}: rebase -i (start): checkout 8b9c0d1
u4v5w6x HEAD@{5}: checkout: switching to feature/checkout

Each line represents a movement. The syntax HEAD@{n} refers to the nth previous value of HEAD. The timestamp and operation description help you find exactly what you're looking for.

If you're searching for a specific branch's history, use:

bash
git reflog show branch-name

For example:

bash
git reflog show feature/checkout

This shows only movements of the feature/checkout reference, making it easier to spot when the branch was at a particular state.

In our experience, the moment you run reflog after realizing something's missing, you'll feel the tension ease. The information is almost always there. You'll see the commit hash and understand exactly what operation led to the loss.

Recovering lost commits by creating a branch

Once you've located the commit in your reflog, recovery is straightforward. The safest approach is to create a new branch pointing to that commit. This preserves the lost history without modifying any existing branches.

Suppose from the reflog above, you can see that commit f4e5d6c (the payment gateway integration) is what you need to recover. Create a branch from it:

bash
git branch rescue-payment f4e5d6c

Or, if you prefer to reference it by reflog position:

bash
git branch rescue-payment HEAD@{1}

Both commands create a new branch called rescue-payment pointing to that commit. You can then check it out and examine the work:

bash
git checkout rescue-payment
git log --oneline -5

Now the lost commits are reachable again, and you can decide how to proceed. You might cherry-pick specific commits onto your main branch, merge the entire branch, or simply copy code from the rescue branch into your working directory.

A common real-world scenario: a developer has been working on a feature branch, makes several commits, but then accidentally runs git reset --hard origin/main before pushing. Their local commits vanish from the branch. The reflog still knows they existed:

bash
git reflog show feature/important-work
# Output shows the commits were at HEAD@{5}
git branch restore-important-work HEAD@{5}
# All commits are now accessible again

The key principle: you're never deleting anything when you create a recovery branch. You're just making an unreachable commit reachable again.

Understanding the time limit: When commits are pruned

Reflog entries don't last forever. By default, Git keeps reflog records for unreachable commits for about 30 days, though this can extend to 90 days depending on your Git configuration and system garbage collection policies.

Check your current reflog expiration setting:

bash
git config --global gc.reflogExpire

If it returns nothing, the default (30 days) applies. You can extend it if needed:

bash
git config --global gc.reflogExpire 90.days

This extends the reflog retention period to 90 days for unreachable commits. For commits reachable from branches or tags, reflog entries persist indefinitely.

The practical implication: don't wait months to recover lost work. If something goes wrong, check the reflog within days. In team environments, this becomes a support question: "I lost a commit—how do I get it back?" Answer: "Run git reflog now. You have at least 30 days."

Garbage collection happens periodically during heavy Git operations like git repack or git gc. Once the reflog expires and garbage collection runs, the unreachable commits may be permanently deleted. However, even then, if you have any reference to a commit (a branch, tag, or even a reflog entry in your team's centralized logs), it can still be recovered.

Common mistakes to avoid

Mistake 1: Assuming the reflog shows all Git history. It doesn't. The reflog is local to your repository. If you clone a fresh copy of a repository, it won't have the previous reflog from another machine. The reflog is also not shared across team members—each developer has their own.

Mistake 2: Not acting quickly enough. Reflog entries expire. If weeks pass without recovery, entries may be pruned. Make recovery a priority if you discover lost commits.

Mistake 3: Directly resetting HEAD to a reflog entry. Instead of git reset --hard HEAD@{3}, which rewrites history, create a recovery branch first. This gives you a safe checkpoint to examine the lost work without risk.

Mistake 4: Forgetting that reflog is machine-specific. If you work across multiple machines, the reflog on your laptop differs from the reflog on your workstation. Lost commits might still exist on the machine where you originally worked.

Mistake 5: Ignoring the branch-specific reflog. If you lost work on a specific branch, use git reflog show branch-name rather than the global reflog. This narrows your search significantly.

Key takeaways

  • The reflog records movements of HEAD and branch references, making it distinct from commit history and crucial for recovery.
  • Run git reflog immediately when you discover lost commits to identify the commit hash and understand what happened.
  • Create a recovery branch from the lost commit using git branch rescue-name commit-hash rather than directly resetting, keeping your recovery process safe.
  • Remember that reflog entries for unreachable commits expire after 30–90 days by default; prioritize recovery.
  • The reflog is local and machine-specific; if you use multiple machines, check the reflog on the machine where you originally worked.
  • Use git reflog show branch-name to focus on movements of a specific branch when narrowing your search.
ShareXLinkedInReddit

Found this useful? Support the writing.

Buy me a coffee
Written by
Expona Admin
Site administrator

Comments

Loading comments…

Leave a comment

Comments are reviewed before they appear. Be kind and stay on topic.

Related articles