Let's consider the following git graph.
- The initial commit is 1.
- The colors identify the authors of each commit.
- Orange has left the project.
- Green, Blue and Pink are still active.
- chat, master and tags are the branches.
- master is to be kept.
- tags is to be kept because Pink is working on it.
- chat is candidate for removal because only Orange was working on it.
The following script will list the branches which are candidates to be deleted.
In order to use it two text files need to be created.
- A file with the live branches. That is, branches we know that should not be deleted. In our previous example the file would contain just "master" (without the quotes). The branches in the file are to be separated with spaces and/or new lines.
- A file with the e-mails of people who are considered to have left the project. Also separated with spaces and/or new lines.
Then invoke the script (which I've named dead.sh) with:
bash dead.sh /route/to/file_with_live_branches /route/to/file_with_emails
It will display the list of branches which are candidates for removal. This script uses version 4.0 bash features. So you need to check that your bash interpreter is at least 4.0 version with:
[email protected]:~$ bash --version
GNU bash, version 5.0.17(1)-release (x86_64-pc-linux-gnu)
The script :
# Bash script to locate dead branches
# $1 = File with live branches separated by spaces and/or in different lines
# $2 = File with email addresses of people who "have left" separated by spaces and/or in different lines
# A commit is said to be alive if its the commit directly associated to a live branch or is an ancestor of a live branch.
# The hanging commits of a branch is the set : (ancestors_of_the_branch PLUS commit_directly_associated_to_the_branch) MINUS commits_which_are_alive
# A branch is dead if it has at least 1 hanging commit and all its hanging commits have been written by people in the list of email addresses of people who have left
echo "dead.sh <live_branches_file> <people_who_left_file>"
echo "Locates branches where all hanging commits are from people who have left."
echo "live_branches_file : A file with a list of branches which are considered live. All commits outside these branches are considered as hanging. Branch names should be separated with spaces and/or new lines."
echo "people_who_left_file : A file with a list of emails of people who \"have left\". If all the hanging commits of a non-live branch are authored exclusively by people in this list the branch is considered dead and will be listed by this command. emails should be separated with spaces and/or newlines"
if [ $# -ne 2 ]; then
declare -A LIVE
for live_branch in $(cat "$1"); do
THISLIVE=$(git log --pretty=format:"%H" $live_branch)
if [ $? -ne 0 ]; then
echo "Error running command : git log --pretty=format:\"%H\" $live_branch"
for l in $THISLIVE; do
BRANCHES=$(git for-each-ref --format='%(refname:short)' refs/heads/)
if [ $RES -ne 0 ]; then exit $RES; fi
declare -A PEOPLE_LEFT
# Note that emails (like any URL) are guaranteed to have no spaces
for p in $(cat "$1"); do
BRANCH_COMMITS=$(git log --pretty=format:"%H" $1)
is_hanging=1 # False
for commit in $BRANCH_COMMITS; do
if [[ -v LIVE[$commit] ]]; then
AUTHOR=$(git show -s --format='%ae' $b)
if [[ -v PEOPLE_LEFT["$AUTHOR"] ]]; then
is_hanging=0 # True
return 1 # Not abandoned because commit author is not among those who left
# Note that git branches are guaranteed to not contain spaces
for b in $BRANCHES; do
if [ $? -eq 0 ]; then
check_args "[email protected]"