Originally published on Cohost in 2 parts.
alias prune="git remote prune origin | sed -n -E '/polywolf/ s/.*(polywolf.*)/\1/p' | xargs git branch -D"
because i found myself typing it out from memory that often
oh no… I’m becoming one of Those girlies aren’t i…
”PolyWolf, What Does This Do?”
i’m glad you asked!! let’s break it down:
NOTE: this assumes some familiarity with how git branches work. See this and potentially this for quick explainer
Goals
in git, I like to use short-lived feature branches that I then rebase onto main
, squash to a single commit, and delete1. Turns out this style of git is so common that GitHub has a dedicated option for doing this with a single click on a pull request.
The problem with the GitHub click is that, while the branch is deleted in the remote repository, the branch you were working on locally is still around and clutters up git branch
output and any tab-complete things you have set up. So! What we want to do, then, is have a command that you can run periodically to delete local branches that were deleted on the remote.
Getting A List Of Branches To Delete
This is actually a tricky UX question! How do you know the difference between a “deleted branch” and “a branch you haven’t pushed yet”? The answer is, you don’t! There is no way for git to know this information 🙂
But! We can still do something that’s almost as good: getting a list of branches that have been deleted on the remote since the last time you did a prune. There is a command for this: git remote prune origin
. This will look at all the locally-cached remote-tracking branches (the ones starting with origin/
), and delete any that are no longer present on the remote.
This is almost exactly what we want. But as I said earlier, even if the branch origin/polywolf/feature-branch
is deleted, polywolf/feature-branch
will stick around. Fortunately, git remote prune origin
prints out what it does. Unfortunately, there are no formatting options for its output, so we resort to Manually Parsing It.
Editing Streams With The Stream EDitor
this is in fact what sed
is meant to do! Let’s break down the specific invocation I use:
The Arguments
From sed --help
-n
: “suppress automatic printing of pattern space”. Basically, only output lines when we tell it to-E
: “use extended regular expressions in the script”. Basically, allow for replacements by capture groups2.- the last argument is interpreted as a sed script, which we will need to go to the manpage for
The Script
From (let’s be real here) searching on Stack Overflow:man sed
/polywolf/
: only run on lines that have “polywolf” in thems/.*(polywolf.*)/\1/p
:2 For every line that looks like* [pruned] origin/polywolf/feature-branch
, print out justpolywolf/feature-branch
. I verified this regex experimentally :)
Great! We’ve collected all the branches we need into a “list” (newline-separated strings), and now we just need to delete them. But how?
Deleting A Branch
The command to delete a branch is git branch -d
. However, in this normal delete, git will complain the branch hasn’t been merged. We don’t care about this, because our feature branches have been effectively added as a commit on main
, so we need to tell git “yes we really want to delete this branch”, which we can do with git branch -D
.
Deleting ALL The Branches
The typical way of iterating over a list in bash-likes is
for branch in $(the-expression)
do
git branch -D "$branch"
done
This is the same as running git branch -D b1; git branch -D b2; git branch -D b3; ...
, which, while somewhat inefficient from starting so many processes, Just Works™️. But! As it turns out, git branch -D b1 b2 b3 ...
has the same effect, so we can use xargs
(I absolutely adore xargs
, it is so useful in one-liners).
xargs
takes in a “list” on standard input, and then turns that into an argument list it appends to whatever command you give it. So, given the list of branches we have currently, xargs git branch -D
does exactly what we want!
And there you have it! A comprehensive explanation of a 1-liner I wrote for my own purposes that will probably be useful to no one else. This is the power of custom aliases/scripts, u can really tailor your own shell experience. it’s almost too powerful… i still have a lot to learn tho!