Cleaning up old remote git branches

I work from two different computers (A and B) and store a common git remote in the dropbox directory.

Let's say I have two branches, master and devel. Both are tracking their remote counterparts origin/master and origin/devel.

Now while on computer A, I delete branch devel, on local and remote.

git push origin :heads/devel
git branch -d devel

Running git branch -a on computer A, I get the following list of branches.

  • master
  • origin/HEAD
  • origin/master

Running git fetch on computer B, I can remove the local devel branch with git branch -d devel, but I can't remove the remote devel branch.

git push origin :heads/devel returns the following error messages.

error: unable to push to unqualified destination: heads/proxy3d
The destination refspec neither matches an existing ref on the remote nor begins with refs/, and we are unable to guess a prefix based on the source ref.
fatal: The remote end hung up unexpectedly

git branch -a still lists origin/devel in the remote branches.

How can I clean up the remote branches from computer B?


First, what is the result of git branch -a on machine B?

Second, you have already deleted heads/devel on origin, so that's why you can't delete it from machine B.

Try

git branch -r -d origin/devel

or

git remote prune origin

or

git fetch origin --prune

and feel free to add --dry-run to the end of your git statement to see the result of running it without actually running it.

Docs for git remote prune and git branch.


Consider to run :

git fetch --prune

On a regular basis in each repo to remove local branches that have been tracking a remote branch that is deleted (no longer exists in remote GIT repo).

This can be further simplified by

git config remote.origin.prune true

this is a per-repo setting that will make any future git fetch or git pull to automatically prune.

To set this up for your user, you may also edit the global .gitconfig and add

[fetch]
    prune = true

However, it's recommended that this is done using the following command:

git config --global fetch.prune true

or to apply it system wide (not just for the user)

git config --system fetch.prune true

Here is bash script that can do it for you. It's modified version of http://snippets.freerobby.com/post/491644841/remove-merged-branches-in-git script. My modification enables it to support different remote locations.

#!/bin/bash

current_branch=$(git branch --no-color 2> /dev/null | sed -e '/^[^*]/d' -e 's/* \(.*\)/\1/')
if [ "$current_branch" != "master" ]; then
  echo "WARNING: You are on branch $current_branch, NOT master."
fi
echo -e "Fetching merged branches...\n"

git remote update --prune
remote_branches=$(git branch -r --merged | grep -v '/master$' | grep -v "/$current_branch$")
local_branches=$(git branch --merged | grep -v 'master$' | grep -v "$current_branch$")
if [ -z "$remote_branches" ] && [ -z "$local_branches" ]; then
  echo "No existing branches have been merged into $current_branch."
else
  echo "This will remove the following branches:"
  if [ -n "$remote_branches" ]; then
echo "$remote_branches"
  fi
  if [ -n "$local_branches" ]; then
echo "$local_branches"
  fi
  read -p "Continue? (y/n): " -n 1 choice
  echo
  if [ "$choice" == "y" ] || [ "$choice" == "Y" ]; then
    remotes=`echo "$remote_branches" | sed 's/\(.*\)\/\(.*\)/\1/g' | sort -u`
# Remove remote branches
for remote in $remotes
do
        branches=`echo "$remote_branches" | grep "$remote/" | sed 's/\(.*\)\/\(.*\)/:\2 /g' | tr -d '\n'`
        git push $remote $branches 
done

# Remove local branches
git branch -d `git branch --merged | grep -v 'master$' | grep -v "$current_branch$" | sed 's/origin\///g' | tr -d '\n'`
  else
echo "No branches removed."
  fi
fi

This command will "dry run" delete all remote (origin) merged branches, apart from master. You can change that, or, add additional branches after master: grep -v for-example-your-branch-here |

git branch -r --merged | 
  grep origin | 
  grep -v '>' | 
  grep -v master | 
  xargs -L1 | 
  awk '{sub(/origin\//,"");print}'| 
  xargs git push origin --delete --dry-run

If it looks good, remove the --dry-run. Additionally, you may like to test this on a fork first.


I'll have to add an answer here, because the other answers are either not covering my case or are needlessly complicated. I use github with other developers and I just want all the local branches whose remotes were (possibly merged and) deleted from a github PR to be deleted in one go from my machine. No, things like git branch -r --merged don't cover the branches that were not merged locally, or the ones that were not merged at all (abandoned) etc, so a different solution is needed.

Anyway, the first step I got it from other answers:

git fetch --prune

A dry run of git remote prune origin seemed like it would do the same thing in my case, so I went with the shortest version to keep it simple.

Now, a git branch -v should mark the branches whose remotes are deleted as [gone]. Therefore, all I need to do is:

git branch -v|grep \\[gone\\]|awk '{print $1}'|xargs -I{} git branch -D {}

As simple as that, it deletes everything I want for the above scenario.

The less common xargs syntax is so that it also works on Mac & BSD in addition to Linux. Careful, this command is not a dry run so it will force-delete all the branches marked as [gone]. Obviously, this being git nothing is gone forever, if you see branches deleted that you remember you wanted kept you can always undelete them (the above command will have listed their hash on deletion, so a simple git checkout -b <branch> <hash>.

Edit: Just add this alias to your .bashrc/.bash_profile, the two commands made into one and I updated the second to work on all shells:

alias old_branch_delete='git fetch -p && git branch -vv | awk "/: gone]/{print \$1}" | xargs git branch -D'