GitRecovering a Deleted Branch

Recovering a Deleted Branch

You deleted a branch and then realised it still had work you needed. Do not panic — Git almost never truly deletes commit data. The commits still exist as "dangling" objects in the repository. The key tool for recovering them is git reflog, which records every position HEAD has been at, even for branches that no longer exist.

Why recovery is usually possible

When you delete a branch with git branch -d or git branch -D, Git only removes the pointer (the label that says "branch-name = this commit hash"). The actual commit objects remain in the repository until Git's garbage collector removes them. The default reflog expiry is 90 days, giving you a generous window to recover.

Step 1: Find the lost commit using reflog

View the reflog

Bash
git reflog
# Output (most recent first):
# abc1234 HEAD@{0}: checkout: moving from feature-payments to main
# bcd2345 HEAD@{1}: commit: Add Stripe webhook handler
# cde3456 HEAD@{2}: commit: Add payment model
# def4567 HEAD@{3}: checkout: moving from main to feature-payments
# ghi5678 HEAD@{4}: commit: Update README
Read through the log looking for the last commit that was on the deleted branch. In this example, `bcd2345` (`HEAD@1`) was the tip of `feature-payments` before you switched back to `main`.

Filter reflog by branch name if the list is long

Bash
git reflog show --all | grep feature-payments
# bcd2345 refs/heads/feature-payments@{0}: commit: Add Stripe webhook handler
# cde3456 refs/heads/feature-payments@{1}: commit: Add payment model
Step 2: Inspect the commit to confirm it is the right one

Look at what is in the commit

Bash
git show bcd2345
# commit bcd2345...
# Author: Jane Dev <jane@example.com>
# Date:   Mon Jan 13 15:30:00 2025 +0000
#
#     Add Stripe webhook handler
#
# diff --git a/src/payments/webhook.js b/src/payments/webhook.js
# ...
Step 3: Re-create the branch

Create a new branch pointing at the recovered commit

Bash
git branch recovered-feature-payments bcd2345
# Branch 'recovered-feature-payments' set up to track nothing.

# Verify it is there with the right history
git log recovered-feature-payments --oneline -5
# bcd2345 Add Stripe webhook handler
# cde3456 Add payment model
# def4567 ... (from main)

Alternative: checkout directly using reflog syntax

Bash
# This creates the branch and switches to it in one step
git checkout -b recovered-feature-payments HEAD@{1}
# Switched to a new branch 'recovered-feature-payments'
If the branch was also on a remote

If the branch was pushed to the remote before it was deleted locally, you may be able to fetch it directly from the remote — even if the remote-tracking branch reference was also removed.

Try fetching the deleted branch from remote

Bash
# If the branch still exists on the remote:
git fetch origin feature-payments
git switch feature-payments
# Already up to date.

# If the remote reference is gone, check with:
git ls-remote origin | grep feature-payments
# If nothing returns, the remote branch is also gone

# Ask a teammate if they have it locally
# git fetch <their-remote> feature-payments
Remote branch deletion on GitHub
GitHub keeps deleted branches for a short time and shows a "Restore branch" button on the pull request page if the branch was linked to a PR. Check the PR before doing any reflog surgery.
Recovering when you cannot find the hash in reflog

If the branch was very old, or if git gc ran recently, the reflog entry may be gone. You can still search for dangling commits:

Find all dangling commits

Bash
git fsck --lost-found
# dangling commit bcd2345abc1234...
# dangling commit ...
# (listed in no particular order)

# Then inspect each dangling commit:
git show bcd2345abc1234

# Once found:
git branch recovered-branch bcd2345abc1234
The reflog expiry window
  • Default expiry for reachable objects: 90 days (gc.reflogExpire).

  • Default expiry for unreachable objects: 30 days (gc.reflogExpireUnreachable).

  • Check your config: git config gc.reflogExpire.

  • You can extend expiry: git config --global gc.reflogExpire "365 days".

  • After git gc --prune=now, dangling commits are deleted permanently.

Warning
Once Git garbage collection runs and prunes the dangling commits, recovery without a backup is impossible. If you work on a team, check whether a remote copy exists before assuming the data is gone.
Complete recovery walkthrough
  1. Run git reflog to see all HEAD movements.

  2. Identify the hash of the last commit on the deleted branch.

  3. Run git show <hash> to confirm it is the right commit.

  4. Run git branch recovered-branch <hash> to recreate the branch.

  5. Switch to it: git switch recovered-branch.

  6. Push to remote: git push origin recovered-branch.

Prevention
  • Push branches to remote before deleting them locally — remote copies serve as backups.

  • Use git branch -d (safe delete) instead of git branch -D — Git will warn you if the branch is not fully merged.

  • On GitHub/GitLab, avoid immediately deleting branches after merging a PR — the platform keeps them with a restore button.

  • Consider extending reflog expiry in teams: git config --global gc.reflogExpire "180 days".

Tip
`git branch -D` is the force-delete that skips the "is this merged?" check. If Git warns you that a branch is not fully merged and you want to delete it anyway, that warning is trying to help you — pause and confirm you do not need those commits.