Quick answer
A Git branch can exist in three places: your local branch, the branch on the remote server, and your local remote-tracking reference (origin/branch-name) that remembers what the remote looked like at your last fetch. Each command below cleans up one of them.
# 1. Delete the local branch (only if it is merged)
git branch -d feature/login
# 2. Delete the branch on the remote
git push origin --delete feature/login
# 3. Remove remote-tracking refs for branches deleted on the server
git fetch --pruneDelete a local branch: -d vs -D
git branch -d (short for --delete) is the safe version. Git only deletes the branch if its commits are already merged into its upstream branch, or into your current HEAD if it has no upstream. If the branch contains work that exists nowhere else, Git refuses with "error: the branch 'x' is not fully merged" and nothing is deleted.
git branch -D is shorthand for --delete --force. It deletes the branch regardless of merge status. Use it when you are certain the work is not needed: an abandoned experiment, a branch that was squash-merged or rebase-merged on GitHub (Git cannot see those as merged because the commit hashes changed), or a branch you already cherry-picked elsewhere.
You cannot delete the branch you are currently on. Switch to another branch first, usually main.
git switch main # or: git checkout main
git branch -d feature/login # safe delete
# error: the branch 'feature/login' is not fully merged.
git branch -D feature/login # force delete
# Deleted branch feature/login (was 4e1c2ab).
# Delete several branches at once
git branch -d fix/typo fix/navbar chore/depsTip
Copy the hash Git prints after "Deleted branch ... (was 4e1c2ab)". With it you can recreate the branch instantly: git branch feature/login 4e1c2ab.
Delete a remote branch
To delete the branch on GitHub, GitLab, Bitbucket or any other remote, push a delete instruction. The modern syntax is git push origin --delete branch-name. The older form git push origin :branch-name (pushing "nothing" to that name) does the same thing and still works; you will see it in older answers and scripts.
Deleting a remote branch affects everyone. Open pull requests from that branch are closed, and colleagues who still have it checked out keep their local copy but can no longer push to it. If the branch is protected, the server rejects the delete; remove the protection rule first if you really mean it.
git push origin --delete feature/login
# To github.com:acme/app.git
# - [deleted] feature/login
# Equivalent older syntax
git push origin :feature/login
# Delete local and remote in one go
git branch -d feature/login && git push origin --delete feature/loginNote
If you get "error: unable to delete 'x': remote ref does not exist", the branch was already deleted on the server (often by the pull request merge). Run git fetch --prune to clean up your stale origin/x reference.
Delete a branch on GitHub or GitLab
Both platforms let you delete branches from the browser, which is handy when you are not at your terminal.
- GitHub: open the repository, click the branch count (or go to
/branches), find the branch and click the trash icon. After merging a pull request, GitHub also shows a Delete branch button on the PR page. - GitHub automation: in Settings, General, enable "Automatically delete head branches" so every merged PR's branch is removed for you. The PR page keeps a Restore branch button.
- GitLab: go to Code, Branches, and click the delete icon next to the branch. The Delete merged branches button removes every merged, unprotected branch at once. Merge requests also have a "Delete source branch" checkbox.
- Deleting in the web UI only removes the remote branch. Your local branch and your
origin/...reference stay until you delete and prune them yourself.
Prune stale remote-tracking branches
When a teammate or GitHub deletes a remote branch, your clone still lists origin/feature/login in git branch -r until you prune. git fetch --prune (or -p) fetches and removes every remote-tracking reference whose branch no longer exists on the server. git remote prune origin does the pruning without fetching, and --dry-run shows what it would remove.
Pruning never touches your local branches. It only removes the cached origin/* references, so it is always safe. Most people turn it on permanently.
git fetch --prune
git remote prune origin --dry-run
# Prune automatically on every fetch and pull
git config --global fetch.prune trueDelete a branch in VS Code and Git GUIs
If you prefer not to type commands, most editors wrap the same operations. In VS Code, open the Command Palette (Ctrl+Shift+P, or Cmd+Shift+P on macOS) and run "Git: Delete Branch..." to remove a local branch; recent versions also offer "Git: Delete Remote Branch...". The Source Control view's branch list lets you do the same with a right-click. JetBrains IDEs list local and remote branches in the Git Branches popup, where Delete removes the local branch and the remote entry offers its own Delete option.
GitHub Desktop removes local branches from Branch, Delete, and asks whether to delete the remote branch as well. Whatever tool you use, it runs the same git branch -d, git branch -D or git push --delete underneath, so the same rules apply: you cannot delete the checked-out branch, unmerged work needs a forced delete, and the remote copy is a separate step.
Delete all merged branches at once
After a few months a repository can have dozens of finished local branches. git branch --merged main lists the ones whose commits are all contained in main. The one-liners below delete them with the safe -d flag, while skipping the current branch (marked *), branches checked out in other worktrees (marked +) and your long-lived branches. Run the listing part on its own first and read it before deleting anything.
macOS and Linux (bash or zsh)
git switch main && git pull
# Preview
git branch --merged main | grep -vE '^[*+]|^\s*(main|master|develop)$'
# Delete
git branch --merged main | grep -vE '^[*+]|^\s*(main|master|develop)$' | xargs -r git branch -dWindows (PowerShell)
git switch main; git pull
git branch --merged main |
ForEach-Object { $_.Trim() } |
Where-Object { $_ -notmatch '^[*+]' -and $_ -notin @('main', 'master', 'develop') } |
ForEach-Object { git branch -d $_ }Branches whose remote is gone
Squash-merged branches do not show up in --merged. A good proxy is "the remote branch was deleted": after git fetch --prune, git branch -vv marks those as [origin/x: gone]. Because they are not technically merged, this needs -D, so check the list carefully.
git fetch --prune
git branch -vv | grep ': gone]' # preview
git branch -vv | grep ': gone]' | awk '{print $1}' | xargs -r git branch -DWarning
The gone filter force-deletes branches. If you have local commits on such a branch that were never pushed, they will be removed. Review the preview output, and remember the reflog recovery steps below.
Recover a deleted branch
Deleting a branch only deletes a pointer; the commits stay in the repository until garbage collection removes unreachable objects, which by default does not happen for at least two weeks and usually much longer because of the reflog. If you still have the hash from the "Deleted branch" message, recreate it directly. Otherwise search the reflog for the last commit you made on that branch.
For a branch deleted on GitHub through a pull request, the quickest fix is the Restore branch button on the closed or merged PR page. If a colleague still has the branch locally, they can simply push it again.
# You know the hash
git branch feature/login 4e1c2ab
# You don't: look for it in the reflog
git reflog | grep -i 'feature/login'
git reflog --date=relative | head -30
git branch feature/login HEAD@{5}
git push -u origin feature/login # restore the remote copy tooDelete a branch: FAQ
Quick answers to common questions
What is the difference between git branch -d and -D?
-d deletes a branch only if it is fully merged, so you cannot lose unmerged commits by accident. -D is --delete --force and deletes the branch whatever its merge status.
Does deleting a local branch delete the remote branch?
No. Local and remote branches are deleted separately. Use git push origin --delete branch-name to remove the remote one, and git fetch --prune to clear stale origin/* references.
Why does Git say my branch is not fully merged when the PR was merged?
The pull request was probably squash-merged or rebase-merged, which creates new commits with different hashes. Git cannot match them to your branch, so use git branch -D once you have confirmed the changes are in main.
How do I delete a branch I am currently on?
You cannot. Switch to another branch first with git switch main, then run git branch -d on the old one.
Can I undo deleting a Git branch?
Yes, in most cases. Recreate it with git branch name <hash> using the hash Git printed when it deleted the branch, or find the last commit with git reflog. On GitHub, use Restore branch on the pull request.

