Git Reflog Explained: Recover Lost Commits, Reset, Amend & Branches

Learn what git reflog is and how to use it with practical examples. Recover commits after git reset --hard, restore amended commits, recover deleted branches, inspect stash reflog, and understand reflog expiration limits.

Published

Updated

Read time 12 min read

Reviewed byDeepak Prasad

Git Reflog Explained: Recover Lost Commits, Reset, Amend & Branches

git reflog is the Git command you use when commit history looks broken after a reset, amend, rebase, branch deletion, or checkout. It records where references such as HEAD, local branches, remote-tracking branches, and stash pointed recently inside your local repository.

If you ran a destructive command and need the shortest recovery path, start here:

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

Use HEAD@{1} only when the reflog entry at that position is the commit you want. In real repositories, always inspect the reflog output first and choose the correct entry.

This article uses tested output from a local Git lab. The examples were run with Git 2.48.1 on June 9, 2026.


What is Git Reflog?

Git reflog means reference log. A reference is a pointer such as HEAD, main, feature/login, origin/main, or stash. Whenever Git moves one of these references, Git can record the old and new position in a reflog.

That makes reflog different from normal commit history:

Command What it shows Best use
git log Commits reachable from the current branch Review normal project history
git reflog Recent movements of HEAD and other refs Recover commits hidden by reset, amend, rebase, checkout, or branch deletion
git reflog --all Reflog entries from all refs that still have reflogs Search across branches, remote-tracking refs, and stash
git reflog show <ref> Reflog for one ref Inspect a specific branch, remote-tracking branch, or stash

Diagram explaining git reflog: how it records HEAD movements and recovers lost commits, resets, amended commits, and deleted branches

The official Git documentation describes reflogs as local records of when branch tips and other references were updated. It also notes that expressions like HEAD@{2} and main@{one.week.ago} can be used to refer to older ref positions.


Git Reflog Recovery Cheat Sheet

Problem Command pattern
See recent HEAD movements git reflog
See reflog with timestamps git reflog --date=iso
Recover after reset git reset --hard HEAD@{1}
Recover by exact hash git reset --hard <commit-hash>
Recover deleted branch git branch <branch-name> <commit-hash>
Search all reflogs git reflog --all
Show one branch reflog git reflog show main
Show stash reflog git reflog show stash
List refs with reflogs git reflog list
Test full ref reflog git reflog exists refs/heads/main
Preview reflog pruning git reflog expire --dry-run --verbose --expire=now --all

Tested Lab Setup

The following test repository was created in /tmp so the commands could be verified safely without touching a real project.

bash
git --version
mkdir reflog-demo
cd reflog-demo
git init -b main
git config user.name "GoLinuxCloud"
git config user.email "author@golinuxcloud.test"

Tested output:

text
git version 2.48.1
Initialized empty Git repository in /tmp/git-reflog-lab.h8jLo3/reflog-demo/.git/

Next, three commits were created:

bash
printf 'one\n' > app.txt
git add app.txt
git commit -m "initial commit"
printf 'two\n' >> app.txt
git add app.txt
git commit -m "add second line"
printf 'three\n' >> app.txt
git add app.txt
git commit -m "add third line"

Tested output:

text
[main (root-commit) 1652683] initial commit
 1 file changed, 1 insertion(+)
 create mode 100644 app.txt
[main 42c9538] add second line
 1 file changed, 1 insertion(+)
[main a535509] add third line
 1 file changed, 1 insertion(+)

The commit history before any recovery test looked like this:

bash
git log --oneline --decorate

Tested output:

text
a535509 (HEAD -> main) add third line
42c9538 add second line
1652683 initial commit

Git Reflog Example After Reset

A common search query is git reflog reset or git reset reflog. Both usually mean: "I ran reset and want my commit back."

In the test repo, the latest commit was removed from visible branch history using a hard reset:

bash
git reset --hard HEAD~1

Tested output:

text
HEAD is now at 42c9538 add second line

At this point, git log would no longer show commit a535509. Reflog still records where HEAD was before the reset:

bash
git reflog --date=iso

Tested output:

