Chapter 2.1 — git reflog — Time Machine☕ 20 min read

git reflog — Time Machine

Jab bhi "Oh shit" bolo, pehla command ho git reflog. 90 din ka safety net tumhare paas hai.

01Reflog — Git ka CCTV

git reflog stands for Reference Log. It records every single move of the HEAD pointer — every commit, checkout, merge, rebase, and reset.

Every time you commit, checkout, merge, rebase, or reset, reflog silently adds an entry. It is always watching, always recording.

Even after a git reset --hard that seems to erase commits, those commits still exist in the object store. They are unreachable from any branch, but reflog remembers exactly where they are.

Entries are indexed: HEAD@{0} is the latest position, HEAD@{1} is one move ago, HEAD@{2} is two moves ago.

Reflog is LOCAL only. It does not travel with clones or fetches. It is your personal safety net on your machine.

Default retention: 90 days for unreachable commits. After that, git gc permanently deletes them.

# View your recent Git moves
git reflog
# a1b2c3d HEAD@{0}: reset: moving to HEAD~2       (you did a reset)
# e4f5g6h HEAD@{1}: commit: important feature      (this was "lost")
# i7j8k9l HEAD@{2}: commit: add login              (this was "lost")
# m0n1o2p HEAD@{3}: commit: initial setup           (current HEAD is here)

# View reflog for a specific branch
git reflog show main
git reflog show feature/login

# See ALL reference movements (not just HEAD)
git reflog --all
reflog is Git's most powerful and least used feature. Most developers only discover it after a disaster. But once you know it, you will never fear git reset --hard again. Think of it as a CCTV camera that records every move — even the ones you regret.
02Recover Lost Commits

When you run git reset --hard HEAD~3, the branch pointer moves back, but the commits are NOT deleted from the object store.

git reflog shows you the hash of the commit you were on BEFORE the disastrous reset.

To recover: git reset --hard HEAD@{N} where N is the reflog index of the commit you want to return to.

Or use the hash directly: git reset --hard <hash-from-reflog>.

This works for recovering from bad merges, accidental rebases, and even deleted branches (if you have the hash).

The recovered commits become reachable again, exactly as they were. Nothing is modified, nothing is recreated — the original objects never left.

# Oh shit moment: hard reset too far
git reset --hard HEAD~3
git log --oneline   # 3 commits are "gone"!

# Step 1: Check the reflog
git reflog
# Find the line BEFORE the reset, e.g., HEAD@{4}

# Step 2: Reset to that reflog entry
git reset --hard HEAD@{4}
# OR use the hash
git reset --hard e4f5g6h

# Step 3: Verify
git log --oneline   # All your commits are back!

# Recover a deleted branch
git branch deleted-branch HEAD@{5}
The commits never left the object store. When you git reset --hard, only the branch pointer moves. The commit objects, trees, and blobs are still sitting in .git/objects/. Reflog gives you the hash to find them. They only get deleted when git gc prunes them after 90 days.
03HEAD@{N} Syntax & Time-based Reflog

HEAD@{0} = Where HEAD is right now.

HEAD@{1} = Where HEAD was 1 move ago.

HEAD@{5} = Where HEAD was 5 moves ago.

You can use this syntax with any Git command that takes a commit reference.

  • git show HEAD@{3} — see what that commit looked like
  • git diff HEAD@{2}..HEAD — what changed in the last 2 HEAD moves
  • git merge HEAD@{4} — merge the state from 4 moves ago

Time-based syntax: HEAD@{2.hours.ago}, HEAD@{yesterday}, HEAD@{1.day.ago}. Git can resolve HEAD positions by time, not just index.

# View the commit 3 moves ago
git show HEAD@{3}

# Diff between now and 2 moves ago
git diff HEAD@{2}..HEAD

# What was the state of main yesterday?
git log main@{yesterday}

# What did I commit in the last hour?
git log HEAD@{1.hour.ago}..HEAD

# See what you were working on 5 moves ago
git show HEAD@{5}:app.js

