DevOps & Workflow5 min read

    How to use git reflog

    By DanaServer Monitoring & Linux
    Share

    Every time HEAD moves — a commit, a checkout, a reset, a rebase, an amend, a merge — git records the previous and new SHA in the reflog. The reflog is purely local; it is not pushed and not part of the repository's normal history. But it is the reason that "I did git reset --hard and lost everything" is almost always recoverable.

    Default retention is 90 days for reachable commits and 30 days for unreachable ones, controlled by gc.reflogExpire and gc.reflogExpireUnreachable.


    The basic command

    git reflog
    

    Output looks like:

    a1b2c3d HEAD@{0}: reset: moving to HEAD~3
    4e5f6g7 HEAD@{1}: commit: feat: pricing table
    89abcde HEAD@{2}: commit: feat: hero section
    fedcba9 HEAD@{3}: pull: Fast-forward
    

    Each entry is: SHA, ref-relative position, action, message.

    HEAD@{0} is where you are now. HEAD@{1} is where you were one move ago. And so on.


    Reflog for specific refs

    git reflog defaults to HEAD. Every branch has its own reflog too:

    git reflog show main
    git reflog show origin/main      # remote-tracking branches also have one
    

    This is useful when you want to know "where did this branch's tip used to be?" — e.g., before someone rebased and force-pushed.


    Recovering a lost commit

    The classic case: you ran git reset --hard HEAD~3 and immediately regretted it.

    git reflog
    # a1b2c3d HEAD@{0}: reset: moving to HEAD~3
    # 4e5f6g7 HEAD@{1}: commit: feat: pricing table   <-- this is the work I want back
    git reset --hard 4e5f6g7
    

    Or, equivalently:

    git reset --hard HEAD@{1}
    

    The work is back. The reflog still records the destructive reset and the recovery, so even this recovery is undoable.


    Recovering a deleted branch

    Deleting a branch (git branch -D) removes the branch ref but leaves the commits in place — for now. Find the tip of the deleted branch in the HEAD reflog (the entry just before the delete):

    git reflog
    # 4e5f6g7 HEAD@{2}: checkout: moving from feature/x to main
    # ...
    git branch feature/x 4e5f6g7
    

    If you can't find it in the HEAD reflog, broader options:

    git fsck --lost-found
    

    This lists dangling commits and dangling blobs — work that has no ref pointing at it. Inspect with git show <sha> and recreate a branch when you find what you want.


    Recovering work after a botched rebase

    A rebase rewrites commits, leaving the originals dangling. The reflog of the branch you rebased shows where it used to point:

    git reflog show feature/x
    # 1a2b3c4 feature/x@{0}: rebase finished: returning to refs/heads/feature/x
    # 5d6e7f8 feature/x@{1}: rebase: hero
    # abcdef0 feature/x@{2}: branch: Created from main
    git reset --hard feature/x@{2}
    

    This is also why you should always create a backup branch before a complex rebase:

    git branch backup/feature-x
    git rebase main
    # if it goes wrong:
    git reset --hard backup/feature-x
    

    Time-based references

    The reflog supports time-based syntax:

    git show HEAD@{yesterday}
    git show HEAD@{2.hours.ago}
    git show main@{1.week.ago}
    git diff main@{1.week.ago} main
    

    Useful for "what did this branch look like before I started this morning?".


    Inspecting individual reflog entries

    Show the diff between where you are now and a previous reflog position:

    git diff HEAD@{1}
    

    Show the commit a reflog entry pointed to:

    git show HEAD@{3}
    

    Limit the reflog to a date range:

    git reflog --since="2 days ago"
    

    Practical recipes

    "I just ran git reset --hard. Get my work back."

    git reflog
    # find the SHA from before the reset
    git reset --hard <sha>
    

    "I deleted a branch I shouldn't have."

    git reflog
    # find the last entry that was on that branch
    git branch <branch-name> <sha>
    

    "My rebase produced garbage. Start over."

    git reflog show <branch>
    # find the entry just before the rebase started ("rebase: checkout ..." or "branch: Created ...")
    git reset --hard <branch>@{N}
    

    "Did anyone force-push to main? Where did it used to point?"

    git reflog show origin/main
    # look at HEAD@{1} or earlier entries
    

    (This works only if your local has fetched recently enough to have the old state. The remote's own reflog is private to the server.)

    "What's been happening on this branch this morning?"

    git reflog show <branch> --since="6 hours ago"
    

    When the reflog will not save you

    • Untracked files. The reflog only knows about commits. A git clean -fd or a git reset --hard over untracked files cannot be undone.
    • Garbage collection has run. After gc.reflogExpireUnreachable (default 30 days), unreachable commits can be permanently pruned by git gc.
    • You're in a different clone. The reflog is local. If the lost work happened on another machine, that machine's reflog is what you need.
    • You've rewritten everything since. Once you make many new commits or run an aggressive git gc, older orphaned commits may be cleaned out faster.

    If you fear loss is imminent, freeze garbage collection:

    git config gc.auto 0
    

    Then recover before turning it back on.


    Pitfalls

    • The reflog is local-only. Never assume someone else's reflog has what you want.
    • HEAD@{N} is by reflog position, not by date. HEAD@{1.day.ago} is by date. Don't confuse the two.
    • Force-pushes to your branch overwrite your remote-tracking reflog with each fetch. If you suspect a force-push and you haven't fetched yet, don't fetch — your local copy of origin/<branch> is still what it was before the force-push.

    Summary

    • git reflog lists every move HEAD has made. git reflog show <ref> does the same for a specific branch.
    • After any destructive command, git reflog is your first stop.
    • Recover with git reset --hard <sha> or by recreating a branch at the lost SHA.
    • The reflog is local and time-bounded — back up before risky operations and don't wait weeks to recover.
    • For deeper rescues, git fsck --lost-found finds dangling objects.