text
42c9538 HEAD@{2026-06-09 08:45:26 +0530}: reset: moving to HEAD~1
a535509 HEAD@{2026-06-09 08:45:26 +0530}: commit: add third line
42c9538 HEAD@{2026-06-09 08:45:26 +0530}: commit: add second line
1652683 HEAD@{2026-06-09 08:45:26 +0530}: commit (initial): initial commit

The lost commit is the entry before the reset: a535509.

You can restore it by resetting back to the reflog entry:

bash
git reset --hard HEAD@{1}
git log --oneline --decorate -3

Tested output:

text
HEAD is now at a535509 add third line
a535509 (HEAD -> main) add third line
42c9538 add second line
1652683 initial commit

You can also use the commit hash directly:

bash
git reset --hard a535509

Tested output:

text
HEAD is now at a535509 add third line

In a shared repository, be careful before using git reset --hard on commits that were already pushed. For pushed history, compare this with git revert and git push force behavior before rewriting remote history.


Recover an Amended Commit with Git Reflog

git commit --amend replaces the latest commit with a new commit hash. The old commit disappears from normal git log, but reflog records the movement.

The test amended the latest commit message:

bash
git commit --amend -m "add third line with better message"

Tested output:

text
[main a7da451] add third line with better message
 Date: Tue Jun 9 08:45:26 2026 +0530
 1 file changed, 1 insertion(+)

Now inspect the latest reflog entries:

bash
git reflog --date=iso -4

Tested output:

text
a7da451 HEAD@{2026-06-09 08:45:26 +0530}: commit (amend): add third line with better message
a535509 HEAD@{2026-06-09 08:45:26 +0530}: reset: moving to HEAD@{1}
42c9538 HEAD@{2026-06-09 08:45:26 +0530}: reset: moving to HEAD~1
a535509 HEAD@{2026-06-09 08:45:26 +0530}: commit: add third line

The amended commit is a7da451, and the earlier commit was a535509. To recover the pre-amend commit without changing the current branch, create a branch at the old hash:

bash
git branch before-amend a535509
echo "before_amend_exit=$?"
git branch --list before-amend

Tested output:

text
before_amend_exit=0
  before-amend

If your goal is only to fix the last commit message, see git commit amend examples and change Git commit message.


Recover a Deleted Branch with Git Reflog

Reflog can also help when a local branch was deleted before you pushed or merged its work.

In the test repo, a branch was created, committed, checked out back to main, and then deleted:

bash
git switch -c feature/login
printf 'feature\n' > feature.txt
git add feature.txt
git commit -m "add login feature"
git switch main
git branch -D feature/login

Tested output:

text
Switched to a new branch 'feature/login'
[feature/login 3e4697d] add login feature
 1 file changed, 1 insertion(+)
 create mode 100644 feature.txt
Switched to branch 'main'
Deleted branch feature/login (was 3e4697d).

If you still have the deletion message, the branch tip is already visible: 3e4697d. If not, search all reflogs:

bash
git reflog --all --date=iso | head -n 8

Tested output:

text
a7da451 refs/heads/main@{2026-06-09 08:45:26 +0530}: commit (amend): add third line with better message
a535509 refs/heads/main@{2026-06-09 08:45:26 +0530}: reset: moving to HEAD@{1}
42c9538 refs/heads/main@{2026-06-09 08:45:26 +0530}: reset: moving to HEAD~1
a535509 refs/heads/main@{2026-06-09 08:45:26 +0530}: commit: add third line
42c9538 refs/heads/main@{2026-06-09 08:45:26 +0530}: commit: add second line
1652683 refs/heads/main@{2026-06-09 08:45:26 +0530}: commit (initial): initial commit
a7da451 HEAD@{2026-06-09 08:45:26 +0530}: checkout: moving from feature/login to main
3e4697d HEAD@{2026-06-09 08:45:26 +0530}: commit: add login feature

Create a new branch at the lost commit:

bash
git branch recovered-login 3e4697d
git branch --list

Tested output:

text
* main
  recovered-login

Verify the recovered branch points to the commit that added the file:

bash
git show --stat --oneline recovered-login --

Tested output:

text
3e4697d add login feature
 feature.txt | 1 +
 1 file changed, 1 insertion(+)

If you need to switch to that branch after recovery, use git checkout or git switch.


Show Reflog for a Specific Branch

