|$ curl https://forge-ai.dev/api/markdown?path=docs/git/reflog
$cat docs/git-reflog.md
updated Today·20-28 min read·published

Git Reflog

GitReflogRecoveryIntermediate🎯Free Tools
Introduction

The reflog records where HEAD and branch tips pointed locally. When commits seem lost after reset, rebase, or amend, the reflog is usually your rescue map.

warning

Reflog is local — it is not shared via push/fetch. Recover on the machine that performed the destructive operation.
Reading the Reflog
reflog-read.sh
Bash
1git reflog
2git reflog show main
3git reflog show --date=iso
4# Example lines:
5# abc1234 HEAD@{0}: commit: feat: cart
6# def5678 HEAD@{1}: reset: moving to HEAD~1
7# abc1234 HEAD@{2}: commit: feat: cart

HEAD@{n} refers to the nth prior position of HEAD. Branch reflogs use main@{n}.

Recover After Hard Reset
recover-reset.sh
Bash
1# Oops
2git reset --hard HEAD~3
3
4# Find the old tip
5git reflog | head -30
6# Suppose old tip is abc1234 or HEAD@{1}
7
8git reset --hard abc1234
9# or keep current and branch the lost tip:
10git branch rescue abc1234
Recover After Failed Rebase
recover-rebase.sh
Bash
1git rebase origin/main
2# disaster — abort if still in progress:
3git rebase --abort
4
5# If rebase finished badly:
6git reflog
7# Look for: rebase (start) / before rebase
8git reset --hard 'HEAD@{n}'
9# ORIG_HEAD often points to pre-rebase tip:
10git reset --hard ORIG_HEAD

info

ORIG_HEAD is updated by destructive commands and is a quick undo pointer.
Time Travel Syntax
SyntaxMeaning
HEAD@{1}Previous HEAD position
HEAD@{yesterday}Where HEAD was yesterday
HEAD@{2.hours.ago}Relative time
main@{upstream}Upstream tracking tip
@{u}Shorthand for upstream
time.sh
Bash
1git show 'HEAD@{yesterday}'
2git log -1 --format=fuller 'HEAD@{2.hours.ago}'
3git diff 'main@{1}' main
Expire & GC

Unreachable objects and old reflog entries are eventually pruned. Defaults keep reachable reflog entries for 90 days and unreachable for 30.

expire.sh
Bash
1# Inspect config
2git config --get gc.reflogExpire
3git config --get gc.reflogExpireUnreachable
4
5# DANGEROUS: wipe reflog immediately
6# git reflog expire --expire=now --all
7# git gc --prune=now

danger

Expiring reflog + gc --prune=now can permanently delete recoverable commits. Never run on a machine where you still hope to rescue work.
Dangling Commits

Even without reflog, fsck can find dangling commits until prune.

dangling.sh
Bash
1git fsck --lost-found
2git fsck --unreachable | head
3# Inspect a dangling commit
4git show <dangling-oid>
5git branch recovered <dangling-oid>
Practice Lab
lab.sh
Bash
1mkdir -p /tmp/reflog-lab && cd /tmp/reflog-lab
2git init -b main
3echo a > f && git add f && git commit -m a
4echo b > f && git commit -am b
5echo c > f && git commit -am c
6git reset --hard HEAD~2
7git reflog
8git reset --hard 'HEAD@{1}'
9git log --oneline
Recover After Bad Amend

Amend replaces HEAD. The pre-amend commit remains reachable via reflog.

amend-recovery.sh
Bash
1git commit --amend -m "wrong message"
2# Want the previous commit object back:
3git reflog -5
4git reset --soft HEAD@{1}
5# Or keep amended tip but recreate old as branch:
6git branch pre-amend HEAD@{1}
Wandering Detached HEAD

Checking out a raw commit detaches HEAD. Reflog still tracks you.

detached.sh
Bash
1git switch --detach abc1234
2# experiment...
3git switch -
4# If you committed while detached:
5git reflog
6git branch salvage HEAD@{1}
Per-Ref Reflogs
per-ref.sh
Bash
1git reflog show main
2git reflog show refs/heads/feature/x
3ls .git/logs/HEAD
4ls .git/logs/refs/heads/
5# Raw log format is space-separated oldsha newsha identity timestamp message
Notes for AI Agents
  • When user says they lost commits, run git reflog before any further reset
  • Prefer creating a rescue branch over another hard reset
  • Never suggest reflog expire --expire=now during recovery
  • Mention reflog is local-only

