W3docs

git reflog

On this page you can find detailed information about git reflog command, see reflog references and subcommands, learn about timed reflogs and see examples.

The git reflog command is your safety net. It records every change made to local references — branches, HEAD, and stashes — so you can recover commits that seem to have vanished after a reset, rebase, amend, or a deleted branch. This page explains what the reflog stores, how to read its name@{n} syntax, how to filter entries by time, the available subcommands, and a complete walkthrough of recovering "lost" commits.

What the reflog is

A reference (or "ref") is a pointer to a commit — HEAD, a branch tip like main, or a stash entry. Many Git operations move these pointers around: each git commit, checkout, merge, rebase, or reset updates where a ref points. The reflog ("reference log") records that history of movements.

This matters because Git almost never deletes commits immediately. When an operation like a hard reset or a rebase makes a commit unreachable from any branch or tag, the commit object still lives in your repository and the reflog still holds a pointer to it. As long as that reflog entry exists, you can get the commit back.

git reflog

Info

The reflog is strictly local and per-clone. It is never pushed or fetched, so a fresh clone has an empty reflog. If you rewrite history and lose a commit, you can only recover it from the machine where the work was done.

Basic usage

The simplest form takes no arguments:

git reflog

This is a shortcut for showing the reflog of HEAD:

git reflog show HEAD

The output lists each position HEAD has held, newest first:

a32556a HEAD@{0}: commit: migrating content
ab371fd HEAD@{1}: commit: adding git reflog outline
23a491a HEAD@{2}: checkout: moving from stage to feature/solver
7b119cb HEAD@{3}: checkout: moving from feature/solver to stage
56a183a HEAD@{4}: commit: changing color scheme
7a2aa71 HEAD@{5}: commit: adding more color palettes
a56322b HEAD@{6}: commit: adding color tool package

Read each line as three parts:

  • a32556a — the abbreviated commit hash that HEAD pointed to.
  • HEAD@{0} — the reflog selector. @{0} is the most recent position, @{1} the one before it, and so on, counting backwards in time.
  • commit: migrating content — the action that moved the ref, plus its message.

The action label tells you how the ref moved (commit, checkout, merge, rebase -i, reset), which makes the reflog readable as a step-by-step history of what you did locally.

Reflog references

By default git reflog shows the reflog of HEAD, which follows whatever branch is currently checked out. But every ref keeps its own reflog, and you access any of them with the name@{qualifier} syntax.

To see the reflog for all references at once:

git reflog show --all

Pass a branch name to inspect just that branch's history. Below, the reflog for test_branch:

git reflog show test_branch
32a591f test_branch@{0}: commit: add snippets
23bae4a test_branch@{1}: commit (initial): initial commit

Note the difference: HEAD@{1} means "where HEAD was one move ago," while test_branch@{1} means "where test_branch itself was one move ago." This distinction is what lets you recover a branch tip that a hard reset or a forced update moved.

You can also read the reflog for the git stash:

git reflog stash
0d44de3 stash@{0}: WIP on git_reflog: a567574 adding Vue.js

Timed reflogs

Each reflog entry has an attached timestamp. They can be used as qualifiers in the Git ref pointer syntax, allowing you to filter Git reflogs by time. Here are some examples of time qualifiers:

  • 1.minute.ago
  • 1.hour.ago
  • 1.day.ago
  • yesterday
  • 1.week.ago
  • 1.month.ago
  • 1.year.ago
  • 2011-05-17.09:00:00

You can combine qualifiers (e.g. 1.week.3.hours.ago) and use plural forms (e.g. 5.hours.ago). A time-qualified ref can be passed to other Git commands, not just git reflog:

git diff master@{0} master@{1.week.ago}

This shows a diff of the current master against where master pointed one week ago.

Warning

A time qualifier resolves against the reflog, not against commit dates. master@{1.week.ago} means "the commit master referenced as of one week ago on this machine," which can differ from "the commit authored a week ago." On a fresh clone with no reflog history, Git falls back to the current tip and may warn that the log is too short.

Subcommands of git reflog

