gitgit-branch

How to prune local tracking branches that do not exist on remote anymore?


With git remote prune origin I can remove the local branches that are not on the remote any more.

But I also want to remove local branches that were created from those remote branches (a check if they are unmerged would be nice).

How can I do this?


Solution

  • After pruning, you can get the list of remote branches with git branch -r. The list of branches with their remote tracking branch can be retrieved with git branch -vv. So using these two lists you can find the remote tracking branches that are not in the list of remotes.

    This line should do the trick (requires bash or zsh, won't work with standard Bourne shell):

    git fetch -p ; git branch -r | awk '{print $1}' | egrep -v -f /dev/fd/0 <(git branch -vv | grep origin) | awk '{print $1}' | xargs git branch -d
    

    This string gets the list of remote branches and passes it into egrep through the standard input. And filters the branches that have a remote tracking branch (using git branch -vv and filtering for those that have origin) then getting the first column of that output which will be the branch name. Finally passing all the branch names into the delete branch command.

    Since it is using the -d option, it will not delete branches that have not been merged into the branch that you are on when you run this command.


    If you would like to have this as an alias, add these lines to your .bashrc file:

    alias git-list-untracked='git fetch --prune && git branch -r | awk "{print \$1}" | egrep -v -f /dev/fd/0 <(git branch -vv | grep origin) | awk "{print \$1}"'
    alias git-remove-untracked='git fetch --prune && git branch -r | awk "{print \$1}" | egrep -v -f /dev/fd/0 <(git branch -vv | grep origin) | awk "{print \$1}" | xargs git branch -d'
    

    Then, the procedure for pruning becomes:

    git remote prune --dry-run origin
    git remote prune origin # Removes origin/asdf that's no longer on origin
    git-list-untracked 
    git-remove-untracked # removes asdf [origin/asdf] where [origin/asdf] no longer exists (after previous command)
    

    If you use squash merges, replace -d with -D. But note that this means that git is not checking whether the branch has been merged before deleting it.