Remote branches and cleanup
Intermediate Git CLI VS Code UI IntelliJ UI GitLab UI GitHub UI
Why this matters
A branch that has been merged has done its job. Left in place, it joins the hundreds of others in the branch dropdown, and nobody can tell which are alive. Cleaning up is three seconds of work, but it involves three separate copies of the same branch, and knowing which command removes which is what stops people from either leaving debris or deleting something they still needed.
Three copies of one branch
After you publish a branch, the name exists in three places (lesson 6.4):
| Copy | Where | Removed by |
|---|---|---|
| Your local branch | .git/refs/heads/ on your computer |
git branch -d <name> |
| The remote branch | on GitLab or GitHub | git push origin --delete <name> |
Your remote-tracking bookmark origin/<name> |
.git/refs/remotes/ on your computer |
git fetch --prune |
Deleting one does not touch the others, which is exactly why branch lists fill up with names that no longer exist anywhere real.
Deleting after a merge
$ git push origin --delete docs/12-windows-install-stepsTo https://gitlab.com/northwind-trails/trailguide.git
- [deleted] docs/12-windows-install-steps$ git branch -d docs/12-windows-install-stepsDeleted branch docs/12-windows-install-steps (was 5f181fc).Both GitLab and GitHub can do the remote half for you: a merge request has a Delete source branch checkbox, ticked by default on most projects, so in practice you often only run the local delete.
The safe delete refuses when the commits are not in another branch:
$ git branch -d feature/21-difficulty-filtererror: the branch 'feature/21-difficulty-filter' is not fully merged
hint: If you are sure you want to delete it, run 'git branch -D feature/21-difficulty-filter'
hint: Disable this message with "git config set advice.forceDeleteBranch false"Two situations produce this, and they need opposite responses:
- The branch was squash-merged.
mainhas the change but not those commits, so Git cannot see the merge.-Dis correct. - The branch was never merged.
-Dabandons the work. Check first.
The check is one command:
$ git branch --merged* main$ git branch --no-merged fix/15-empty-distance--merged lists branches whose commits are already in the branch you are on, so they are safe to delete; --no-merged lists the rest. Run them from main after pulling.
Stale bookmarks
Colleagues merge and delete their branches all day. Your clone keeps the bookmarks until you tell it otherwise:
$ git branch -r origin/HEAD -> origin/main
origin/docs/40-temp
origin/mainorigin/docs/40-temp no longer exists on the server. Clearing it out:
$ git fetch --pruneFrom https://gitlab.com/northwind-trails/trailguide
- [deleted] (none) -> origin/docs/40-temp$ git branch -r origin/HEAD -> origin/main
origin/mainPruning only removes bookmarks for branches that are gone from the remote; it never touches your local branches or any commit. Set fetch.prune true once (lesson 3.5) and every fetch and pull cleans up by itself.
To see the whole picture at once, including which branches are stale:
$ git remote show origin* remote origin
Fetch URL: https://gitlab.com/northwind-trails/trailguide.git
Push URL: https://gitlab.com/northwind-trails/trailguide.git
HEAD branch: main
Remote branch:
main tracked
Local branch configured for 'git pull':
main merges with remote main
Local ref configured for 'git push':
main pushes to main (up to date)How to do it
$ git switch main && git pull
$ git branch --merged
$ git branch -d docs/12-windows-install-steps
$ git push origin --delete docs/12-windows-install-steps
$ git fetch --prunePull first so that --merged judges against the current main.
- Command Palette (Ctrl+Shift+P / ⇧⌘P) → Git: Delete Branch… removes a local branch; VS Code warns when it is unmerged.
- Git: Fetch (Prune) clears the stale
origin/…entries. - Deleting the remote branch: use the merge request checkbox, or the terminal. VS Code has no built-in menu entry for
push origin --delete.
- Open the branches popup (status bar, bottom right). Point at a local branch → Delete. IntelliJ shows a notification with an Undo link for a while afterwards, which is a genuine safety net.
- Point at a remote branch under Remote → Delete removes it on the server.
- Git → Fetch prunes automatically when
fetch.pruneis set; otherwise use the terminal.
Code → Branches lists every branch with its ahead/behind counts against main and separates Active from Stale (no commits for three months). The bin icon deletes one; Delete merged branches at the top removes every branch already merged into the default branch, which is the safest bulk cleanup available.
On a merge request, Delete source branch is a checkbox next to the Merge button and is usually ticked by default.
The Branches page (click the branch count on the repository home) lists branches with ahead/behind counts and a bin icon, and offers Delete for merged ones. A deleted branch shows a Restore button for a while, which is worth knowing before you panic.
On a pull request, a Delete branch button appears after merging; repositories can be set to delete the branch automatically in Settings → General → Automatically delete head branches.
Common mistakes
- Deleting the local branch and leaving the remote one. The name stays in everyone's dropdown forever. Use the merge request checkbox or
git push origin --delete. -Dwithout checking. Confirm withgit branch --no-mergedor by finding the change inmain; on a squash-merged branch-Dis right, on an abandoned one it discards work (recoverable for a while through the reflog).git branch -astill listing a colleague's deleted branch. That is a stale bookmark, not a branch. Prune.- Trying to delete the branch you are on. Git refuses; switch to
mainfirst.
Try it yourself
Goal: delete all three copies of a branch and watch each disappear.
- Create
docs/practice-cleanupfrommain, make one commit, push it with-u. - Switch to
main, merge the branch, and pushmain. - Run
git branch --merged; the practice branch should be listed. - Delete it locally with
-d, then on the remote withgit push origin --delete docs/practice-cleanup. - Run
git branch -aand, if the bookmark is still there,git fetch --prune.
Expected result: step 3 lists the branch as merged; step 4 prints "Deleted branch …" and "- [deleted]"; after step 5 no trace of the name remains in git branch -a.
Show solution
If git branch -a still shows remotes/origin/docs/practice-cleanup after step 4, that is the bookmark, and pruning removes it. If your fetch.prune is set from lesson 3.5, the bookmark disappeared on its own during the next fetch and step 5 prints nothing, which is the point of that setting.