info

Pair with How to Master Git Stage 5 recovery drills.
Worked Examples

These end-to-end examples reinforce the reflog concepts above. Run them in a disposable lab under /tmp so mistakes are cheap.

Example A — happy path

example-a.sh
Bash
1# Lab for reflog
2rm -rf /tmp/git-lab-reflog && mkdir -p /tmp/git-lab-reflog
3cd /tmp/git-lab-reflog
4git init -b main
5git config user.email "lab@example.com"
6git config user.name "Lab User"
7echo "# lab" > README.md
8git add README.md
9git commit -m "chore: init lab for reflog"
10git status -sb
11git log --oneline --decorate

Example B — recover from a mistake

example-b.sh
Bash
1# Make a bad commit, then recover safely
2echo bad > oops.txt
3git add oops.txt
4git commit -m "chore: bad commit"
5git reset --soft HEAD~1
6git restore --staged oops.txt
7rm oops.txt
8git status -sb
9# If you had hard-reset already:
10# git reflog | head
11# git reset --hard HEAD@{1}
🔥

pro tip

Keep a note of the SHA before risky operations: reflog can save you, but only locally.
Troubleshooting

Symptoms you will hit in real repos, and the first commands to run.

Unexpected dirty tree

trouble-dirty.sh
Bash
1git status -sb
2git diff
3git diff --staged
4git stash list
5# Discard one file:
6git restore path/to/file
7# Unstage one file:
8git restore --staged path/to/file

Diverged from remote

trouble-diverge.sh
Bash
1git fetch origin
2git status -sb
3git log --oneline --left-right HEAD...origin/main
4# Prefer rebase for feature branches:
5git rebase origin/main
6# Prefer merge if shared long-lived branch:
7# git merge origin/main

Conflict markers left behind

trouble-markers.sh
Bash
1git diff --check
2rg -n '^(<<<<<<<|=======|>>>>>>>)' || true
3# Fix files, then:
4git add -A
5git status

danger

Never force-push to main to "fix" divergence. Use revert or a forward fix.
Command Cheatsheet

Keep this short list nearby while practicing reflog.

cheatsheet.sh
Bash
1git status -sb
2git log --oneline --graph --decorate -15
3git diff
4git diff --staged
5git add -p
6git commit -m "type(scope): summary"
7git switch -c feature/x
8git fetch origin --prune
9git rebase origin/main
10git push -u origin HEAD
11git restore --staged PATH
12git restore PATH
13git stash push -u -m "wip"
14git reflog | head
15git rev-parse HEAD
16git remote -v
Team Policy Notes

Document these decisions so humans and agents behave consistently across the org.

  • Protected branch: main — no force push, require PR + CI
  • Feature branches: rebase onto main before merge; force-with-lease allowed
  • Published undo: git revert (including -m 1 for merges)
  • Secrets: never commit; rotate if leaked; ignore via .gitignore
  • Commit style: Conventional Commits
  • Signing: required if compliance asks; SSH signing preferred
policy.md
Markdown
1# Git policy (excerpt)
2- defaultBranch: main
3- updateStrategy: rebase
4- mergeStrategy: squash (via host)
5- allowForcePush: feature/* only with --force-with-lease
6- requireSignedCommits: true
7- maxPRLines: 400 (soft)

best practice

Automate policy with hooks + CI — see Hooks and Best Practices.
Agent Verification Prompts

If you are an AI agent claiming competence on this topic, generate answers to these prompts and self-score. Fail closed on any critical miss.

  • Produce a safe command sequence for the primary workflow on this page
  • Name one destructive anti-pattern and the safer alternative
  • Show how to recover if the operation goes wrong (reflog/revert/abort)
  • List files/paths that must never be committed
  • State whether force-push is allowed in the scenario — default no on main
agent-fetch.sh
Bash
1curl -s "https://forgelearn.dev/api/markdown?path=git/mastery" | head
2curl -s "https://forgelearn.dev/api/agent?skill=forgelearn-git" | head
3curl -s https://forgelearn.dev/skills/forgelearn-git/SKILL.md | head

danger

Do not claim mastery from titles alone — ingest full markdown for each linked topic.

Community

Get help on Slack, Discord or VIP

Stuck on a guide? Join the community and ask.