Remove tracking branches no longer on remote

git remote prune origin prunes tracking branches not on the remote.

git branch --merged lists branches that have been merged into the current branch.

xargs git branch -d deletes branches listed on standard input.

Be careful deleting branches listed by git branch --merged. The list could include master or other branches you'd prefer not to delete.

To give yourself the opportunity to edit the list before deleting branches, you could do the following in one line:

git branch --merged >/tmp/merged-branches && \
  vi /tmp/merged-branches && xargs git branch -d </tmp/merged-branches

Most of these answers do not actually answer the original question. I did a bunch of digging and this was the cleanest solution I found. Here is a slightly more thorough version of that answer:

  1. Check out your default branch. Usually git checkout master
  2. Run git fetch -p && git branch -vv | awk '/: gone]/{print $1}' | xargs git branch -d

Explanation:

Works by pruning your tracking branches then deleting the local ones that show they are "gone" in git branch -vv.

Notes:

If your language is set to something other than English you will need to change gone to the appropriate word. Branches that are local only will not be touched. Branches that have been deleted on remote but were not merged will show a notification but not be deleted on local. If you want to delete those as well change -d to -D.


The safest way to do this is to use the "plumbing" command git for-each-ref with the interpolation variable %(upstream:track), which will be [gone] when the branch is no longer on the remote:

git fetch -p && for branch in $(git for-each-ref --format '%(refname) %(upstream:track)' refs/heads | awk '$2 == "[gone]" {sub("refs/heads/", "", $1); print $1}'); do git branch -D $branch; done

This approach is somewhat safer than using the "porcelain" command, because there is no risk of accidentally matching on part of the commit message. Here is a version using the "porcelain" git commands:

git fetch -p && for branch in $(git branch -vv | grep ': gone]' | awk '{print $1}'); do git branch -D $branch; done

The way this works is that after the command

git fetch -p

removes the remote references, when you run

git branch -vv

it will show 'gone' as the remote status. For example,

$ git branch -vv
  master                 b900de9 [origin/master: behind 4] Fixed bug
  release/v3.8           fdd2f4e [origin/release/v3.8: behind 2] Fixed bug
  release/v3.9           0d680d0 [origin/release/v3.9: behind 2] Updated comments
  bug/1234               57379e4 [origin/bug/1234: gone] Fixed bug

This is what the scripts iterate over.

Tags:

Git

Git Branch