One of Git’s strengths is its implementation of branches. They are extremely cheap to create, move and destroy and we should therefore try to leverage this power and encapsulate work in different branches. But sometimes local branches clutter up and you just want to delete all of them except master (you can always create new ones matching a branch in the remote repository). Automating this is a perfect bash exercise! Here is what I came up with:
Running this command inside a Git repository will delete all local branches except the one you are currently on. I wrote this as a pipeline to make it a single line:
Pipes: The character “|” pipes output of the command to the left as input to the command on the right. This gives bash a somewhat functional twist.
xargs: On its own, git branch -D does not read branch names from input but takes them as arguments. That means we cannot use it in pipes, because it will receive no arguments but input. The necessary conversion from input to arguments is exactly what xargs 1 does. It invokes a given program (here git branch -D) with standard input as arguments.
First git branch creates a list of all local branches, then grep 2 is used to filter branches. The -v option negates the filter which means the resulting list contains all branch names not matching the given pattern. The pattern is given as result of git rev-parse –abbrev-ref HEAD which returns the name of the current branch (Improvements to this step in the next paragraph). In the last pipeline stage git branch -D is invoked for all branches in the filtered list which means all branches except the current one will be deleted.
Improved version based on feedback
Some nice people added valuable feedback on dev.to3 and on GitHub4,
suggesting that the filter with grep can be simplified to
grep -v "^*".
Thank you! This works because Git automatically prepends an asterisk to the current branch when listing all branches.
And an asterisk is not allowed as first character for a branch name,
so this filter is exactly what we need.
Besides being simpler and cleaner it is also more accurate:
Currently the command does not delete branches which contain the name of the current branch as a part of their name.
If this is an issue you should probably level up your branch naming game,
but it is nice edge case thinking!
The better version therefore is:
If you have suggestions for further improvement or run into any issues its probably best to comment on the GitHub gist directly.