By default, git reflog shows the HEAD reflog. To inspect a specific branch, use git reflog show <branch>.

bash
git reflog show main --date=iso | head -n 5

Tested output:

text
a7da451 main@{2026-06-09 08:45:26 +0530}: commit (amend): add third line with better message
a535509 main@{2026-06-09 08:45:26 +0530}: reset: moving to HEAD@{1}
42c9538 main@{2026-06-09 08:45:26 +0530}: reset: moving to HEAD~1
a535509 main@{2026-06-09 08:45:26 +0530}: commit: add third line
42c9538 main@{2026-06-09 08:45:26 +0530}: commit: add second line

This is useful when multiple branches are involved and HEAD moved through several checkouts.

For remote-tracking branches, the same pattern works if your local clone has a reflog for that ref, such as origin/main. This is helpful after a force push because your local clone may remember where the remote-tracking ref pointed before it moved.


Git Reflog List and Exists

Git can list refs that currently have reflogs:

bash
git reflog list

Tested output:

text
HEAD
refs/heads/main
refs/heads/recovered-login

When testing whether a reflog exists, use the full ref name. In this lab, the full ref worked, but the short branch name did not:

bash
git reflog exists refs/heads/main
echo "exists_refs_heads_main_exit=$?"
git reflog exists main
echo "exists_main_exit=$?"

Tested output:

text
exists_refs_heads_main_exit=0
exists_main_exit=1

An exit code of 0 means the reflog exists. A non-zero exit code means Git did not find a reflog for that exact ref argument.


Use HEAD@{n} and HEAD@{time}

Reflog entries can be referenced by position:

Syntax Meaning
HEAD@{0} Current recorded HEAD position
HEAD@{1} Previous recorded HEAD position
main@{1} Previous recorded position of main
HEAD@{1.minute.ago} Where HEAD pointed around one minute ago, if the reflog goes back that far
main@{yesterday} Where main pointed yesterday, if available

The test confirmed HEAD@{0} resolves to the current commit:

bash
git rev-parse --short HEAD
git rev-parse --short 'HEAD@{0}'

Tested output:

text
a7da451
a7da451

You can also compare two reflog positions:

bash
git diff --stat main@{1} main@{0}

In the test repo this produced no output because the selected reflog states did not change file content in that comparison.


Git Reflog for Stash

Stash has its own ref, so you can inspect stash reflog entries too.

bash
printf 'temporary\n' >> app.txt
git stash push -m "temporary app change"
git reflog show stash --date=iso

Tested output:

text
Saved working directory and index state On main: temporary app change
a0ba40e stash@{2026-06-09 08:45:26 +0530}: On main: temporary app change

The normal stash list also shows the saved entry:

bash
git stash list

Tested output:

text
stash@{0}: On main: temporary app change

For more stash workflows, see Git stash examples.


Git Reflog Expiration and Limitations

Reflog is powerful, but it is not permanent backup.

Important limits:

  • Reflog is local to your clone; it is not pushed to GitHub or GitLab.
  • Reflog usually cannot recover changes that were never committed or stashed.
  • Reflog entries can expire and be pruned by Git garbage collection.
  • If a commit is no longer reachable and its reflog entry expires, Git may eventually remove the object.
  • A different clone may have a useful reflog even when your clone does not.

Common default expiration behavior is:

Setting Common default Meaning
gc.reflogExpire 90 days Keeps reachable reflog entries
gc.reflogExpireUnreachable 30 days Keeps reflog entries not reachable from the current tip

You can preview reflog expiration without deleting anything:

bash
git reflog expire --dry-run --verbose --expire=now --all | head -n 10

Tested output:

text
would prune commit (initial): initial commit
would prune commit: add second line
would prune commit: add third line
would prune reset: moving to HEAD~1
would prune reset: moving to HEAD@{1}
would prune commit (amend): add third line with better message
would prune checkout: moving from main to feature/login
would prune commit: add login feature
would prune checkout: moving from feature/login to main
would prune reset: moving to HEAD

Do not run expiration or garbage collection commands casually on a repository where you still need recovery options. Keep backups for important projects.


Git Reflog vs Git Log

Use git show and log commands when the commit is still part of normal branch history. Use reflog when the commit disappeared from normal history because a reference moved.

