Git Course 0%

Remote branches and cleanup

Intermediate Git CLI VS Code UI IntelliJ UI GitLab UI GitHub UI ≈ 8 min

What you will learn

  • The three copies of a branch and which command removes which
  • Why deleted branches linger in git branch -a, and what prune does
  • How to check whether a branch is safe to delete

After this lesson you can

  • I can clean up after a merged branch without leaving debris on the remote or in my clone

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

Terminal
$ git push origin --delete docs/12-windows-install-steps
To https://gitlab.com/northwind-trails/trailguide.git
 - [deleted]         docs/12-windows-install-steps
Terminal
$ git branch -d docs/12-windows-install-steps
Deleted 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:

Terminal
$ git branch -d feature/21-difficulty-filter
error: 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. main has the change but not those commits, so Git cannot see the merge. -D is correct.
  • The branch was never merged. -D abandons the work. Check first.

The check is one command:

Terminal
$ git branch --merged
* main
Terminal
$ 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:

Terminal
$ git branch -r
  origin/HEAD -> origin/main
  origin/docs/40-temp
  origin/main

origin/docs/40-temp no longer exists on the server. Clearing it out:

Terminal
$ git fetch --prune
From https://gitlab.com/northwind-trails/trailguide
 - [deleted]         (none)     -> origin/docs/40-temp
Terminal
$ git branch -r
  origin/HEAD -> origin/main
  origin/main

Pruning 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:

Terminal
$ 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

Terminal
$ 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 --prune

Pull first so that --merged judges against the current main.

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.
  • -D without checking. Confirm with git branch --no-merged or by finding the change in main; on a squash-merged branch -D is right, on an abandoned one it discards work (recoverable for a while through the reflog).
  • git branch -a still 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 main first.

Try it yourself

Goal: delete all three copies of a branch and watch each disappear.

  1. Create docs/practice-cleanup from main, make one commit, push it with -u.
  2. Switch to main, merge the branch, and push main.
  3. Run git branch --merged; the practice branch should be listed.
  4. Delete it locally with -d, then on the remote with git push origin --delete docs/practice-cleanup.
  5. Run git branch -a and, 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.

Check yourself

1. git branch -a lists remotes/origin/old-feature, but the branch is gone from GitLab. What is it?
2. git branch -d refuses with "not fully merged" on a branch you know was merged through a squash. What should you do?
3. Which command removes the branch from GitLab or GitHub?

Key terms

Branch Remote-tracking branch origin Merge