Last active
March 24, 2025 13:55
-
-
Save philiprenich/b62cb7f68c2fd4a966a9eaade1c1ef48 to your computer and use it in GitHub Desktop.
Script to remove git branches without an upstream (removed or non-existant). Corresponding blog post: https://www.philiprenich.com/blog/delete-git-branches-with-no-remote-tracking-branch/
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/bin/bash | |
while [[ $# -gt 0 ]]; do | |
case $1 in | |
-h|--help) | |
echo "This script lists Git branches whose upstream tracking branches no longer exist (are \"[gone]\") and that have no upstream tracking branch." | |
echo "It will ask for confirmation to delete branches from each group." | |
echo "While the script can live anywhere, it will work on the current working directory's Git repository." | |
echo "" | |
exit 0 | |
;; | |
esac | |
done | |
echo "Fetching and pruning..." | |
git fetch --prune | |
echo "" | |
echo "Branches with a \"[gone]\" upstream branch:" | |
echo "-----" | |
git for-each-ref --format '%(refname:short) %(upstream:track)' refs/heads/ | awk '$2 == "[gone]" {print $1}' | |
GONE=$(git for-each-ref --format '%(refname:short) %(upstream:track)' refs/heads/ | awk '$2 == "[gone]"' | wc -l) | |
echo "" | |
echo "Branches not tracking an upstream branch:" | |
echo "-----" | |
git for-each-ref --format '%(refname:short) %(upstream)' refs/heads/ | awk '$2 == "" {print $1}' | |
NONTRACKING=$(git for-each-ref --format '%(refname:short) %(upstream)' refs/heads/ | awk '$2 == ""' | wc -l) | |
echo "" | |
if (( $GONE )); then | |
read -p "Delete [gone] branches? (y/n) " REMOVE_GONE | |
fi | |
if (( $NONTRACKING )); then | |
read -p "Delete branches w/out tracking? (y/n) " REMOVE_LOCAL | |
fi | |
echo "" | |
if [ "$REMOVE_GONE" == 'y' ]; then | |
git for-each-ref --format '%(refname:short) %(upstream:track)' refs/heads/ | awk '$2 == "[gone]" {print $1}' | xargs -r git branch -D | |
elif (( $GONE )); then | |
echo "Skipping \"[gone]\" branches" | |
echo "" | |
fi | |
if [ "$REMOVE_LOCAL" == 'y' ]; then | |
git for-each-ref --format '%(refname:short) %(upstream)' refs/heads/ | awk '$2 == "" {print $1}' | xargs -r git branch -D | |
elif (( $NONTRACKING )); then | |
echo "Skipping branches w/out tracking" | |
fi | |
echo "" | |
echo "Done." |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Update notes: improved output verbosity based on data