As your Git repository grows, you'll accumulate branches from completed features, merged pull requests, and abandoned experiments. Knowing how to properly clean up these branches is essential for maintaining a tidy repository. In this guide, you'll learn the three levels of branch deletion in Git.
What You'll Learn: In this comprehensive guide, you'll master:
- Understanding the three types of branch references in Git
- Safely deleting local branches with
git branch -dand-D - Removing remote-tracking branches with
git branch -dr - Deleting branches from remote repositories (GitHub)
- The correct order of operations for complete branch cleanup
- Common pitfalls and how to avoid them
Understanding Git's Three Branch Locations
Before deleting branches, you need to understand that a "branch" can exist in three different places:
+------------------+ +----------------------+ +------------------+
| LOCAL BRANCH | | REMOTE-TRACKING REF | | REMOTE BRANCH |
| | | | | |
| Your computer | | Your computer | | GitHub/ |
| (working copy) | | (cache of remote) | | GitLab |
+------------------+ +----------------------+ +------------------+
| | |
git branch git branch -r git ls-remote
(shows these) (shows these) (shows these)
What Each Location Means
| Location | Description | Example | Command to View |
|---|---|---|---|
| Local Branch | Branch you work on directly | master, dev, feature-x | git branch |
| Remote-Tracking | Local cache of remote state | origin/master, hello/dev | git branch -r |
| Remote Branch | Actual branch on GitHub/GitLab | Lives on the server | git ls-remote |
Important: Deleting a local branch does NOT delete the remote branch, and vice versa. You must delete each separately!
Step 1: Deleting a Local Branch
Let's start with deleting a local branch. First, check your current branches:
git branch
Output:
dev
master
* newtest
The * indicates you're currently on the newtest branch.
Switch Away From the Branch First
You cannot delete the branch you're currently on. Switch to another branch first:
git checkout master
Output:
Switched to branch 'master'
Your branch is up to date with 'hello/master'.
Delete the Local Branch
Now delete the local branch with -d (safe delete):
git branch -d newtest
Output:
warning: deleting branch 'newtest' that has been merged to
'refs/remotes/hello/newtest', but not yet merged to HEAD
Deleted branch newtest (was 6d3aac9).
Understanding the Warning
Git warns you when the branch hasn't been merged to your current branch (HEAD). This is a safety feature!
Before deletion:
master ----*----*----* (HEAD)
newtest ---*----*----* (has commits not in master)
└── 6d3aac9
After deletion:
master ----*----*----* (HEAD)
newtest [DELETED locally]
(but still exists on remote!)
Verify the Deletion
git branch
Output:
dev
* master
The newtest branch is gone locally!
Step 2: Deleting the Remote-Tracking Reference
Even after deleting the local branch, Git still remembers the remote branch exists. This is the "remote-tracking reference":
git branch -r
You might still see hello/newtest in the list. To remove this cached reference:
git branch -dr hello/newtest
Output:
Deleted remote-tracking branch hello/newtest (was 6d3aac9).
What Just Happened?
Before git branch -dr:
Your Computer GitHub
+------------------+ +------------------+
| master (local) | | master |
| [newtest deleted]| | newtest <------- Still here!
| hello/newtest | <-- cache | |
+------------------+ +------------------+
After git branch -dr:
Your Computer GitHub
+------------------+ +------------------+
| master (local) | | master |
| [newtest deleted]| | newtest <------- Still here!
| [cache cleared] | | |
+------------------+ +------------------+
Note: The -dr flag combines -d (delete) with -r (remote-tracking). This only removes the local cache - the branch still exists on GitHub!
The Cache Comes Back!
If you run git pull or git fetch, Git will recreate the remote-tracking reference:
git pull
Output:
From https://github.com/owais-io/secondproject
* [new branch] newtest -> hello/newtest
Already up to date.
The remote-tracking branch is back because the actual branch still exists on GitHub!
Step 3: Deleting the Remote Branch (GitHub)
To permanently remove the branch from the remote repository, use:
git push hello --delete newtest
Output:
To https://github.com/owais-io/secondproject.git
- [deleted] newtest
Alternative Syntax
You can also use this older syntax (pushes "nothing" to the remote branch):
git push hello :newtest
Now It's Truly Gone
After git push --delete:
Your Computer GitHub
+------------------+ +------------------+
| master (local) | | master |
| [newtest deleted]| | [newtest GONE] |
| [cache cleared] | | |
+------------------+ +------------------+
Complete Cleanup Workflow
Here's the recommended order for completely removing a branch:
Step 1: Switch to a different branch
git checkout master
Step 2: Delete local branch
git branch -d branchname
Step 3: Delete remote branch (GitHub)
git push origin --delete branchname
Step 4: (Optional) Clean up stale remote-tracking refs
git fetch --prune
The --prune Shortcut
Instead of manually deleting remote-tracking references, use git fetch --prune:
git fetch --prune
This automatically removes any remote-tracking references for branches that no longer exist on the remote.
You can also configure Git to always prune during fetch:
git config --global fetch.prune true
Force Deletion with -D
If Git refuses to delete a branch (unmerged changes), you can force it:
# Safe delete (checks if merged)
git branch -d feature-branch
# Force delete (ignores merge status)
git branch -D feature-branch
Danger: Using -D can result in lost work! Only use it when you're certain you don't need the unmerged commits.
Quick Reference
| Task | Command |
|---|---|
| List local branches | git branch |
| List remote-tracking branches | git branch -r |
| List all branches | git branch -a |
| Delete local branch (safe) | git branch -d <branch> |
| Delete local branch (force) | git branch -D <branch> |
| Delete remote-tracking ref | git branch -dr <remote>/<branch> |
| Delete remote branch | git push <remote> --delete <branch> |
| Prune stale references | git fetch --prune |
Common Mistakes to Avoid
Mistake 1: Thinking Local Delete Affects Remote
git branch -d feature-x # Only deletes locally!
# The branch still exists on GitHub
Mistake 2: Deleting Remote-Tracking Instead of Remote
git branch -dr origin/feature-x # Only clears local cache!
# The branch still exists on GitHub
# git fetch will bring it back
Mistake 3: Trying to Delete Current Branch
git branch -d master # Error if you're on master!
# Switch to another branch first
Practice Exercise
Try this cleanup workflow on a test repository:
- Create a new branch:
git branch test-cleanup - Push it to remote:
git push origin test-cleanup - Verify it exists everywhere:
git branch(local)git branch -r(remote-tracking)- Check GitHub (remote)
- Delete in correct order:
git branch -d test-cleanupgit push origin --delete test-cleanup
- Verify complete removal with
git branch -a
Summary
Cleaning up Git branches requires understanding where branches live:
- Local branches: Delete with
git branch -d - Remote branches: Delete with
git push origin --delete - Remote-tracking refs: Auto-cleanup with
git fetch --prune
Always delete in order: local first, then remote, and use --prune to keep your repository tidy!

