How to Recover a Branch You Accidentally Deleted

by Eric Hanson, Backend Developer at Clean Systems Consulting

The Commits Are Still There

You ran git branch -D feature/payment-retry and immediately realized you hadn't merged it. Or your Git host auto-deleted the branch after merge, but the merge was to the wrong target. Or you ran git push origin --delete feature/payment-retry and regretted it immediately.

The branch is gone. The commits are not. In Git's object model, a branch is just a named pointer to a commit. Deleting the branch removes the pointer, not the commits themselves. Those commits remain in the object store until Git's garbage collector runs — typically not for at least two weeks, and not at all if the objects are reachable from any other reference (tags, stash, reflog).

The recovery path depends on whether you're recovering a local branch, a remote branch, or both.

Recovering a Local Branch

Reflog is your first stop. Reflog records every movement of HEAD and every branch pointer, including the tip commit of a branch just before it was deleted.

# Show recent HEAD movements
git reflog

# Output example:
# a3f9d24 HEAD@{0}: checkout: moving from feature/payment-retry to main
# b7c12e1 HEAD@{1}: commit: Add exponential backoff to retry logic
# f4d8a09 HEAD@{2}: commit: Add PaymentRetryService
# 9e1b3c7 HEAD@{3}: checkout: moving from main to feature/payment-retry

The entry HEAD@{0} shows you switched from feature/payment-retry to main. The entry at HEAD@{1} is the last commit on the deleted branch — SHA b7c12e1.

Recreate the branch at that commit:

git checkout -b feature/payment-retry b7c12e1
# or
git branch feature/payment-retry b7c12e1

If you know the branch name but not the SHA, search reflog specifically:

git reflog | grep 'feature/payment-retry'
# Shows all reflog entries mentioning that branch name

You can also search for the branch's last known tip using the branch-specific reflog (which may still exist briefly after deletion):

git reflog show feature/payment-retry
# If it still exists in reflog, this shows commits from that branch's perspective

Recovering a Remote Branch

If the branch was deleted on the remote (GitHub, GitLab, etc.), your recovery options depend on timing and who has local copies.

If you still have the branch locally (you deleted it remotely but not locally):

# Re-push it
git push origin feature/payment-retry

If another developer has it locally:

# Have them push it back
git push origin feature/payment-retry

If nobody has it locally and it was deleted recently from GitHub:

GitHub retains deleted branches for a period and exposes a "Restore branch" option in the PR associated with the branch. Navigate to the closed or merged PR → look for "feature/payment-retry was deleted" → click "Restore branch." This works if there was an associated PR. If the branch was pushed but never had a PR, this option doesn't exist.

GitLab has a similar restore option in the repository's branch management UI for recently deleted branches.

If the remote branch is gone and nobody has it locally:

This is the worst case. Your only hope is the object store on the remote server, which you likely don't have direct access to. However, if you have any local repository that ever fetched from the remote while that branch existed, your local object store may contain the commits even without a local branch pointing to them.

# Check if any objects related to your lost work exist locally
git fsck --lost-found
# Creates .git/lost-found/commit/ with dangling commit objects

ls .git/lost-found/commit/
# Each file is a commit SHA — read them to find your work
git log --oneline <sha>
git show <sha>

Walk through the dangling commits until you find the one that's the tip of your lost branch. Then recreate the branch pointing to it.

If You Had Uncommitted Changes When You Deleted

This is the harder case. Git stash is reflogged, so if you stashed before deleting:

git stash list
git stash show -p stash@{0}  # inspect the stash
git stash pop                 # restore it

But if you had uncommitted, unstaged changes that weren't stashed when you deleted the branch — those are truly gone. Git's object store only tracks committed content. The working tree's state is not preserved unless it was committed or stashed.

This is the one scenario in Git that is genuinely difficult to recover from. The lesson: if you're about to do anything destructive (branch deletion, reset --hard, rebase), run git stash push -m "safety: $(date)" first.

Preventing Accidental Deletion

For local branches:

# -d (lowercase) only deletes if the branch is fully merged
# -D (uppercase) force-deletes regardless
git branch -d feature/payment-retry   # safe: fails if not merged
git branch -D feature/payment-retry   # dangerous: always deletes

Make -D a deliberate choice, not a habit.

For remote branches on GitHub, enable branch protection on main to prevent accidental deletion of the main branch. For other branches, consider requiring PRs before deletion for long-lived branches (release branches, develop branches).

The GitHub CLI gh makes it easy to check before deleting:

gh pr list --head feature/payment-retry
# Verify there's a merged PR before deleting
git push origin --delete feature/payment-retry

Recovery is almost always possible. The window is wide — reflog entries persist for 90 days by default (gc.reflogExpire). Don't panic, open reflog, and find the SHA.

Scale Your Backend - Need an Experienced Backend Developer?

We provide backend engineers who join your team as contractors to help build, improve, and scale your backend systems.

We focus on clean backend design, clear documentation, and systems that remain reliable as products grow. Our goal is to strengthen your team and deliver backend systems that are easy to operate and maintain.

We work from our own development environments and support teams across US, EU, and APAC timezones. Our workflow emphasizes documentation and asynchronous collaboration to keep development efficient and focused.

  • Production Backend Experience. Experience building and maintaining backend systems, APIs, and databases used in production.
  • Scalable Architecture. Design backend systems that stay reliable as your product and traffic grow.
  • Contractor Friendly. Flexible engagement for short projects, long-term support, or extra help during releases.
  • Focus on Backend Reliability. Improve API performance, database stability, and overall backend reliability.
  • Documentation-Driven Development. Development guided by clear documentation so teams stay aligned and work efficiently.
  • Domain-Driven Design. Design backend systems around real business processes and product needs.

Tell us about your project

Our offices

  • Copenhagen
    1 Carlsberg Gate
    1260, København, Denmark
  • Magelang
    12 Jalan Bligo
    56485, Magelang, Indonesia

More articles

Dublin's Best Backend Developers Work for Google and Meta — What the Rest of Us Do

You posted a backend role three weeks ago. The only applicants who fit are already at a FAANG company and just "seeing what's out there." They're not leaving.

Read more

How Melbourne Tech Teams Are Extending Their Bandwidth With Async Remote Backend Contractors

A small backend team in Melbourne can only move so fast. Some startups have found a way to extend that capacity without adding permanent headcount.

Read more

Java Code Quality in Practice — The Rules That Help and the Ones That Don't

Most Java code quality guidance is either too abstract to apply or applied too rigidly to improve real codebases. Here is a honest assessment of the rules that consistently improve maintainability and the ones that create friction without payoff.

Read more

Spring Boot Request Processing Overhead — Filter Chains, Serialization, and What's Worth Measuring

Spring Boot's request processing pipeline adds overhead before and after your business logic runs. Most of it is negligible. Some of it isn't. Here is how to measure each layer and what actually warrants optimization.

Read more