git reflog: Finding Lost Commits and Recovering Deleted Branches
The previous lesson's warning about `git reset --hard` mentioned that reflog can sometimes help recover commits a reset moved away from. This lesson explains exactly how: `git reflog` is Git's own local safety net, silently recording every movement of HEAD, making many seemingly catastrophic mistakes — a bad hard reset, an accidentally deleted branch, a botched rebase — genuinely recoverable.
Learning Objectives
- Explain what git reflog records and why it exists.
- Use reflog to find a commit that seems to have disappeared after a reset or rebase.
- Recover from an accidentally deleted branch using reflog.
- Understand the limitations of reflog, including that it eventually expires and is local-only.
Key Terms to Know Before Using git reflog
- git reflog: A local, chronological log of every position HEAD has pointed to, recording nearly every operation that moves it (commits, resets, rebases, checkouts, and more).
- Reflog entry: A single recorded line in the reflog, showing a specific past HEAD position along with a description of the operation that led to it.
- Dangling commit: A commit that still exists in Git's object database but is no longer reachable from any branch or tag, typically because a reset, rebase, or branch deletion moved away from it.
- Reflog expiration: The eventual garbage collection of old reflog entries and unreachable commits, meaning reflog-based recovery isn't available indefinitely.
How git reflog Actually Works
Git maintains a local, chronological record called the **reflog**, tracking essentially every operation that moves `HEAD` — every commit, every branch switch, every reset, every rebase step, every checkout. Crucially, this log exists **independently of your actual branches**: even when a commit becomes unreachable from any branch (for example, after a `git reset --hard` moves the branch pointer away from it, or a rebase replaces it with a new commit), the original commit object doesn't immediately vanish from Git's underlying storage — it becomes what's called a **dangling commit**, still fully present but simply not pointed to by anything, and the reflog remembers exactly where to find it.
Viewing the reflog:
```
git reflog
```
produces output like:
```
9f8e7d6 HEAD@{0}: reset: moving to HEAD~1
a1b2c3d HEAD@{1}: commit: fix critical bug
3c4d5e6 HEAD@{2}: commit: add feature
```
Each line shows a past position of HEAD (with its commit hash), labeled with an index (`HEAD@{0}` being the most recent) and a description of what operation led to that position. In this example, `HEAD@{1}` shows the commit `a1b2c3d` — 'fix critical bug' — which the very next reflog entry (`HEAD@{0}`) shows was then reset away from. Even though this commit is no longer reachable through the normal branch history, it's still sitting right there in the reflog, fully recoverable.
**Recovering a 'lost' commit** after an accidental reset (or rebase, or any other history-altering operation) is often as simple as creating a new branch pointing directly at the dangling commit's hash found in the reflog:
```
git branch recovery-branch a1b2c3d
```
or, if you want to move your current branch back to that exact point:
```
git reset --hard a1b2c3d
```
(using reset once more, but this time deliberately moving *forward* to the commit you want to recover, rather than accidentally away from it).
**Recovering an accidentally deleted branch** works the same way: since deleting a branch (`git branch -D`, Module 3) only removes the pointer, not the underlying commits it referenced (as long as they're still reachable via reflog or another reference), you can find the branch's last known commit hash in the reflog and recreate the branch pointing at it:
```
git reflog
# find the entry showing the deleted branch's last commit, e.g.:
# 7f8e9d0 HEAD@{5}: checkout: moving from feature/lost-work to main
git branch feature/lost-work 7f8e9d0
```
It's important to understand reflog's limitations: it is **entirely local** — it exists only on your own machine and is never pushed to or shared via a remote, so it can't help recover something that was never on your local machine in the first place. It also **eventually expires**: unreachable commits and their reflog entries are subject to Git's periodic garbage collection (by default, after roughly 90 days for unreachable commits, though this is configurable), so reflog is a genuinely powerful and forgiving safety net, but not an infinite, permanent one.
git reflog Recovery: Visual Walkthrough
Draw a timeline of reflog entries, most recent first: 'HEAD@{0}: reset: moving to HEAD~1' pointing at commit 9f8e7d6, 'HEAD@{1}: commit: fix critical bug' pointing at commit a1b2c3d, 'HEAD@{2}: commit: add feature' pointing at 3c4d5e6. Show the CURRENT branch pointer sitting at HEAD@{0}'s commit (9f8e7d6), with commit a1b2c3d shown as 'dangling — not reachable from any branch, but still present in Git's storage.' Draw an arrow labeled 'git branch recovery-branch a1b2c3d' from the reflog entry directly to a NEW branch pointer placed back on the dangling commit, captioned 'Fully recovered.'
Common git reflog Recovery Scenarios: Quick Reference Table
| Scenario | Recovery Approach |
|---|---|
| Accidentally ran git reset --hard, losing recent commits | git reflog to find the commit hash, then git reset --hard <hash> or create a new branch there |
| Accidentally deleted a branch (git branch -D) | git reflog to find the branch's last commit hash, then git branch <name> <hash> to recreate it |
| A rebase or amend produced an unexpected result | git reflog to find the pre-rebase/amend commit hash, then check it out or branch from it |
| Lost work from days/weeks ago | May no longer be recoverable — reflog entries and unreachable commits eventually expire (default ~90 days) |
git reflog: Command Syntax and Recovery Examples
# View the reflog to find a lost commit
git reflog
# 9f8e7d6 HEAD@{0}: reset: moving to HEAD~1
# a1b2c3d HEAD@{1}: commit: fix critical bug <- this is the commit we lost!
# Recover it by creating a new branch pointing at that commit
git branch recovery-branch a1b2c3d
# Or, move your CURRENT branch back to that exact commit
git reset --hard a1b2c3d
# Recovering an accidentally deleted branch
git branch -D feature/important-work # oops!
git reflog
# 7f8e9d0 HEAD@{3}: checkout: moving from feature/important-work to main
git branch feature/important-work 7f8e9d0 # branch recreated, pointing at its last commit
Breaking Down the git reflog Recovery Example
The first block demonstrates the core recovery pattern: `git reflog` reveals that `a1b2c3d` (the 'fix critical bug' commit) was reset away from, and creating a new branch (or resetting back) to that exact hash fully recovers it, since the commit was never actually deleted from Git's storage, only unreachable from any branch. The second block shows recovering an entire accidentally deleted branch using the same underlying principle — finding its last known commit hash in the reflog and recreating a branch pointer there, effectively undoing the deletion.
How git reflog Is Used to Recover From Real Mistakes
- git reflog has saved countless developers from what initially felt like catastrophic, unrecoverable mistakes — an accidental hard reset or a mistakenly deleted branch — turning a moment of panic into a routine recovery.
- Experienced Git users often reflexively check git reflog as their very first troubleshooting step whenever something in their local history seems to have unexpectedly disappeared.
- Some teams' onboarding materials explicitly teach reflog early specifically to reduce anxiety around more powerful, potentially destructive commands like reset --hard and interactive rebase, since users can be reassured that most mistakes remain recoverable.
- Because reflog is local-only, developers who accidentally delete a branch that was only ever local (never pushed) rely entirely on reflog for recovery, since no remote copy exists to fall back on.
git reflog Interview Questions and Answers
Q1. What is git reflog, and what does it record?
It's a local, chronological log tracking essentially every operation that moves HEAD — commits, resets, rebases, checkouts, and more — recording each past position along with a description of what operation led to it. It exists independently of your actual branches, which is what makes recovery of seemingly lost commits possible.
Q2. How would you recover a commit that was accidentally lost due to a hard reset?
Run git reflog to find the commit's hash from before the reset occurred, then either create a new branch pointing at that hash (git branch recovery-branch <hash>) or move your current branch back to it with git reset --hard <hash>, since the original commit still exists in Git's storage even though it was no longer reachable from any branch.
Q3. What are the limitations of git reflog as a recovery mechanism?
It's entirely local, existing only on your own machine and never pushed to or shared via a remote, so it can't recover something that was never on your local machine. It also eventually expires — unreachable commits and their reflog entries are subject to periodic garbage collection, by default after roughly 90 days, so it's a powerful but not infinite safety net.
git reflog Quiz: Test Your Understanding
1. What does git reflog record?
- Only commits pushed to a remote repository
- Every position HEAD has pointed to locally, including commits, resets, rebases, and checkouts
- Only merge commits
- A list of all repository collaborators
Answer: B. Every position HEAD has pointed to locally, including commits, resets, rebases, and checkouts
Explanation: Reflog tracks nearly every local operation that moves HEAD, maintaining a chronological record independent of your current branch structure.
2. After an accidental git reset --hard, how would you recover a commit that seems to have disappeared?
- It's permanently unrecoverable
- Find its hash using git reflog, then create a new branch or reset back to that hash
- Re-clone the entire repository from the remote
- Run git commit --undo
Answer: B. Find its hash using git reflog, then create a new branch or reset back to that hash
Explanation: Since the original commit still exists in Git's storage even after becoming unreachable, reflog reveals its hash, letting you recover it by branching from or resetting back to that exact commit.
3. What is a key limitation of git reflog as a recovery tool?
- It only works on Windows
- It is entirely local and its entries eventually expire (by default, after roughly 90 days)
- It requires a paid GitHub plan
- It can only recover the single most recent commit
Answer: B. It is entirely local and its entries eventually expire (by default, after roughly 90 days)
Explanation: Reflog exists only on your own machine, never shared via a remote, and its entries for unreachable commits are subject to periodic garbage collection after a default retention period.
Common git reflog Mistakes and Misunderstandings
- Panicking after a bad reset or accidental branch deletion without realizing git reflog can very likely recover it.
- Assuming reflog can recover something that was never actually committed in the first place — it only tracks HEAD positions across commits, not uncommitted working directory changes.
- Expecting reflog entries to be shared across machines or pushed to a remote, when it's entirely local to each individual clone.
- Waiting too long to attempt recovery, not realizing reflog entries and unreachable commits eventually expire and become permanently unrecoverable.
git reflog: Exam-Ready Quick Notes
- git reflog: local, chronological log of every HEAD movement (commits, resets, rebases, checkouts).
- Dangling commit: still exists in Git's storage even when unreachable from any branch — reflog reveals its hash.
- Recovery: git branch <name> <hash> or git reset --hard <hash>, using a hash found in the reflog.
- Limitations: entirely local (never shared via remote); entries eventually expire (default ~90 days for unreachable commits).
git reflog: Key Takeaways
- git reflog is Git's own local safety net, making most seemingly catastrophic history mistakes genuinely recoverable.
- Commits aren't immediately deleted when they become unreachable from a branch — they remain as dangling commits until eventually garbage collected.
- Reflog's local-only nature and eventual expiration mean it's a powerful but not infinite or universally available recovery mechanism.
Frequently Asked Questions About git reflog
Q1. What is git reflog?
It's a local log that Git automatically maintains, recording essentially every position HEAD has pointed to — including commits, resets, rebases, and branch checkouts — letting you look back at your repository's recent history of operations, even ones that seem to have undone something.
Q2. Can I recover a commit after accidentally running git reset --hard?
Yes, very likely. Run git reflog to find the commit's hash from before the reset, then create a new branch pointing at that hash, or reset your branch back to it — the original commit typically still exists in Git's storage even though it became unreachable from any branch.
Q3. Can git reflog recover an accidentally deleted branch?
Yes. Since deleting a branch only removes the pointer, not necessarily the commits it referenced, you can find the branch's last known commit hash in the reflog and recreate the branch pointing at that exact commit.
Q4. Does reflog work across different machines or get shared when I push?
No. Reflog is entirely local to each individual clone of a repository — it's never pushed to or shared via a remote, so it can only help recover something that existed on your own machine.
Q5. Is git reflog a permanent, unlimited safety net?
No. While it's genuinely powerful for recent mistakes, reflog entries and the unreachable commits they point to are eventually subject to Git's periodic garbage collection, by default after roughly 90 days, so recovery isn't guaranteed indefinitely.
Summary
`git reflog` maintains a local, chronological log of essentially every operation that moves HEAD — commits, resets, rebases, checkouts — existing independently of your current branch structure. This is what makes recovery from seemingly catastrophic mistakes possible: when a commit becomes unreachable from any branch (due to a hard reset, a rebase, or a deleted branch), it doesn't immediately disappear from Git's storage — it becomes a dangling commit, still fully present and findable via its hash in the reflog. Recovery typically involves running `git reflog` to find the relevant commit hash from before the mistake occurred, then creating a new branch pointing at it or resetting your current branch back to it. Reflog's key limitations are that it's entirely local (never pushed to or shared via a remote, so it can't recover something that only ever existed elsewhere) and that its entries eventually expire through Git's periodic garbage collection, by default after roughly 90 days for unreachable commits — making it a powerful, forgiving safety net, but not an infinite one.