Git, CI/CD & GitOpsXVII · ReflogNavigation
Navigation with reflog — @{N}, @{date}, and using reflog as a history of HEAD
What you'll learn
- Use the @{N} and HEAD@{N} reflog selectors to address prior states of HEAD
- Use date-based selectors like @{yesterday} and @{2.days.ago} for time-based navigation
- Combine reflog selectors with reset, switch, and checkout to navigate or recover
- Distinguish @{N} (reflog-relative) from ~N (commit-relative) and ^N (parent)
Prerequisites
Verified against Git 2.55.x teaching target; 2.40+ minimum · GitHub Actions continuous service; Aug 2026 documentation baseline · Argo CD v3.5.x teaching target; v3.0+ minimum · Flux v2.9.x · Sigstore Cosign v3.1.x · SLSA v1.2 · OCI Distribution Specification v1.1 · Git LFS v3.7.1 · Kubernetes (cross-course target) 1.36.x
The reflog’s primary operational use is navigation: it lets
the engineer address prior states of a ref by ordinal
position or by date. The selectors @{N}, HEAD@{N},
@{yesterday}, and HEAD@{2.days.ago} resolve to specific
commits in the reflog and can be passed to any command that
takes a revision — git reset, git checkout, git diff,
git log. Combined with the recovery commands from lessons
4 and 5, the reflog selectors are the navigational layer that
makes the reflog actionable.
The @{N} selector
@{0} is the current value of HEAD (the same as HEAD). @{1}
is the previous value (the OID HEAD pointed at before the most
recent update). @{2} is the value before that, and so on.
git reflog -3
# 9a8b7c6 HEAD@{0}: commit: bump terraform module
# 4d2c8e0 HEAD@{1}: commit: update iam policy
# 8a3f9d2 HEAD@{2}: checkout: moving from main to feature/iam
git show HEAD@{1}
# commit 4d2c8e0
# Author: ...
# update iam policy
git diff HEAD@{2} HEAD
# diff between the commit at HEAD@{2} and the current tip
HEAD@{N} and @{N} are equivalent in the common case. The
explicit form is required only when the command’s position
parser would otherwise bind @{N} to a different ref.
flowchart LR
A["HEAD@{0} = current"] --> B["HEAD@{1} = previous"]
B --> C["HEAD@{2} = before that"]
C --> D["HEAD@{N} = N updates ago"]
Date-based selectors
@{<date>} resolves to the most recent reflog entry at or
before the given date. The date can be a relative phrase,
an ISO date, or a Unix timestamp.
git show @{yesterday}
# shows the commit HEAD pointed at most recently as of yesterday
git show @{2.days.ago}
# shows the commit HEAD pointed at most recently two days ago
git show @{"2026-08-19 14:00"}
# shows the commit HEAD pointed at most recently at the named time
The date selector walks the reflog from newest to oldest and returns the first entry whose timestamp is at or before the named time. If no entry exists at or before that time, the selector fails with an error.
The relative phrases supported include yesterday, 1.day.ago,
2.weeks.ago, 3.hours.ago. The full grammar is in
git help revisions under “Reflog selectors”.
Combining reflog selectors with commands
The selector is just a revision; it works anywhere a revision is accepted.
# Reset to the previous state of HEAD (soft: keep working tree)
git reset --soft HEAD@{1}
# Reset to a previous state and discard working tree changes
git reset --hard HEAD@{1}
# Switch to a previous state in detached HEAD mode (for inspection)
git switch --detach HEAD@{1}
# Diff working tree against the state two commits ago
git diff @{2}
# Cherry-pick a commit the engineer remembers making yesterday
git cherry-pick @{yesterday}
The reset and cherry-pick combinations are the recovery
patterns covered in the next two lessons. The switch --detach
and diff combinations are diagnostic patterns: inspect a
prior state without committing to it, then git switch - back
to the previous branch.
@{N} versus ~N versus ^N
Three selectors look similar but resolve differently:
HEAD@{N}— the Nth most recent state of HEAD, as recorded in the reflog. Resolves to a commit OID.HEAD~N— the Nth ancestor of HEAD, walking first parents only. Resolves to a commit OID.HEAD^N— the Nth parent of HEAD. For a merge commit,HEAD^2is the second parent.
# Three different ways to write "two commits ago" — usually the same:
git show HEAD@{2}
git show HEAD~2
git show HEAD^^
# But they differ at the start of a rebase:
# HEAD@{1} might point at the pre-rebase tip, while
# HEAD~1 points at HEAD's parent (which is the first replayed commit)
flowchart LR
A["HEAD@{N}"] --> A1["N updates ago\n(reflog ordinal)"]
B["HEAD~N"] --> B1["N first-parent ancestors\n(history traversal)"]
C["HEAD^N"] --> C1["Nth parent\n(merge parents)"]
The rule of thumb: @{N} is time-based (when was HEAD last
at this OID), ~N is history-based (walk back through the
DAG), ^N is parent-based (which parent of a merge).
Production engineers default to ~N for “back through the
history” and reach for @{N} only when the reflog is the
authoritative record (recovery scenarios, time-based
diagnostics).
Using reflog for navigation without recovery
The reflog is useful even when nothing has gone wrong. Common non-recovery uses:
- “What did I have on this branch yesterday?” —
git diff @{yesterday}answers the question without changing branches. - “When did I last touch this file?” — combine with
git log -g -- <path>to walk the reflog as if it were history. - “What was the tip of
mainthree days ago?” —git log main@{3.days.ago}shows the tip at that time.
The -g (or --walk-reflogs) flag makes git log walk the
reflog instead of the commit graph. The reflog has a chain
shape (each entry is an update event), so git log -g shows
the chronological history of HEAD movements rather than the
DAG history of commits.
git log -g --oneline
# 9a8b7c6 HEAD@{0}: commit: bump terraform module
# 4d2c8e0 HEAD@{1}: commit: update iam policy
# 8a3f9d2 HEAD@{2}: checkout: moving from main to feature/iam
Production discipline
- Default to
HEAD@{N}for “the prior state of HEAD”. The selector is unambiguous and matches the recovery pattern in lesson 4. - Use date selectors for diagnostics, not recovery.
HEAD@{2.days.ago}is a fine way to ask “what was I working on Tuesday?” but a recovery recipe should pin to an ordinal@{N}so the recipe is repeatable. - Combine reflog selectors with
--walk-reflogs(-g) for chronological views.git log -g -- <path>shows when a path was last touched, whichgit log -- <path>cannot answer directly. - Verify before destructive commands.
git reset --hard HEAD@{1}is the recovery;git diff HEAD@{1} HEADfirst shows what will be lost.
Cross-course references
- Git, CI/CD & GitOps — Part V (Branches, Refs and HEAD) —
Part V lesson 4 covered detached HEAD state; the
switch --detach HEAD@{N}pattern is the same idea applied to a reflog-relative commit. - Git, CI/CD & GitOps — Part XV (Reset) — the recovery
recipes in lesson 4 use
HEAD@{N}to address the pre-reset state. - Linux for Production Sysadmins — Part XXVII (Backup and
Recovery) — reflog selectors are the Git analogue of
find -mtime -3: a time-based recovery primitive for a different storage layer.
Quiz
Knowledge check · 4 questions
Q1. Which command addresses the state of HEAD two updates prior to the current state, as recorded in the reflog?
Q2. The reflog selector `@{yesterday}` resolves to the most recent state of HEAD at or before yesterday, and fails with an error if no reflog entry exists at or before that time.
Q3. State the difference between `HEAD@{N}`, `HEAD~N`, and `HEAD^N`, and give one scenario where they resolve to different commits.
Q4. Choose the correct reflog selector and command combination for three time-relative and history-relative queries against an engineer's last day of work.
An engineer worked on `feature/iam-rotation` yesterday from 14:00 to 17:30, made three commits, and switched to `main` at 17:45. Today at 10:00 the engineer asks three questions: (a) 'what did `feature/iam-rotation` point at when I last touched it?' (b) 'show me the diff between the working tree and where I was at 16:00 yesterday' (c) 'restore the branch tip to the state it was in at 17:30 yesterday'.
Passing score: 75%. Answers are checked in this browser.