Skip to content

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 → C3
register → C4
After deletion:
main → C3
No branch name points to C4

The 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.

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 HEAD through commands such as reset or rebase.

Run:

Terminal window
git reflog

With 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:

Terminal window
git reflog show HEAD

show selects the display operation, and HEAD selects the reference whose log we want to inspect.

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 log displays commit history. git reflog displays a local movement record for references. Reflog does not create another project history.

Illustrative output based on our example:

c02a268 HEAD@{0}: checkout: moving from register to main
b0d3acb HEAD@{1}: commit: feat: add registration form
4e2ad21 HEAD@{2}: checkout: moving from main to register
4e2ad21 HEAD@{3}: commit: fix login validation

Read 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 → b0d3acb

Deleting 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 reference
b0d3acb may still exist in the object database

If 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:

Terminal window
git reflog show register

That 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:

Terminal window
git reflog

This is why the recovery workflow normally begins with the HEAD Reflog.

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”
Terminal window
git branch

Example:

* main

This lists local branches. If register is absent, its local branch reference does not currently exist.

Terminal window
git reflog

Look for entries related to:

  • A commit message you remember.
  • Switching from register to main.
  • 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 form

Do not recreate the branch yet merely because the message looks familiar. Inspect the commit first.

Terminal window
git show --stat b0d3acb
git 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:

Terminal window
git show b0d3acb

Confirm the author, message, date, and changes. If it is not the correct tip, return to the Reflog and inspect another candidate.

After verifying the hash, run:

Terminal window
git switch -c register b0d3acb
git 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 → C3
register → C4 (b0d3acb)
HEAD → register

No commit is copied, modified, or recreated. We restore a branch reference that points to the already existing commit.

Terminal window
git branch -v
git log --oneline --decorate -n 3
git status
  • git branch -v shows each local branch and its tip commit.
  • --oneline uses a compact log format.
  • --decorate displays names such as HEAD and register beside commits.
  • -n 3 limits the output to three commits.
  • git status confirms the current branch and repository state.

Expected idea:

* register b0d3acb feat: add registration form
main 4e2ad21 fix login validation

The asterisk shows that register is current, and its tip is the recovered commit.

If you want to stay on main, use:

Terminal window
git branch register b0d3acb
git 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 → C3
register → C4 (b0d3acb)
HEAD → main

Use git switch register later when you are ready to work on it.

Yes, Git revision syntax can identify a Reflog entry:

Terminal window
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:

Terminal window
git switch -c register b0d3acb

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.

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.

Several commits may have similar messages. Verify with git show before creating 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.

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.

Terminal window
git switch -c register

without 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.

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

Deleting a branch removes a name pointing to a commit; it does not necessarily erase the commit immediately. Use the local HEAD Reflog to find the lost tip, verify its hash with git show, then recreate the branch at that exact commit with git switch -c <branch> <hash> or git branch <branch> <hash>.