Skip to content

Instantly share code, notes, and snippets.

@kikuchi-m
Last active October 8, 2021 02:39
Show Gist options
  • Select an option

  • Save kikuchi-m/55028305055a3637d1ab711cece988f9 to your computer and use it in GitHub Desktop.

Select an option

Save kikuchi-m/55028305055a3637d1ab711cece988f9 to your computer and use it in GitHub Desktop.
#!/bin/bash
set -e
USAGE="usage: git delete-merged-branches
[(-r|--remote) <remote-name>]
[(-b|--branch) <merge-base>]
[(-s|--older-than) <date>]
[--local-only] [--yes] [-n|--dry-run]"
for (( i = 1; i < $(($#+1)); ++i )); do
# echo "(option ${@:$i:1})"
case "${@:$i:1}" in
-r|--remote)
REMOTE="${@:$((++i)):1}"
;;
-b|--branch)
BASE="${@:$((++i)):1}"
;;
-s|--older-than)
OLDER_THAN="${@:$((++i)):1}"
;;
--local-only)
LOCAL_ONLY=1
;;
--yes)
CONTINUE=yes
;;
-n|--dry-run)
DRY_RUN=-n
;;
-h|--help)
cat <<< $USAGE
exit 0
;;
*)
echo "unknown option ${@:$i:1}">&2
echo $USAGE>&2
exit 1
;;
esac
done
# REMOTE: remote name
if [ ! $LOCAL_ONLY ]; then
if [ -z "$REMOTE" ]; then
REMOTE=origin
read -p "remote ($REMOTE): " REMOTE
fi
if [ -z "$REMOTE" ]; then
REMOTE=origin
else
if [ ! $(git remote | grep -e "^$REMOTE\$") ]; then
echo "not found: $REMOTE"
exit 1
fi
fi
fi
# BASE: base branch/commit
if [ -z "$BASE" ]; then
if [ -z "$REMOTE" ]; then
BASE=master
else
BASE=$REMOTE/master
fi
read -p "base ($BASE): " BASE
fi
if [ -z "$BASE" ]; then
if [ -z "$REMOTE" ]; then
BASE=master
else
BASE=$REMOTE/master
fi
elif [[ $BASE =~ ^HEAD ]]; then
BASE=$(git rev-parse $BASE)
elif [ -z $(git branch --all --list $BASE) ]; then
echo "branch not found: $BASE"
exit 1
fi
# OLDER_THAN: to remove branch older than
if [ -z "$OLDER_THAN" ]; then
OLDER_THAN="4 months ago"
read -p "older than ($OLDER_THAN): " OLDER_THAN
fi
if [ -z "$OLDER_THAN" ]; then
OLDER_THAN="4 months ago"
fi
if [ ! "$LOCAL_ONLY" -o -n "$REMOTE" ]; then
REMOTE_REF=refs/remotes/$REMOTE/
fi
REFS=$(git for-each-ref \
--format="%(refname:short)" \
--sort=committerdate \
--merged $BASE \
$REMOTE_REF refs/heads/)
REFS=$(cat <<< $REFS | grep -v "$BASE" | grep -v "$REMOTE/master" | grep -v HEAD)
LOGFMT="%C(red)%h%Creset %C(cyan)%ci%Creset %C(green)(<branch>)%Creset %C(yellow)%cn%Creset %s"
TARGETS=
for BRANCH in $REFS; do
P=$(sed "s|<branch>|$BRANCH|" <(echo "$LOGFMT"))
if [ -n "$(git log -1 --oneline --since="$OLDER_THAN" $BRANCH)" ]; then
git log -1 --pretty="remaining: $P" $BRANCH
else
git log -1 --pretty="deleting: $P" $BRANCH
TARGETS="$TARGETS
$BRANCH"
fi
done
if [ -z "$TARGETS" ]; then
echo no branch to delete
exit 0
fi
if [ -z "$DRY_RUN" -a "$CONTINUE" != "yes" ]; then
echo "delete branches..."
read -p "continue? (yes/No): " CONTINUE
fi
CONTINUE=$(echo $CONTINUE | tr '[:upper:]' '[:lower:]')
if [ -z "$DRY_RUN" -a "$CONTINUE" == yes ]; then
echo continue...
for BRANCH in $TARGETS; do
if [ -n "$REMOTE" ]; then
if [[ "$BRANCH" =~ ^$REMOTE ]]; then
git push $DRY_RUN $REMOTE :$(echo $BRANCH | sed "s/$REMOTE\///")
continue
fi
fi
if [ -n "$DRY_RUN" ]; then
echo git branch -D $BRANCH
else
git branch -D $BRANCH
fi
done
fi
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment