Skip to content

Instantly share code, notes, and snippets.

@ivanopcode
Created July 10, 2023 23:12
Show Gist options
  • Save ivanopcode/2b77ad2556b757619b559892de30d518 to your computer and use it in GitHub Desktop.
Save ivanopcode/2b77ad2556b757619b559892de30d518 to your computer and use it in GitHub Desktop.
git-branch-cleanup shell script that deletes local branches
#!/bin/zsh
# ---------------------------------------------------------------------------------
# Script Name: git-branch-cleanup
# Version: 1.0.0+2023-06-11
# Author: Ivan Oparin <amici.waxwing.01@icloud.com>
#
# License:
# MIT License
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in all
# copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE.
# ---------------------------------------------------------------------------------
# SCRIPT DESCRIPTION:
#
# This script is designed to clean up local Git branches. It operates
# within a Git repository, deleting all local branches except those specified
# as "protected". Currently, the script only runs from a predefined "main"
# branch and will exit if attempted from any other branch. In the future,
# this main branch and list of protected branches will be configurable via
# a .gitcleanup configuration file located in the root of the repository.
#
# The script first verifies if it is being run within a Git repository, and
# if there are any unstaged changes. If either of these conditions fails,
# the script displays an appropriate error message and exits. This prevents
# accidental execution in non-repository directories or when unstaged changes
# are present.
#
# Once validated, the script checks if it's being run from the specified main
# branch. If not, it presents an error message and terminates.
#
# Lastly, the script iterates over each local branch. If a branch is not
# present in the list of protected branches, the script deletes it. This
# operation is performed using the 'git branch -D' command.
#
# Please see the 'NOTES TO USERS AND MAINTAINERS' section below for more
# information on certain command usage and other nuances.
# NOTES TO USERS AND MAINTAINERS:
#
# This script contains safety checks to ensure it is run only within a Git
# repository and when there are no unstaged changes. 'git rev-parse
# --is-inside-work-tree' is employed to determine if the script is being
# executed within a Git repository. The command returns 0 (success) when
# inside a Git repository, and 1 (failure) otherwise. If a non-zero status
# is returned, an error message is displayed and the script terminates.
#
# The script also checks for unstaged changes using 'git diff-index
# --quiet HEAD --'. This command compares the working directory and the
# index (staging area) for changes. It returns 0 if no differences are
# detected (i.e., there are no unstaged changes), and 1 if there are
# unstaged changes. If there are unstaged changes, the script displays an
# error message and exits. These checks help maintain the integrity of the
# user's Git repository and ensure the script behaves as expected.
# TODO:
#
# Implement a .gitcleanup configuration file which should be placed at the
# root of the repository. The file should contain a list of protected branches,
# one per line. The first line of the file should be the main branch from
# which this script is allowed to run. Modify the script to read from this
# file at the start of its execution. Make sure to handle cases where the
# file does not exist or is incorrectly formatted.
# Color codes
ERROR='\033[1;31m' # Bold Red
SUCCESS='\033[1;32m' # Bold Green
WARNING='\033[1;33m' # Bold Yellow
NOCOLOR='\033[0m' # No Color
# Check if this is a git repository
git rev-parse --is-inside-work-tree > /dev/null 2>&1
if [[ $? != 0 ]]; then
echo -e "${ERROR}❌ This script must be run inside a Git repository.${NOCOLOR}"
exit 1
fi
# Check if there are unstaged changes
git diff-index --quiet HEAD --
if [[ $? != 0 ]]; then
echo "${ERROR}❌ There are unstaged changes. Please commit or stash them before running this script.${NOCOLOR}"
exit 1
fi
# Configurable main branch
main_branch="development"
# Array of branches to protect, including main branch
protected_branches=("$main_branch" "develop" "development" "master" "main")
# Current branch
current_branch=$(git rev-parse --abbrev-ref HEAD)
# Check if current branch is the main branch
if [[ "$current_branch" != "$main_branch" ]]; then
echo "${ERROR}❌ This script can only be run from the ${main_branch} branch!${NOCOLOR}"
exit 1
fi
# Branches to be deleted
branches_to_delete=()
# Loop over each local branch
for branch in $(git branch | cut -c3-); do
if [[ ! " ${protected_branches[@]} " =~ " ${branch} " ]]; then
# If branch is not in protected branches, add to delete list
branches_to_delete+=("$branch")
fi
done
# Print branches to be deleted and ask for confirmation
echo "${WARNING}⚠️ The following branches will be deleted:${NOCOLOR}"
for branch in ${branches_to_delete[@]}; do
echo "🔘 $branch"
done
echo "${WARNING}⚠️ Are you sure you want to continue? [Y/n]${NOCOLOR}"
read REPLY
if [[ $REPLY =~ ^[Yy]$ || $REPLY == "" ]]
then
# If confirmed, delete branches
for branch in ${branches_to_delete[@]}; do
git branch -D $branch > /dev/null
echo "☑️ Deleted local branch $branch"
done
echo "${SUCCESS}✅ All non-protected local branches were deleted.${NOCOLOR}"
else
echo "${ERROR}❌ No appropriate confirmation. Operation cancelled.${NOCOLOR}"
exit 1
fi
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment