--- /dev/null
+#!/bin/bash
+
+set -eu
+
+function usage {
+ echo "Usage: $0 [--remote origin] [--age ndays]"
+ echo
+ echo "This tool will not change your repository, the output is a list of git push commands you can use to delete old branches."
+ echo
+ echo "Note that the arguments must be passed in the order listed above."
+ exit 1
+}
+
+if [ "${1:-}" = "--help" ]; then
+ usage
+fi
+
+remote="origin"
+if [ "${1:-}" = "--remote" ]; then
+ remote="$2"
+ shift
+ shift
+fi
+
+age_days=30
+if [ "${1:-}" = "--age" ]; then
+ age_days="$2"
+ shift
+ shift
+fi
+age_seconds=$((age_days*24*3600))
+
+if [ -n "${1:-}" ]; then
+ usage
+fi
+
+
+echo "## Fetching latest changes from $remote"
+git fetch -p "${remote}"
+
+
+echo "## Constructing list of revisions in master and tags"
+safe_revs_file="$(mktemp -t gitcleanup.XXXXXX)"
+git rev-list origin/master --tags > "$safe_revs_file"
+
+
+echo "## Checking for branches to delete"
+now="$(date +%s)"
+git ls-remote --heads "$remote" | while read line; do
+ set $line
+ rev="$1"
+ branch="$2"
+ timestamp="$(git rev-list --format=format:'%ct' --max-count=1 "$rev"|tail -n1)"
+ age=$((now-timestamp))
+
+ if [ "$branch" = "refs/heads/master" ]; then
+ continue;
+ fi
+
+ if grep -q "$rev" "$safe_revs_file"; then
+ echo git push "$remote" ":$branch" "# remove merged into master or tag"
+ continue
+ fi
+
+ if [ "$age" -gt "$age_seconds" ]; then
+ branch_name="${branch##refs/heads/}"
+ echo git tag "archived/$branch_name" "$rev" "# create tag for older than $age_days days branch"
+ echo git push "$remote" tag "archived/$branch_name" "# push tag for older than $age_days days branch"
+ echo git push "$remote" ":$branch" "# remove older than $age_days days"
+ continue
+ fi
+done
+
+rm -f "$safe_revs_file"
+