Recovering a deleted branch Jump to heading
Branches get deleted by accident all the time: git branch -D on the wrong name, a cleanup script with a pattern that matched too much, the forge’s “delete branch” button clicked after merging a pull request that was not actually finished. Deleting a branch removes a name, not commits. The commits stay in the repository until garbage collection decides nobody can reach them, which by default takes weeks for anything that was recently referenced. Recovery is a matter of finding the hash the branch pointed to and creating the name again. This page covers each kind of deletion, from the easiest to the hardest, within history rewriting and recovery.
When to use this approach Jump to heading
- You deleted a local branch and realise it had unmerged work.
- A remote branch was deleted — by you, a teammate, a cleanup job or a merge button.
- A stale-branch automation, like the one in closing stale branches and pull requests, removed something still in use.
- The deletion happened recently; the sooner you act, the more recovery paths remain.
Step 1 — Read the hash from the deletion message Jump to heading
git branch -d and -D print the hash the branch pointed to. If the terminal is still open, that is the fastest recovery.
$ git branch -D feature/invoice-pdf
Deleted branch feature/invoice-pdf (was 8b3e4f2). git branch feature/invoice-pdf 8b3e4f2
git log --oneline -3 feature/invoice-pdf Step 2 — Find it in the HEAD reflog Jump to heading
If the message has scrolled away, the HEAD reflog remembers every commit you checked out. A branch you worked on recently appears there, usually as the target of a checkout or as commits you made.
git reflog --date=relative | grep -E 'feature/invoice-pdf|checkout: moving from feature/invoice-pdf' | head
# 8b3e4f2 HEAD@{14 minutes ago}: checkout: moving from feature/invoice-pdf to main
git branch feature/invoice-pdf 8b3e4f2 The branch’s own reflog is deleted along with the branch, which is why the HEAD reflog and the remote-tracking reflog are the places to look.
Step 3 — Recover a deleted remote branch Jump to heading
If the branch was deleted on the server but you fetched it before, your remote-tracking ref may still exist — fetching with prune removes it, so check before fetching again.
# Still present locally? Recreate the remote branch from it
git rev-parse --verify origin/feature/invoice-pdf && \
git push origin origin/feature/invoice-pdf:refs/heads/feature/invoice-pdf
# Already pruned? Its reflog may still record the last value
git reflog show origin/feature/invoice-pdf 2>/dev/null | head -3 For branches deleted through a merged or closed pull request, hosted forges offer a restore action, and the pull request page records the head commit hash even after deletion.
# The head commit of the pull request survives on the forge
gh pr view 812 --json headRefName,headRefOid --jq '"\(.headRefName) \(.headRefOid)"'
git fetch origin "$(gh pr view 812 --json headRefOid --jq .headRefOid)"
git push origin FETCH_HEAD:refs/heads/feature/invoice-pdf Step 4 — When reflogs have nothing: search for dangling commits Jump to heading
If the branch never touched your HEAD and you have no remote-tracking ref, its commits may still be in the object store as unreachable objects. git fsck lists them, and the commit messages identify the right one.
git fsck --lost-found --no-reflogs 2>/dev/null | awk '/dangling commit/{print $3}' |
while read -r c; do git log -1 --format="%h %ci %s" "$c"; done | sort -k2 -r | head -20 The fuller technique, including recovering blobs and stashes, is in recovering unreachable objects with git fsck.
Step 5 — Lengthen the safety net Jump to heading
Recovery depends on objects surviving long enough to be found. The defaults keep reachable reflog entries for ninety days and unreachable ones for thirty. On machines where branches are deleted by automation, and on servers, consider longer windows.
git config --global gc.reflogExpire 180.days
git config --global gc.reflogExpireUnreachable 90.days
git config --global gc.pruneExpire 1.month.ago On servers you control, deleted branches can be preserved automatically by a hook that archives the old value of every deleted ref.
#!/bin/sh
# hooks/post-receive — keep deleted branch tips under refs/deleted/
zero=$(git hash-object --stdin </dev/null | tr '0-9a-f' '0')
while read -r old new ref; do
[ "$new" = "$zero" ] && git update-ref "refs/deleted/$(date +%Y%m%d)/${ref#refs/heads/}" "$old"
done Validation checklist Jump to heading
Frequently Asked Questions Jump to heading
How long do I have after deleting a branch? Jump to heading
Locally, commits that were recently on a branch stay reachable through the HEAD reflog for ninety days by default and survive as unreachable objects for at least two weeks after that. On a hosted forge, the timeline depends on its garbage collection, so act quickly.
Does git branch -d protect me? Jump to heading
Lower-case -d refuses to delete a branch that is not merged into its upstream or HEAD. Upper-case -D deletes regardless. Making -d your habit avoids most accidental losses.
Can I recover a branch someone else deleted from their own machine? Jump to heading
Only if it was pushed or shared somewhere. Unpushed commits exist only in that person’s repository; they need to run the recovery steps themselves.
Related Jump to heading
- History Rewriting & Recovery — the parent topic.
- Recovering Lost Commits with git reflog — reflog techniques in depth.
- Recovering from an Accidental Force-Push — when the branch still exists but lost commits.
- Deleting Merged Branches Automatically — automation that deletes safely.