Scenario Use git log Use git reflog
Review normal commits on current branch Yes Sometimes
Find commit hidden by hard reset No Yes
Find pre-amend commit No Yes
Find branch tip after branch deletion Usually no Yes, if recently referenced
Inspect branch switching history No Yes
Recover never-committed file edits No Usually no

git reflog show is closely related to this command:

bash
git log -g --abbrev-commit --pretty=oneline -3

Tested output:

text
a7da451 HEAD@{0}: reset: moving to HEAD
a7da451 HEAD@{1}: checkout: moving from feature/login to main
3e4697d HEAD@{2}: commit: add login feature

Git Reflog Recovery Checklist

Use this checklist before changing history again:

  1. Run git reflog --date=iso and identify the exact entry you need.
  2. Prefer creating a recovery branch at the commit hash before resetting anything.
  3. Use git reflog --all if the normal HEAD reflog does not show the missing commit.
  4. Check branch-specific reflog output when multiple branches were involved.
  5. Act quickly because reflog entries can expire.

Common Mistakes

Using HEAD@{1} without checking it

HEAD@{1} often means the previous HEAD position, but not always the one you want. If you checked out branches, amended commits, stashed changes, or reset multiple times, inspect git reflog first.

Expecting reflog to recover uncommitted work

Reflog tracks ref movement. If a file was never committed, stashed, or saved elsewhere, reflog usually cannot restore it.

Searching only HEAD reflog for a branch issue

If git reflog does not show the commit, try git reflog --all or a branch-specific reflog such as git reflog show main.

Waiting too long

Reflog entries expire. If you need to recover a commit, create a branch at that commit as soon as you find it.

Confusing git reflogging with git reflog

There is no standard Git command named git reflogging. The command is git reflog; "reflogging" is just a casual way people describe using reflog.


Frequently Asked Questions

1. What is git reflog?

Git reflog is a local reference log that records updates to HEAD, branches, stash, and other refs. It helps you find previous commit positions after reset, amend, rebase, checkout, or branch deletion.

2. How do I use git reflog to recover after git reset --hard?

Run git reflog, find the commit before the reset, then restore it with git reset --hard HEAD@{1} or git reset --hard . Use the entry that matches your own reflog output.

3. What is the difference between git log and git reflog?

Git log shows commits reachable from the current branch history. Git reflog shows where references such as HEAD and branches pointed recently, including commits hidden by reset, amend, rebase, or branch switching.

4. Can git reflog recover a deleted branch?

Yes, if the deleted branch tip still appears in HEAD reflog or another reflog. Find the commit with git reflog --all, then recreate the branch with git branch .

5. Is git reflog pushed to GitHub or GitLab?

No. Reflog is local to each repository clone. Remote hosting providers do not expose your local reflog, so recovery depends on reflog entries available in your local clone or another developer's clone.

6. How long does git reflog keep entries?

Git commonly keeps reachable reflog entries for 90 days and unreachable entries for 30 days before expiration, depending on gc.reflogExpire and gc.reflogExpireUnreachable configuration.

7. Can git reflog recover uncommitted changes?

Usually no. Reflog records reference movement, not arbitrary uncommitted working tree content. It can recover commits, branch tips, amended commits, rebased commits, and some stash references, but not unsaved or never-committed file changes.

8. Is git reflogging a command?

No. People sometimes search for git reflogging when they mean using git reflog. The Git command is git reflog.

Summary

Git reflog is a local safety record for reference movement. It helps recover commits after git reset --hard, restore pre-amend commits, locate deleted branch tips, inspect branch-specific history, and review stash movement.

The safest habit is to create a recovery branch before changing your current branch again. In the test lab, this preserved the recovered branch tip:

bash
git branch recovery 3e4697d
echo "recovery_exit=$?"
git branch --list recovery recovered-login

Tested output:

text
recovery_exit=0
  recovered-login
  recovery

Creating a recovery branch is often safer than immediately resetting your current branch. After you verify the recovered commit, you can merge, cherry-pick, or reset depending on your workflow.


Official Documentation

Steve Alila

Specializes in web design, WordPress development, and data analysis, with proficiency in Python, JavaScript, and data extraction tools. Additionally, he excels in web API development, AI integration, …