Monday, May 22, 2023

Bash script to delete merged local git branches

When using git, overtime, your local copies of branches can grow and become burdensome to search through.  While you could manually delete 'old' branches, some of those branches may still be active eg not merged in yet.  It would be nice to have a bash script which would find merged branches older than N days and delete them.

First, list branches merged
> git branch --merged
# https://git-scm.com/docs/git

Then ensure to exclude your main branches: master, main, development
> git branch --merged | grep -v -E "\\*|\bmaster\b|\bmain\b|\bdevelopment\b"
# -v, --invert-match        select non-matching lines
# -E, --extended-regexp  \b word boundaries

Then to loop over those branches, use xargs to split the prior results
for k in $(git branch --merged | grep -v -E "\\*|\bmaster\b|\bmain\b|\bdevelopment\b" | xargs -r -n 1); do 
# xargs - build and execute command lines from standard input
# -n max-args, --max-args=max-args; exit if greater
# -r, --no-run-if-empty; do not run if no results

Then for each branch, see if it has commits greater than N days ago
> git log -1 --since="$days days ago" -s $k
# git log, one line, since $days days ago, for branch $k

If so, then delete the branch
> git branch -d $k


Full script below, with a confirmation prompt
#!/bin/bash

# delete merged local branches
days=90
found=0

# preview
# git branch --merged | grep -v -E "\\*|\bmaster\b|\bmain\b|\bdevelopment\b" | xargs -r -n 1

# list branches merged
# git branch --merged
# https://git-scm.com/docs/git-branch

# exclude master, main, development
# grep -v -E "\\*|\bmaster\b|\bmain\b|\bdevelopment\b"
# -v, --invert-match        select non-matching lines
# -E, --extended-regexp     \b word boundaries
# https://www.man7.org/linux/man-pages/man1/grep.1.html

# xargs -r -n 1
# -n max-args, --max-args=max-args; exit if greater
# -r, --no-run-if-empty; do not run if no results
# https://www.man7.org/linux/man-pages/man1/xargs.1.html

# git log -1 --since="$days days ago" -s $k
# gti log, one line, since $days days ago, for branch $k
# https://www.git-scm.com/docs/git-log

# delete branch
# git branch -d $k
# https://git-scm.com/docs/git-branch

echo "branches older than $days days:"
for k in $(git branch --merged | grep -v -E "\\*|\bmaster\b|\bmain\b|\bdevelopment\b" | xargs -r -n 1); do
  if [[ ! $(git log -1 --since="$days days ago" -s $k) ]]; then
    echo $k
    (( found++ ))
  fi
done

if [[ $found -eq 0 ]]; then
    echo "no branches found"
    exit 0
fi;

read -s -n 1 -p "press any key to delete $found branches older than $days days . . ."
echo ""

# run
for k in $(git branch --merged | grep -v -E "\\*|\bmaster\b|\bmain\b|\bdevelopment\b" | xargs -r -n 1); do
  if [[ ! $(git log -1 --since="$days days ago" -s $k) ]]; then
    git branch -d $k
  fi
done

Source: GitHub Gist

-End of Document-
Thanks for reading