Skip to content

Instantly share code, notes, and snippets.

@jbcpollak
Forked from gparlakov/delete-stale-branches.sh
Last active January 24, 2022 18:29
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save jbcpollak/089d449a5418b7b08cba679507e1a582 to your computer and use it in GitHub Desktop.
Save jbcpollak/089d449a5418b7b08cba679507e1a582 to your computer and use it in GitHub Desktop.
Delete Stale Branches
#!/usr/bin/env bash
while getopts "d" opt; do
case $opt in
d) dryRunOpt="--dry-run";;
esac
done
UPSTREAM=origin
BASE=main
UPSTREAM_BASE="$UPSTREAM/$BASE"
STALE_AGE="365 days"
REVIEW_AGE="180 days"
# prune local "cache" of remote branches first:
git fetch --prune $UPSTREAM
# delete merged to $UPSTREAM_BASE branches:
mergedBranches=$(git branch -r --merged $UPSTREAM_BASE | grep "^ $UPSTREAM/" | cut -d/ -f2- | grep -v -e "^$BASE$" -e "^HEAD -> $UPSTREAM_BASE$")
if [ -n "${mergedBranches}" ]; then
echo -e "\033[0;32mDeleting merged branches...\033[0m"
git push $dryRunOpt --delete $UPSTREAM ${mergedBranches}
fi
# delete branches with last (cherry picked) commit older than $STALE_AGE:
echo -e "\033[0;32mSearching for stale branches (older than $STALE_AGE)...\033[0m"
staleTimestamp=$(date -d "now - $STALE_AGE" +"%s")
maybeStaleTimestamp=$(date -d "now - $REVIEW_AGE" +"%s")
notMergedBranches=$(git branch -r --no-merged $UPSTREAM_BASE | grep "^ $UPSTREAM/")
branchesToDelete=""
branchesToReview=""
for branch in ${notMergedBranches}; do
lastCommitInfo=$(git cherry $UPSTREAM_BASE ${branch} | grep -v "^-" | cut -d" " -f2 | xargs git show --format="%H|%ct|%cr|%an" --quiet | grep -v "^$(git rev-parse HEAD)" | tail -1)
lastCommitTimestamp=$(echo "${lastCommitInfo}" | cut -d"|" -f2)
# use this logic because lastCommitTimestamp can be null
if [[ ! -z "${lastCommitTimestamp}" ]] && [[ ${lastCommitTimestamp} -lt ${staleTimestamp} ]]; then
branchesToDelete+=" ${branch#$UPSTREAM/}"
elif [[ ${lastCommitTimestamp} -lt ${maybeStaleTimestamp} ]]; then
branchesToReview+="${branch#$UPSTREAM/}|${lastCommitInfo}"$'\n'
fi
echo -n .
done
echo # for new line after dots
if [[ -n "${branchesToDelete}" ]]; then
echo -e "\033[0;32mDeleting stale branches...\033[0m"
git push $dryRunOpt --delete $UPSTREAM ${branchesToDelete}
else
echo -e "\033[0;32mNo stale branches...\033[0m"
fi
echo -e "\033[1;33mBranches to review (older than $REVIEW_AGE and may be stale):\033[0m"
echo "${branchesToReview}" | sort -t"|" -k5 | awk -F"|" 'NF {print $5 " changed branch \"" $1 "\" in project \"'${PWD##*/}'\" " $4}'
@jbcpollak
Copy link
Author

This revision makes it easier to change the upstream and base branch names, as well as the stale and review ages. Logging is improved and the possibility of deleting a branch with null commit timestamp is avoided.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment