When working on multiple repositories and branches, testing branches, backing them up, code reviewing, playing around branches, etc. I find myself in a situation where it pains me when the time for clean-up comes.
In order to delete branches, I need to google the command. However, it might not always work as I want. For example, if I want some branches to be saved I need to update the command and restart the terminal, or if I want to save few additional branches with different naming convention I again need to update the command and restart the terminal... you get the point.
Additionally, I wanted to create a more permanent solution for all of the repositories. Here is the link to the repository: remove-git-branch. Let me try and explain what I did in the script the best I can.
My goal was to have a flexible script that does deletion based on arguments.
In the repository linked above you will find the script remove-git-branches.sh.
for i in "$@"; do
case $i in
-b=*|--branch=*)
BRANCHES="${i#*=}"
shift # past argument=value
;;
-p=*|--pattern=*)
PATTERN="${i#*=}"
shift # past argument=value
;;
-a|--all)
ALL=".*"
shift # past argument=value
;;
-e=*|--exclude=*)
EXCLUDE="${i#*=}"
shift # past argument=value
;;
-c|--check)
CHECK="true"
shift # past argument=value
;;
-f|--force)
FORCE="true"
shift # past argument=value
;;
-h|--help)
echo "usage: remove-git-branch [-b=<pattern> | --branch=<pattern>] [-p=<pattern> | --pattern=<pattern>]
[-a | --all] [-h | --help]"
echo "-b (--branch) - Branches to remove separated by ','. It has priority over pattern."
echo "-p (--pattern) - Regex pattern to define witch branches should be removed."
echo "-a (--all) - Remove all branches, expect master, **main, and current."
echo "-e (--exclude) - Branches to exclude from deleting."
echo "-c (--check) Print branches that will be deleted. But DOES NOT delete them."
echo "-f (--force) Force delete branches, even if it has unmerged changes."
echo "-h (--help) - Available flags."
exit 1;
;;
*)
# unknown option
;;
esac
done
One of the first things you will notice is a for-in loop. This loop will collect all the arguments when a script is called. You can thank Bruno Bronosky stackoverflow answer for this piece of code.
if [[ $EXCLUDE ]]; then
SPLIT_EXCLUDE=$(echo $EXCLUDE | tr "," "|");
EXCLUDE="^($EXCLUDE_DEFAULT|$SPLIT_EXCLUDE)$"
else
EXCLUDE="^($EXCLUDE_DEFAULT)$"
fi
EXCLUDE, as the name suggests, excludes branches from deleting. By default, it always excludes master, main and current branches which is represented by EXCLUDE_DEFAULT.
if [[ $BRANCHES ]]; then
SPLIT_BRANCHES=$(echo $BRANCHES | tr "," "|");
DELETE_BRANCHES="^($SPLIT_BRANCHES)$"
fi
Here I am checking if the variable BRANCHES is not empty. If not empty, replacing is done in the same way as EXCLUDE.
if [[ $PATTERN ]]; then
DELETE_PATTERN="$PATTERN"
fi
This one is here just for taking the value from the PATTERN.
if [[ $DELETE_PATTERN ]] && [[ $DELETE_BRANCHES ]]; then
DELETE="(($DELETE_BRANCHES)|($DELETE_PATTERN))"
elif [[ $DELETE_PATTERN ]]; then
DELETE=$DELETE_PATTERN
elif [[ $DELETE_BRANCHES ]]; then
DELETE=$DELETE_BRANCHES
fi
There are three ways of deleting: by passing branches, by passing pattern, or combined. The first IF statement would merge branch and pattern meaning we passed both of them, the second one would pass only pattern, and the third one would pass only branches.
if [[ $ALL ]]; then
DELETE="$ALL"
fi
Next IF statement is ALL. It removes all the local branches we have. Again, the master, the main, and the current branch will not be deleted.
if [[ $CHECK ]]; then
git branch | awk '{gsub(/^[ \t]+| [ \t]+$/,""); print $0 }' | egrep -v "$EXCLUDE" | egrep "$DELETE"
elif [[ $FORCE ]]; then
git branch | awk '{gsub(/^[ \t]+| [ \t]+$/,""); print $0 }' | egrep -v "$EXCLUDE" | egrep "$DELETE" | xargs git branch -D
else
git branch | awk '{gsub(/^[ \t]+| [ \t]+$/,""); print $0 }' | egrep -v "$EXCLUDE" | egrep "$DELETE" | xargs git branch -d
fi
The last block of code is where the command runs. There are few things that are happening.
-
git branch
gets a list of all branches -
awk '{gsub(/^[ \t]+| [ \t]+$/,""); print $0 }'
removes empty spaces on both sides of the branch -
egrep -v "$EXCLUDE"
prints all the branches that DO NOT match pattern,-v
flag does that. -
egrep "$DELETE"
prints all the branches that DO match pattern. - - If we pass the check flag (
$CHECK
), deletion will not happen but the branch name that was supposed to be deleted will be printed, it can be thought of as a sanity check.- If we pass the force flag (
$FORCE
), deletion will happen but it will additionally delete a branch that was not merged. - The last ELSE statement is a "safe" option that prevents deletion of the branch if it has unmerged changes.
- If we pass the force flag (
Top comments (0)