Skip to content

Instantly share code, notes, and snippets.

@LucasRoesler
Last active November 17, 2023 13:07
Show Gist options
  • Save LucasRoesler/0da1a7515a822bcf3cb5eb2a31a515bb to your computer and use it in GitHub Desktop.
Save LucasRoesler/0da1a7515a822bcf3cb5eb2a31a515bb to your computer and use it in GitHub Desktop.
Find squash-commited branches that can be deleted

Git Branch Audit

  1. It retrieves the name of the default branch from the remote repository using the git ls-remote command.
  2. It checks out the default branch locally.
  3. It lists all local branches using the git for-each-ref command.
  4. For each local branch, it finds the merge base between the default branch and the current branch using the git merge-base command.
  5. It creates a temporary commit tree for the current branch using the git commit-tree command.
  6. It checks if the temporary commit is a descendant of the default branch using the git cherry command.
  7. If the temporary commit is not a descendant (i.e., the branch has been merged into the default branch), it prints a message indicating that the branch can be deleted.

Essentially it fakes a squash merge for each branch and then checks of the default branch is a decendent from this. It will also print the branches that were merged in the "normal" way, i.e. git merge.

#!/usr/bin/env bash
set -e
# Function to display the help text
display_help() {
echo "Usage: git-audit [OPTIONS]"
echo "Check for merged branches in a Git repository and print messages indicating whether each branch is merged and can be deleted."
echo ""
echo "Options:"
echo " -q Quiet mode. Only print the branch names without additional messages."
echo " -h Display this help message."
echo ""
echo "Example:"
echo " git-audit -q | xargs -n 1 git branch -D"
}
quiet=false
while getopts "qh" opt; do
case $opt in
q)
# Set the quiet flag to true if the -q option is provided
quiet=true
;;
h)
# Display the help text and exit if -h or --help option is provided
display_help
exit 0
;;
\?)
# Print an error message and exit if an invalid option is provided
echo "Invalid option: -$OPTARG" >&2
exit 1
;;
esac
done
# Shift the processed options, so the remaining arguments are accessible
shift $((OPTIND - 1))
# Get the default branch of the repository
default_branch=$(git ls-remote --symref origin HEAD | sed -nE 's|^ref: refs/heads/(\S+)\s+HEAD|\1|p')
# Function to print the branch message
print_branch_message() {
local branch=$1
# Check if the script is running in quiet mode
if [ "$quiet" = true ]; then
echo "$branch"
else
echo "$branch is merged into '$default_branch' and can be deleted"
fi
}
# Switch to the default branch and iterate over all local branches
git checkout -q "$default_branch" && git for-each-ref refs/heads/ "--format=%(refname:short)" | while read branch; do
# Find the merge base between the default branch and the current branch
mergeBase=$(git merge-base $default_branch $branch)
# Check if the branch is merged by comparing the result of git cherry with a hyphen
if [[ $(git cherry $default_branch $(git commit-tree $(git rev-parse "$branch^{tree}") -p $mergeBase -m _)) == "-"* ]]; then
print_branch_message "$branch"
fi
done
# Get a list of merged branches and filter out the default branch
git branch --merged | grep -v "$default_branch" | while read merged; do
print_branch_message "$branch"
done
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment