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
Where a deleted branch's tip can be foundThe deletion message prints the hash immediately. The HEAD reflog records recent checkouts and commits. The remote-tracking reflog records the last fetched tip of a remote branch. The forge can restore branches deleted through pull requests, and any clone that still has the branch can push it back.from fastest to most effortDeletion message(was 8b3e4f2)HEAD reflogcheckouts and commitsorigin/<branch> refloglast fetched remote tipForge restore / other clonesserver-side or teammatesthe branch's own reflog is deleted with it — the others are not

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.

Which recovery path to tryIf you still have the deletion output, recreate the branch from the printed hash. If the branch was local, search the HEAD reflog. If it was remote, use the remote-tracking ref, the forge's pull request record, or a teammate's clone. If none of those work, search dangling commits.What do you still have?the deletion messageRecreate from hashgit branch name shaa local cloneReflogsHEAD or origin/nameonly the forgePR head SHAfetch + pushgit fsck for dangling commits is the last resort that usually still works

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.

How long a deleted branch stays recoverableWith default settings, commits from a deleted branch stay reachable through the HEAD reflog for up to ninety days if you had them checked out. After that they become unreachable objects, which garbage collection prunes once they are older than two weeks. Recovery gets harder at each stage.Deletedhash in the messageday 0HEAD refloggit reflog finds itdays 0–90Unreachablegit fsck finds itafter reflogPruned by gcgone locally+2 weeksthe defaults are generous locally; forges and CI clones are far less predictable
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.