Recovering a Deleted Branch with git reflog
Imagine that you created a branch named register, committed a completed
registration feature, switched back to main, and then deleted register by
mistake.
Before deletion:
main → C3register → C4
After deletion:
main → C3
No branch name points to C4The branch name disappeared, but the commit object is not necessarily erased immediately. If Git still has the commit and a recent local Reflog entry can identify it, we can create the branch name again at that commit.
First: do not panic or run cleanup commands
Section titled “First: do not panic or run cleanup commands”When you notice the mistake, avoid commands that expire Reflog entries or prune unreachable objects. Do not assume recovery will remain possible forever.
What is a Reflog?
Section titled “What is a Reflog?”Reflog is short for reference log. Git references include branch names
and HEAD. A Reflog records recent changes to the value of a reference in this
local repository.
For example, the HEAD Reflog can record that you:
- Created a commit.
- Amended the latest commit.
- Switched from one branch to another.
- Moved
HEADthrough commands such as reset or rebase.
Run:
git reflogWith no reference name, this displays the Reflog for HEAD. It is equivalent
to asking Git to show recent positions that HEAD has occupied.
git reflog show HEAD is the explicit form:
git reflog show HEADshow selects the display operation, and HEAD selects the reference whose
log we want to inspect.
git log versus git reflog
Section titled “git log versus git reflog”These commands answer different questions:
| Command | Main question |
|---|---|
git log |
Which commits are reachable through the history I asked to view? |
git reflog |
Where did a local reference, normally HEAD, point recently? |
After deleting register, its unique commit may no longer be reachable from
the remaining branch names, so a normal git log on main may not show it.
The HEAD Reflog may still remember that HEAD occupied that commit.
git logdisplays commit history.git reflogdisplays a local movement record for references. Reflog does not create another project history.
Reading a Reflog line
Section titled “Reading a Reflog line”Illustrative output based on our example:
c02a268 HEAD@{0}: checkout: moving from register to mainb0d3acb HEAD@{1}: commit: feat: add registration form4e2ad21 HEAD@{2}: checkout: moving from main to register4e2ad21 HEAD@{3}: commit: fix login validationRead the second line as follows:
b0d3acb Abbreviated commit hash for the state recorded by this entry.
HEAD@{1} The previous position recorded for HEAD, one Reflog entry ago.
commit The kind of action that updated HEAD.
feat: add registration form The Reflog message, derived here from the commit action and message.HEAD@{0} is the newest entry, HEAD@{1} is the one before it, and so on.
The number is a Reflog position, not a commit number.
Why can the commit survive branch deletion?
Section titled “Why can the commit survive branch deletion?”A branch is a reference: a movable name pointing to a commit.
register → b0d3acbDeleting the branch removes the register reference. It does not directly
issue an instruction to erase commit b0d3acb at that moment.
Before:register → b0d3acb
After:no register referenceb0d3acb may still exist in the object databaseIf no remaining branch, tag, or other reference reaches the commit, it is unreachable. Reflog entries can keep recently unreachable objects available for a recovery period, but that period is not permanent.
Important: the deleted branch’s own Reflog may be gone
Section titled “Important: the deleted branch’s own Reflog may be gone”Local branches can have their own Reflogs. However, deleting a branch also deletes the Reflog associated with that branch reference. Therefore, a command such as this may fail after deletion:
git reflog show registerThat does not immediately prove the commit is gone. The HEAD Reflog may
still contain entries from when you switched to register or committed on it:
git reflogThis is why the recovery workflow normally begins with the HEAD Reflog.
Recovery workflow
Section titled “Recovery workflow”We will recover register without changing or rewriting any existing commit.
Step 1: confirm that the branch is missing
Section titled “Step 1: confirm that the branch is missing”git branchExample:
* mainThis lists local branches. If register is absent, its local branch reference
does not currently exist.
Step 2: inspect the Reflog
Section titled “Step 2: inspect the Reflog”git reflogLook for entries related to:
- A commit message you remember.
- Switching from
registertomain. - The approximate time of the lost work.
- The commit that was at the tip of
register.
Suppose you find:
b0d3acb HEAD@{1}: commit: feat: add registration formDo not recreate the branch yet merely because the message looks familiar. Inspect the commit first.
Step 3: verify the candidate commit
Section titled “Step 3: verify the candidate commit”git show --stat b0d3acbgit show Displays information about a Git object, here a commit.
--stat Shows the changed-file summary instead of the complete patch.
b0d3acb The candidate commit hash found in the Reflog.If you need to inspect the exact patch:
git show b0d3acbConfirm the author, message, date, and changes. If it is not the correct tip, return to the Reflog and inspect another candidate.
Step 4: recreate and switch to the branch
Section titled “Step 4: recreate and switch to the branch”After verifying the hash, run:
git switch -c register b0d3acbgit switch Switches branches.
-c Creates a new branch before switching to it.
register The branch name to create.
b0d3acb The starting commit for the new branch.The command creates a new reference named register pointing to
b0d3acb, then makes it the current branch:
Before recovery:
main → C3 C4 (b0d3acb) has no branch name
After recovery:
main → C3register → C4 (b0d3acb)HEAD → registerNo commit is copied, modified, or recreated. We restore a branch reference that points to the already existing commit.
Step 5: verify the recovered branch
Section titled “Step 5: verify the recovered branch”git branch -vgit log --oneline --decorate -n 3git statusgit branch -vshows each local branch and its tip commit.--onelineuses a compact log format.--decoratedisplays names such asHEADandregisterbeside commits.-n 3limits the output to three commits.git statusconfirms the current branch and repository state.
Expected idea:
* register b0d3acb feat: add registration form main 4e2ad21 fix login validationThe asterisk shows that register is current, and its tip is the recovered
commit.
Recreate the branch without switching
Section titled “Recreate the branch without switching”If you want to stay on main, use:
git branch register b0d3acbgit branch Creates a branch reference when given a new name.
register The new branch name.
b0d3acb The commit the branch should point to.State afterward:
main → C3register → C4 (b0d3acb)HEAD → mainUse git switch register later when you are ready to work on it.
Can HEAD@{n} be used directly?
Section titled “Can HEAD@{n} be used directly?”Yes, Git revision syntax can identify a Reflog entry:
git switch -c register "HEAD@{1}"Quoting is a safe habit because some shells give braces special meaning. However, the hash is clearer for a recovery walkthrough after verification:
git switch -c register b0d3acbReflog is local
Section titled “Reflog is local”Reflog records belong to a particular local repository:
- Your computer’s Reflog is not uploaded by
git push. - A teammate normally has a different Reflog.
- A fresh clone does not receive the old Reflog from another machine.
- A hosting website is not a substitute for your local Reflog.
If the branch existed on a remote, fetching and recreating a local branch from the remote-tracking reference may be easier. Remote recovery belongs to a later lesson.
Reflog is temporary
Section titled “Reflog is temporary”Git expires old Reflog entries according to configuration and maintenance. Typical defaults are longer for reachable entries and shorter for unreachable entries, but settings and repository maintenance can change the actual window. Do not build a recovery plan around a guaranteed number of days.
Reflog often saves recent local work, but it does not promise permanent retention.
Common mistakes
Section titled “Common mistakes”Choosing the first familiar hash
Section titled “Choosing the first familiar hash”Several commits may have similar messages. Verify with git show before
creating the branch.
Pointing to an older commit on the branch
Section titled “Pointing to an older commit on the branch”Choose the last required commit at the branch tip. Pointing to an earlier commit can make later work appear missing even though other objects still exist.
Using HEAD@{n} as if it were permanent
Section titled “Using HEAD@{n} as if it were permanent”The position changes as new Reflog entries are added. Record the verified commit hash.
Thinking Reflog restores uncommitted edits
Section titled “Thinking Reflog restores uncommitted edits”Reflog records reference movements. It does not generally store arbitrary unsaved or uncommitted Working Tree content.
Creating the branch at current HEAD
Section titled “Creating the branch at current HEAD”git switch -c registerwithout the recovered hash creates register at the current commit, which may
be main, not at the lost registration commit.
Running destructive cleanup before recovery
Section titled “Running destructive cleanup before recovery”Expiring Reflogs or pruning unreachable objects can reduce recovery options. Inspect and restore the reference first.
Command summary
Section titled “Command summary”| Goal | Command |
|---|---|
Show the HEAD Reflog |
git reflog |
| Show it explicitly | git reflog show HEAD |
| Inspect a candidate summary | git show --stat b0d3acb |
| Inspect the complete candidate patch | git show b0d3acb |
| Recreate and switch to the branch | git switch -c register b0d3acb |
| Recreate it without switching | git branch register b0d3acb |
| Verify branch tips | git branch -v |
| Verify decorated history | git log --oneline --decorate -n 3 |
Key takeaway
Section titled “Key takeaway”Deleting a branch removes a name pointing to a commit; it does not necessarily erase the commit immediately. Use the local
HEADReflog to find the lost tip, verify its hash withgit show, then recreate the branch at that exact commit withgit switch -c <branch> <hash>orgit branch <branch> <hash>.