Git reflog accepts several arguments that act as subcommands. These are described below.

git reflog show

git reflog show is the default behavior and is itself an alias for git log -g --abbrev-commit --pretty=oneline. These two commands are equivalent:

git reflog master@{0}
git reflog show master@{0}

git reflog expire

git reflog expire prunes old or unreachable reflog entries. Because removing entries can make commits genuinely unrecoverable, you rarely run it by hand — Git runs it automatically during git gc. By default reachable entries expire after 90 days (gc.reflogExpire) and unreachable ones after 30 days (gc.reflogExpireUnreachable). To force a custom expiry:

git reflog expire --expire=1.day.ago --all

git reflog delete

git reflog delete removes one specific reflog entry by its selector. Like expire, it carries a real risk of losing recoverability and is seldom needed in everyday work:

git reflog delete HEAD@{1}
Danger

Once a reflog entry expires or is deleted, the commit it pointed to becomes truly unreachable and will be removed the next time git gc runs. Treat expire and delete as cleanup tools, not undo tools.

Recovering lost commits

Commits are never truly lost in Git, even during history-rewriting operations — and the reflog is how you get them back. Suppose git log --pretty=oneline looks like this:

2b43ceab309da94256db8fb1f35b1678fb74abd4 changes in content
c32557493a95185997c87e0bc3a9481715279351 adding Vue.js
abc234f986d270d7f97c77618314a06f024c4563 migrating content
a5673cd762d8ef2e146d7f0226e81a92f91956b1 adding git reflog outline
2bce4a4404c42128bee8468a9517418ed0ea412 initial commit

Now suppose we commit some new changes to this repository:

# make changes to HEAD
git commit -am "API changes"

The log now looks like this:

37656e19d4e4f1a9b419f57850c8f1974f871b07 API changes
2b43ceab309da94256db8fb1f35b1678fb74abd4 changes in content
c32557493a95185997c87e0bc3a9481715279351 adding Vue.js
abc234f986d270d7f97c77618314a06f024c4563 migrating content
a5673cd762d8ef2e146d7f0226e81a92f91956b1 adding git reflog outline
2bce4a4404c42128bee8468a9517418ed0ea412 initial commit

Next we start an interactive rebase against master:

git rebase -i origin/master

During the rebase we mark commits with the s (squash) action to fold them into the most recent "API changes" commit. Afterwards the git log output is collapsed to:

40d8a1237656e19d4e4f1a9b419f57850c8f1974 API changes
35aee4a4404c42128bee8468a9517418ed0eb3dc initial commit

The squashed commits appear gone. But the reflog still records every position HEAD held during the rebase:

git reflog
37656e1 HEAD@{0}: rebase -i (finish): returning to refs/heads/git_reflog
37656e1 HEAD@{1}: rebase -i (start): checkout origin/master
37656e1 HEAD@{2}: commit: API changes

HEAD@{2} is the state right before the rebase started. Pass that selector to git reset to rewind to it:

git reset --hard HEAD@{2}

This moves HEAD back to the pre-rebase "API changes" commit and restores all the squashed commits. Use --hard to also reset your working tree to that state, or omit it (git reset HEAD@{2}) to move only the branch pointer while keeping current files.

When to use git reflog

Reach for the reflog whenever a ref moved and you want it back:

  • After a git reset --hard that discarded commits you actually needed.
  • To recover commits orphaned by an interactive rebase, amend, or squash.
  • To restore a branch you deleted with git branch -D (find its last tip in the reflog, then git branch <name> <hash>).
  • To find where HEAD was before a confusing series of checkouts or merges.

If the commit is younger than the reflog expiry window (90 days for reachable entries by default), it is recoverable.

  • git reset — move refs to a reflog entry to undo changes.
  • git rebase — the rewriting operation the reflog most often rescues.
  • git stash — stashes have their own reflog under stash@{n}.
  • git log — the regular history view; git log -g reads the reflog.

Practice

Practice
What are the correct statements about the `git reflog` command?
What are the correct statements about the `git reflog` command?
Was this page helpful?