# Combine with other commands
git cherry-pick HEAD@{3}   # cherry-pick a "lost" commit
git branch backup HEAD@{4} # create branch at an old state
💡 Pro Tip: Use git reflog --date=iso or git reflog --date=relative to see exactly WHEN each move happened. This helps you find the right entry when your reflog is long.
04When Reflog Can't Help

If you never committed your changes, reflog cannot help. Unstaged/uncommitted work is truly lost after git reset --hard or git checkout overwrites it.

If you cloned a fresh repository, you do not have the reflog of the original repo. Reflogs are strictly local — they are stored in .git/logs/ and never transferred.

After 90 days (default), unreachable reflog entries expire and git gc permanently deletes the objects.

If someone else force-pushed a shared branch, your local reflog can help YOU, but it will not fix the remote history for the team.

git gc --prune=now will immediately delete unreachable objects, making reflog recovery impossible.

# UNCOMMITTED CHANGES: reflog won't help
echo "important work" > app.js
# Oops, didn't commit!
git reset --hard HEAD
# "important work" is GONE FOREVER. reflog has no record.

# CLONED REPO: no reflog history
git clone https://github.com/user/repo.git
cd repo
git reflog
# Only shows the clone operation. No past team history.

# EXPIRED ENTRIES: gc deletes them
git reflog expire --expire=0 --all
git gc --prune=now
# All unreachable commits are permanently deleted.
# reflog recovery is now IMPOSSIBLE.

# If you must reset, commit or stash FIRST!
git stash                   # safe backup
git reset --hard HEAD~3    # risky operation
# If it went wrong:
git stash pop               # recover the stash
Golden rule: commit or stash BEFORE any destructive operation. reflog only records HEAD movements, and HEAD only points to commits. Uncommitted changes are not tracked by reflog. If you are about to run git reset --hard, first run git stash. It takes 2 seconds and can save hours of work.
05git log vs git reflog

git log shows the current branch's commit history. If commits are unreachable (no branch points to them), they do not appear in git log.

git reflog shows the history of WHERE HEAD HAS BEEN, regardless of whether those commits are reachable now.

git log is about the project timeline. git reflog is about YOUR actions timeline.

Reflog is the safety net that catches what git log cannot see.

Use git log to understand the project. Use git reflog to find lost work.

# After a hard reset, git log shows nothing "lost"
git log --oneline
# abc1234 (HEAD -> main) Initial commit
# The 3 "lost" commits don't appear here!

# But reflog shows everything
git reflog
# def5678 HEAD@{1}: commit: lost feature 2
# ghi9012 HEAD@{2}: commit: lost feature 1
# jkl3456 HEAD@{3}: commit: lost setup
# abc1234 HEAD@{4}: commit: Initial commit

# You can even see the "lost" commits with log using reflog refs
git log --oneline HEAD@{1}
# Shows the history as it was at HEAD@{1}

# Quick sanity check: how many moves today?
git reflog --since="today" | wc -l
💡 Mental Model: git log answers "what is the history of this branch?" git reflog answers "what did I do to HEAD?" These are fundamentally different questions. When you lose commits, git log will not help — it only shows reachable history. git reflog is your recovery tool because it shows the actions that made commits unreachable.

Lo kar liya — Key Points:

  • git reflog records every HEAD movement — commits, checkouts, resets, rebases — acting as Git's CCTV camera
  • ✅ Even after git reset --hard, commits are NOT deleted immediately; they are just unreachable from branches but visible in reflog
  • ✅ Recover lost work with git reset --hard HEAD@{N} or git reset --hard <hash-from-reflog>
  • HEAD@{0} is the current position, HEAD@{1} is one move ago, etc. You can also use time like HEAD@{yesterday}
  • ✅ reflog is LOCAL only — it does not transfer with clone or push, and it expires after ~90 days
  • ✅ Uncommitted changes lost to git reset --hard or git checkout cannot be recovered with reflog
  • git log shows current branch history; git reflog shows your action history including "lost" commits
Course Search
Search across all chapters & stages
📖

Search the course

Type any topic — branching, stash, rebase, hooks — and jump straight to that chapter.

merge branchesgit stashundo commitrebase