Recover a recently deleted local branch
A recently deleted local branch can be recreated if its commit still exists and you can identify the correct commit. Inspect HEAD’s local reflog for a surviving candidate, check that candidate’s changes, then create a new branch at it. This restores a reference to existing history; it cannot reconstruct content that Git no longer has.
First identify what disappeared
A missing branch name, a missing commit and missing uncommitted edits are different problems. This guide covers the first: a local branch reference was deleted, but its unique tip commit still exists. The example deliberately keeps that commit available through the recent local history. It does not simulate expired logs, removed objects or files that were never committed.
Avoid turning the first plausible identifier into a recovery result. A repository may contain several recent commits with similar messages. The useful question is whether the candidate contains the work you meant to preserve. Inspect the message, changed files and content together. A familiar branch name alone cannot establish that a candidate is the right tip.
The HEAD reflog records reference movements and branch switches1. Deleting a branch deletes that branch’s own reflog2, so inspect git reflog show HEAD, not the deleted branch’s log. Recover promptly. The deletion message, Deleted branch … (was <id>), is another direct clue to inspect if it remains in your terminal output. Both clues depend on the commit object still existing.
Reproduce the narrow recovery case
The script starts a new fictional repository, creates a topic branch with a unique committed change, switches back to main, and deletes the topic reference. The deletion is included only to construct the example. Do not transplant that step into a repository containing work you want to recover.
The next steps inspect the retained entry, verify the candidate’s content, and create recovered at that commit. The script asserts that the recovered tip is the original unique tip and differs from the commit still checked out on main. Run it from an empty directory with Git 2.56.0 available.
Download the exact MIT-licensed example. The script leaves its new repository in place rather than deleting the evidence afterward.
#!/bin/sh
# SPDX-License-Identifier: MIT
set -eu
export TZ=UTC LC_ALL=C
export GIT_CONFIG_NOSYSTEM=1 GIT_CONFIG_GLOBAL=/dev/null
export GIT_AUTHOR_NAME='Example Author'
export GIT_AUTHOR_EMAIL='author@example.invalid'
export GIT_COMMITTER_NAME='Example Author'
export GIT_COMMITTER_EMAIL='author@example.invalid'
export GIT_AUTHOR_DATE='2026-10-25T12:00:00Z'
export GIT_COMMITTER_DATE='2026-10-25T12:00:00Z'
test "$(git --version)" = 'git version 2.56.0'
mkdir recovery-example
cd recovery-example
git -c init.templateDir= init -q -b main
printf 'base\n' > note.txt
git add note.txt
git commit -qm 'Base'
git switch -qc topic
printf 'unique topic work\n' > note.txt
git commit -qam 'Unique topic work'
original_tip=$(git rev-parse HEAD)
git switch -q main
# This deletion is only for the newly created fictional repository.
git branch -D topic > deletion.txt
cat deletion.txt
git reflog show HEAD --format='%h %gs'
candidate=$(git rev-parse 'HEAD@{1}')
test "$candidate" = "$original_tip"
test "$candidate" != "$(git rev-parse HEAD)"
git show --format=fuller --stat "$candidate"
test "$(git show "$candidate":note.txt)" = 'unique topic work'
git branch recovered "$candidate"
test "$(git rev-parse recovered)" = "$original_tip"
test "$(git branch --show-current)" = main
printf 'recovery: original tip named; main remains checked out\n'
Read the log before choosing a candidate
The printed reflog identifies the operations performed in this fresh repository. Because the script creates the same sequence each time, its candidate is the previous HEAD value after the switch to main. That position is a feature of this example’s sequence. In an existing repository, other commands may have added entries, so the same numbered position can identify something else.
Read the entries and inspect the candidate that matches the work, instead of copying the example’s position mechanically. If the log is ambiguous, preserve the available evidence and investigate further before moving any existing branch. A new, unused branch name can protect a chosen surviving commit without replacing the reference that is currently in use.
The example stores the original topic tip before deleting its name. That value is an assertion oracle for the demonstration, not a recovery prerequisite imposed on readers. The candidate is obtained from the retained reflog entry, and the stored value checks whether the method found the intended unique commit. This distinction prevents the demonstration from merely renaming the current commit and calling it recovery.
Inspect the content, not just the identifier
The inspection step prints the candidate’s commit details and changed-file summary. It also reads note.txt from the candidate commit and compares the content with the unique topic text. Those checks give a concrete reason to accept this candidate. A matching identifier without an inspected change would be much less informative to someone trying to recover actual work.
For a real project, inspect the relevant files and their relationships before concluding that the whole task has returned. One recovered commit can be the tip of several earlier commits, or it can be a different point in the same line of work. The example contains one unique topic commit so that the expected result is clear. It makes no claim about choosing between several competing tips.
Create a name without switching immediately
Creating a branch at a candidate commit does not itself check that branch out2. The example verifies this: recovered points to the unique topic tip while main remains current. That separation is useful because identifying and preserving history can happen before deciding how to change the working directory.
Choose an unused branch name for the recovery attempt. Do not overwrite an existing branch merely to reuse the old spelling. Once the candidate has a durable reference, compare its history with the branch where the work belongs and decide the next step. The diff guide covers the narrower distinction between staged and working changes, which should also be checked before switching tasks.
The recovered branch contains a change that is not merged into main. The example stops with that branch preserved. It does not configure an upstream or run branch cleanup; recovering the reference is the task, and deleting other references would be a separate decision.
Know where this method stops
Reflog entries expire first: gc.reflogExpireUnreachable defaults to 30 days for entries unreachable from the current tip, and gc.reflogExpire defaults to 90 days1. Once no reference or reflog protects an object, it can become prunable; gc.pruneExpire defaults to an age cutoff of two weeks3. This is not an extra two-week recovery window after a log expires.
Git can run garbage collection automatically during ordinary operations when its maintenance thresholds are met4. Configuration can change the defaults, so do not treat them as a recovery guarantee. Inspect the surviving candidate and give it a new branch name promptly, before an expiry or collection removes the evidence.
If the relevant entry is absent, do not treat this example as evidence that recovery must still succeed. Other local references, another clone or an established backup may contain the work, but checking those is a separate investigation. This guide intentionally stops before destructive cleanup, object pruning or attempts to reconstruct data from partial evidence.
Verify the result before resuming the task
A useful recovery record identifies the chosen commit, the new branch name and the content that made the candidate convincing. Keep the current branch and working files separate from that record until you decide how to continue. Recovering a name is complete when it points to the intended surviving history; integrating that history is another operation with its own checks.
Not covered on this page
- Recovery after reflog expiry or removal of the underlying objects.
- Restoration of uncommitted files that Git never recorded.
- Server-side branch recovery or searching another person’s repository.
- Choosing an integration strategy for several competing recovered tips.
Sources
How we test: methodology. Found a mistake? Corrections.