Delete all branches that are more than X days/weeks old

GitShell

Git Problem Overview


I found the below script that lists the branches by date. How do I filter this to exclude newer branches and feed the results into the Git delete command?

for k in $(git branch | sed /\*/d); do 
  echo "$(git log -1 --pretty=format:"%ct" $k) $k"
done | sort -r | awk '{print $2}'

Git Solutions


Solution 1 - Git

How about using --since and --before?

For example, this will delete all branches that have not received any commits for a week:

for k in $(git branch | sed /\*/d); do 
  if [ -z "$(git log -1 --since='1 week ago' -s $k)" ]; then
    git branch -D $k
  fi
done

If you want to delete all branches that are more than a week old, use --before:

for k in $(git branch | sed /\*/d); do 
  if [ -z "$(git log -1 --before='1 week ago' -s $k)" ]; then
    git branch -D $k
  fi
done

Be warned though that this will also delete branches that where not merged into master or whatever the checked out branch is.

Solution 2 - Git

The poor man's method:

List the branches by the date of last commit:

git branch --sort=committerdate | xargs echo

this will list the branches while xargs echo pipe makes it inline (thx Jesse).

You will see all your branches with old ones at the beginning:

1_branch 2_branch 3_branch 4_branch

Copy the first n ones, which are outdated and paste at the end of the batch delete command:

git branch -D 1_branch 2_branch

This will delete the selected ones only, so you have more control over the process.

To list the branches by creation date, use the --sort=authordate:iso8601 command as suggested by Amy

Remove remote branches

Use git branch -r --sort=committerdate | xargs echo (says kustomrtr) to review the remote branches, than git push origin -d 1_branch 2_branch to delete the merged ones (thx Jonas).

Solution 3 - Git

Safe way to show the delete commands only for local branches merged into master with the last commit over a month ago.

for k in $(git branch --format="%(refname:short)" --merged master); do 
  if (($(git log -1 --since='1 month ago' -s $k|wc -l)==0)); then
    echo git branch -d $k
  fi
done

This does nothing but to output something like:

git branch -d issue_3212
git branch -d fix_ui_search
git branch -d issue_3211

Which I copy and paste directly (remove the echo to delete it directly)

This is very safe.

Solution 4 - Git

This is what worked for me:

for k in $(git branch -r | sed /\*/d); do 
  if [ -z "$(git log -1 --since='Aug 10, 2016' -s $k)" ]; then
    branch_name_with_no_origin=$(echo $k | sed -e "s/origin\///")
    echo deleting branch: $branch_name_with_no_origin
    git push origin --delete $branch_name_with_no_origin
  fi
done

The crucial part is that the branch name (variable $k) contains the /origin/ part eg origin/feature/my-cool-new-branch However, if you try to git push --delete, it'll fail with an error like:
unable to delete 'origin/feature/my-cool-new-branch': remote ref does not exist.
So we use sed to remove the /origin/ part so that we are left with a branch name like feature/my-cool-new-branch and now git push --delete will work.

Solution 5 - Git

It's something similar to Daniel Baulig answer, but also takes in consideration ben's comment. Also It filters branches by a given patter, since we're using try-XX convention for branching.

for k in $(git branch -r | awk -F/ '/\/YOUR_PREFIX_HERE/{print $2}' | sed /\*/d); do
   if [ -z "$(git log -1 --since='Jul 31, 2015' -s origin/$k)" ]; then
     echo deleting "$(git log -1 --pretty=format:"%ct" origin/$k) origin/$k";
	 git push origin --delete $k;
   fi;
done

Solution 6 - Git

The above code did not work for me, but it was close. Instead, I used the following:

for k in $(git branch | sed /\*/d); do 
  if [[ ! $(git log -1 --since='2 weeks ago' -s $k) ]]; then
    git branch -D $k
  fi
done

Solution 7 - Git

Delete 5 oldest remote branches

git branch -r --sort=committerdate | head -n 5 | sed 's/  origin\///' | xargs git push origin --delete

Solution 8 - Git

git branch --sort=committerdate | head -n10 | xargs git branch -D

Solution 9 - Git

for k in $(git branch -r | sed /\*/d); do 
  if [ -n "$(git log -1 --before='80 week ago' -s $k)" ]; then
    git push origin --delete "${k/origin\//}"
  fi
done

Solution 10 - Git

I'm assuming that you want to delete just the refs, not the commits in the branches. To delete all merged branches except the most recent __X__:

