We can use git fetch --prune
to remove the remote-tracking branches that no longer exist on the remote. However, the local branches that track on them still exist. This post aims to tell you how to remove them using the git alias git cleanup
and explain how it works.
TLDR
Step 1: Create a file git-cleanup
under your PATH
Step 2: Paste the following scripts in git-cleanup
:
#!/bin/bash
git fetch --prune && git branch -r | awk '{print $1}' | egrep -v -f /dev/fd/0 <(git branch -vv | grep origin) | awk '{print $1}' | xargs git branch -D
Note: The first line(shebang) should be either
#!/bin/bash
or#!/bin/zsh
Step 3: Make it executable:
chmod +x ./git-cleanup
Step 4: Add git alias:
git config alias.cleanup "!git-cleanup"
Then, you can call git cleanup
directly in your command line!
How it works
Let's look at the shell script git-cleanup
. Assume that we have the following branches in the local:
main -> origin/main
branch1 -> origin/branch1
branch3
Note:
->
means track on
And the branches in the remote
origin/main
origin/branch2
The branch1
is merged and has been removed in the remote. And the branch3
is still under development and hasn't been pushed to remote yet.
According to the assumptions, let's look at how the script works!
git fetch --prune
This command removes the remote-tracking branch in your local.
See the git documentation for more information.
git branch -r
Show all the remote branches. Documentation
awk '{print $1}'
awk
is a program that helps you parse your stdin. In this case the stdin is the result of git branch -r
:
origin/HEAD -> origin/main
origin/main
origin/branch2
We are interested in the first field of each line. So we use the action 'print $1' to list out all the remote branches. The result will be:
origin/HEAD
origin/main
origin/branch2
egrep -v -f /dev/fd/0 <(git branch -vv | grep origin)
This is the most important part of this script. Let's look at git branch -vv | grep origin
first.
git branch -vv
shows the local branches with their tracking branches in the following:
main <SHA> [origin/main] last commit message
branch1 <SHA> [origin/branch1] last commit message
branch3 <SHA> last commit message
Thus, we use grep
to filter the lines with origin
, which means it has a remote-tracking branch. So the output of git branch -vv | grep origin
will be:
main <SHA> [origin/main] last commit message
branch1 <SHA> [origin/branch1] last commit message
Then, we are going to compare the result of git branch -r
and git branch -vv | grep origin
to find the local branches which remote-tracking branch has been removed. We are using egrep
with -v
options to select the lines which is not in the git branch -r
. We use -f
option because <()
, which we call Process Substitution, will be treat as a file. /dev/fd/0
means stdin, which is git branch -r
in our case.
Thus until here, the result should be:
branch1 <SHA> [origin/branch1] last commit message
awk '{print $1}'
Again, we are using awk
to parse the stdin. The result should be:
branch1
xargs git branch -D
Finally, we are going to delete the branches in the previous result one-by-one using xargs. You can think of xargs
works like:
for line in stdin
git branch -D line
Here I use -D
to force delete even though the branch isn't fully merged. If you don't want to delete the branches that aren't fully merged, please use -d
#!/bin/bash
It is very important to add this line at the first of the script. This is called shebang and it is use to specify which shell are we going to execute this script. We are leveraging Process Substitution, which isn't supported in sh
. So if not specifying this, the script may be triggered by sh
and throws error because sh
doesn't recognize <()
.
Top comments (1)
would be really cool if someone made this a vscode extension..