How can I delete all git branches which have been "Squash and Merge" via GitHub?
Here's a script that will delete all local branches that have been squash merged into master:
git checkout -q master && git for-each-ref refs/heads/ "--format=%(refname:short)" | while read branch; do mergeBase=$(git merge-base master $branch) && [[ $(git cherry master $(git commit-tree $(git rev-parse "$branch^{tree}") -p $mergeBase -m _)) == "-"* ]] && git branch -D $branch; done
If you want to run a dry run, you can instead run this:
git checkout -q master && git for-each-ref refs/heads/ "--format=%(refname:short)" | while read branch; do mergeBase=$(git merge-base master $branch) && [[ $(git cherry master $(git commit-tree $(git rev-parse "$branch^{tree}") -p $mergeBase -m _)) == "-"* ]] && echo "$branch is merged into master and can be deleted"; done
You can then setup an alias like this:
alias gprunesquashmerged='git checkout -q master && git for-each-ref refs/heads/ "--format=%(refname:short)" | while read branch; do mergeBase=$(git merge-base master $branch) && [[ $(git cherry master $(git commit-tree $(git rev-parse "$branch^{tree}") -p $mergeBase -m _)) == "-"* ]] && git branch -D $branch; done'
Source:
There is no easy way to automate this, at least not completely. (Some special cases could be handled.) Instead, the best thing to do is to delegate this branch-deleting to the person whose pull request has been squash-merged. There are several good reasons for that:
They are the only ones who can be sure the merge was done correctly.
Suppose, for instance, that in order to squash-merge a series of six commits, the person who did the squash-merge had to, or chose to, change a few characters somewhere in a line or two, for some reason good or bad. That line or two means that the overall change in the final commit is different from the sum of the six changes in the six commits.
But is the overall result correct? If you did not do any of the changes yourself, how will you know?
They are the only ones who know if they intend to keep developing on that branch.
Just because the six commits on
feature/tall
were squashed into one commit added todevel
does not mean thatfeature/tall
is all done. They may have several more commits to add; they may want to rebasefeature/tall
ontodevel
again, dropping the six squashed commits in favor of the one six-commit-squash, but keeping another three commits they are about to add.
There are probably some more cases. These may all be rare; they may never occur in your project; but the point here is that branch feature/tall
is their branch, not your branch, so they—whoever they are—should be the ones deleting it when it's done.
Note that when you pick up feature/tall
you have your own Git rename it to origin/feature/tall
(assuming your remote is named origin
). If you are experimenting with it, and git checkout feature/tall
, your Git makes a copy for you. Once they delete feature/tall
and you run git fetch origin --prune
, your Git deletes your origin/feature/tall
. So now the problem is simpler and can be automated: find branches whose "upstream" is gone, and delete those. (The one line script in this answer has some minor flaws; see the comments; a fancier one would use git for-each-ref
and look up each branch's upstream setting with git rev-parse
, but that's probably overkill.)
The answer in this post is also useful https://medium.com/opendoor-labs/cleaning-up-branches-with-githubs-squash-merge-43138cc7585e
Adapted slightly to allow any origin name and prevent deletion of popular branches I use this:
git fetch --allREMOTE=$(git remote)comm -12 <(git branch | sed 's/ *//g') \ <(git remote prune $REMOTE | sed 's/^.*$REMOTE//g') \ | grep -v -e main -e master -e develop \ | xargs -L1 -J % git branch -D %