git branch -d `for k in $(git branch | sed /\*/d); do
  echo "$(git log -1 --pretty=format:"%ct" $k) $k"
done | sort -r | awk 'BEGIN{ORS=" "}; {if(NR>__X__) print $2}'`

To delete all branches before timestamp __Y__:

git branch -d `for k in $(git branch | sed /\*/d); do
  echo "$(git log -1 --pretty=format:"%ct" $k) $k"
done | sort -r | awk 'BEGIN{ORS=" "}; {if($1<__Y__) print $2}'`

Replace the -d option by -D if you want to delete branches that haven't been merged as well... but be careful, because that will cause the dangling commits to be garbage-collected at some point.

Solution 11 - Git

Based on @daniel-baulig's answer and the comments I came up with this:

for k in $(git branch -r --format="%(refname:short)" | sed s#^origin/##); do
   if [ -z "$(git log -1 --since='4 week ago' -s $k)" ]; then
    ## Info about the branches before deleting
    git log -1 --format="%ci %ce - %H $k" -s $k;
    ## Delete from the remote
    git push origin --delete $k;
    ## Delete the local branch, regardless of whether it's been merged or not
    git branch -D $k
  fi;
done

This can be used to delete all old branches (merged or NOT). The motivation for doing so is that it is unlikely that branches that has not been touched in a month rot and never make it to master. Naturally, the timeframe for pruning old branches depends on how fast the master branch moves.

Solution 12 - Git

Sometimes it needs to know if a branch has been merged to the master branch. For that purpose could be used the following script:

#!/usr/bin/env bash

read -p "If you want delete branhes type 'D', otherwise press 'Enter' and branches will be printed out only: " action
[[ $action = "D" ]] && ECHO="" || ECHO="echo"

for b in $(git branch -r --merged origin/master | sed /\*/d | egrep -v "^\*|master|develop"); do
  if [ "$(git log $b --since "10 months ago" | wc -l)" -eq 0 ]; then
    $ECHO git push origin --delete "${b/origin\/}" --no-verify;
  fi
done

Tested on Ubuntu 18.04

Solution 13 - Git

Actually, I found the accepted answer wasn't reliable enough for me because of the ben's comment. I was looking for cleaning up old release branches so it's possible that the top commit has been cherry picked and has an old commit date... Here's my take on it:

REMOTE_NAME=origin
EXPIRY_DATE=$(date +"%Y-%m-%d" -d "-4 week")

git fetch $REMOTE_NAME --prune
git for-each-ref --format='%(committerdate:short) %(refname:lstrip=3) %(refname:short)' --sort -committerdate refs/remotes/$REMOTE_NAME | while read date branch remote_branch; do
    # protected branch
    if [[ $branch =~ ^master$|^HEAD$ ]]; then
        printf "%9s | %s | %50s | %s\n" "PROTECTED" $date $branch $remote_branch
    elif [[ "$date" < "$EXPIRY_DATE" ]]; then
        printf "%9s | %s | %50s | %s\n" "DELETE" $date $branch $remote_branch
        #git push $REMOTE_NAME --delete $branch
    fi
done

You can easily adapt the delete command based on your needs. Use this carefully.

Output example: enter image description here

Solution 14 - Git

For how using PowerShell:

  • Delete all merged branches excluding notMatch pattern
git branch -r --merged | Select-String -NotMatch "(^\*|master)" | %{ $_ -replace ".*/", "" } | %{ git push origin --delete $_ }
  • List all merged branches in txt file
git branch -r --merged | Select-String -NotMatch "(^\*|master)" | %{ $_ -replace ".*/", "" } | Set-Content -Path .\deleted-branches.txt

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionKenoyer130View Question on Stackoverflow
Solution 1 - GitDaniel BauligView Answer on Stackoverflow
Solution 2 - GitgazdagergoView Answer on Stackoverflow
Solution 3 - GitestaniView Answer on Stackoverflow
Solution 4 - GitKomuView Answer on Stackoverflow
Solution 5 - Git3615View Answer on Stackoverflow
Solution 6 - GitKirk StrobeckView Answer on Stackoverflow
Solution 7 - GitNovikovView Answer on Stackoverflow
Solution 8 - GitSD.View Answer on Stackoverflow
Solution 9 - GitYogi SadhwaniView Answer on Stackoverflow
Solution 10 - GitJulianView Answer on Stackoverflow
Solution 11 - GitGeorgeView Answer on Stackoverflow
Solution 12 - GitwwwebmanView Answer on Stackoverflow
Solution 13 - GitmathpaquetteView Answer on Stackoverflow
Solution 14 - GitakramgassemView Answer on Stackoverflow