DEV Community

Cover image for 🍂 Remove gone git branches
Andrei L
Andrei L

Posted on • Edited on

🍂 Remove gone git branches

tl;dr Alias for removing local branches that are gone on remote

# ~/.gitconfig file
[alias]
    gone = "!f() { git fetch --all --prune; git branch -vv | awk '/: gone]/{print $1}' | xargs git branch -D; }; f"
Enter fullscreen mode Exit fullscreen mode
git gone
Enter fullscreen mode Exit fullscreen mode

If your git workflow is using Pull Requests that are merged into main branch, after a while your local list of branches will get very messy, because most of the time the PR is merged and remote branch is deleted.

However on local you just create a new branch from main for a new feature/fix, and you leave the previous branch behind without deleting it.

Let's start with this, list all local branches with their remotes

git branch -vv
Enter fullscreen mode Exit fullscreen mode
  feature-1 4ea9770 [origin/feature-1] test commit
  feature-2 4ea9770 [origin/feature-2] test commit
  feature-3 4ea9770 [origin/feature-3] test commit
  feature-4 4ea9770 [origin/feature-4] test commit
  feature-5 4ea9770 [origin/feature-5] test commit
  feature-6 4ea9770 [origin/feature-6] test commit
  feature-7 4ea9770 [origin/feature-7] test commit
* main      4ea9770 [origin/main] test commit
Enter fullscreen mode Exit fullscreen mode

Next we remove some remote branches, fetch remote info, and list branches again

git fetch --prune
git branch -vv
Enter fullscreen mode Exit fullscreen mode
  feature-1 4ea9770 [origin/feature-1: gone] test commit
  feature-2 4ea9770 [origin/feature-2] test commit
  feature-3 4ea9770 [origin/feature-3: gone] test commit
  feature-4 4ea9770 [origin/feature-4] test commit
  feature-5 4ea9770 [origin/feature-5] test commit
  feature-6 4ea9770 [origin/feature-6] test commit
  feature-7 4ea9770 [origin/feature-7: gone] test commit
* main      4ea9770 [origin/main] test commit
Enter fullscreen mode Exit fullscreen mode

travolta confused

As you can see there are some lines that have gone, that means that the remote branch is gone, so origin/feature-1, origin/feature-3, origin/feature-7 remote branches don't exist anymore, but we still have them locally. And with time this list can get very big.

Let's get back to our alias. Now that we have this gone keyword in the branch list, we can hook in and get the branch name and delete it. For example to manually delete feature-7 we would do:

# Fetch info for all remotes and prune info of missing remote branches
git fetch --all --prune
# List all branches to see what is gone
git branch -vv
# Delete desired branch
git branch -D feature-7
Enter fullscreen mode Exit fullscreen mode

Now let's combine all these 3 into a single one liner 🚀

git fetch --all --prune; git branch -vv | awk '/: gone]/{print $1}' | xargs git branch -D;
Enter fullscreen mode Exit fullscreen mode

Here we use pipe (|) operator to pass output from one command to another pipe.

git fetch --all --prune just fetches remotes info
git branch -vv list branches and pipes output lines to awk
awk '/: gone]/{print $1}' find lines with gone, select first column (which is branch name) and pipe to xargs
xargs git branch -D takes received branches names and deletes them

And to make this one liner a git alias we put it into a function that will be called 💻

You can add manually the alias in your ~/.gitconfig file

# ~/.gitconfig file
[alias]
    gone = "!f() { git fetch --all --prune; git branch -vv | awk '/: gone]/{print $1}' | xargs git branch -D; }; f"
Enter fullscreen mode Exit fullscreen mode

Or follow these steps. Usually is a single line, but because of multiple quotes, double quotes and dollar signs we have to do it in multiple steps using a temporary file:

Put the alias code in alias temporary file

echo "f() { git fetch --all --prune; git branch -vv | awk '/: gone]/{print \$1}' | xargs git branch -D; }; f" > alias
Enter fullscreen mode Exit fullscreen mode

Consume alias file for git alias command

git config --global alias.gone "!`cat alias`"
# remove temporary created file
rm alias
Enter fullscreen mode Exit fullscreen mode

Now let's do a full demo 😮‍💨

git branch -vv
Enter fullscreen mode Exit fullscreen mode
  feature-1 4ea9770 [origin/feature-1] test commit
  feature-2 4ea9770 [origin/feature-2] test commit
  feature-3 4ea9770 [origin/feature-3] test commit
  feature-4 4ea9770 [origin/feature-4] test commit
  feature-5 4ea9770 [origin/feature-5] test commit
  feature-6 4ea9770 [origin/feature-6] test commit
  feature-7 4ea9770 [origin/feature-7] test commit
* main      4ea9770 [origin/main] test commit
Enter fullscreen mode Exit fullscreen mode

Next I deleted all feature branches on remote. And call git gone

git gone
Enter fullscreen mode Exit fullscreen mode
Fetching origin
From /Users/iamandrewluca/Temp/gone-bare
 - [deleted]         (none)     -> origin/feature-1
 - [deleted]         (none)     -> origin/feature-2
 - [deleted]         (none)     -> origin/feature-3
 - [deleted]         (none)     -> origin/feature-4
 - [deleted]         (none)     -> origin/feature-5
 - [deleted]         (none)     -> origin/feature-6
 - [deleted]         (none)     -> origin/feature-7
Deleted branch feature-1 (was 4ea9770).
Deleted branch feature-2 (was 4ea9770).
Deleted branch feature-3 (was 4ea9770).
Deleted branch feature-4 (was 4ea9770).
Deleted branch feature-5 (was 4ea9770).
Deleted branch feature-6 (was 4ea9770).
Deleted branch feature-7 (was 4ea9770).
Enter fullscreen mode Exit fullscreen mode

magician focus gone

I like my local repo to always be clear. And in the past I had always to check what branches are deleted on remote and delete them also locally. Now I don't have to remember anything. Just git gone

Are you still here? 😊 Thanks for reading my blog posts! 🎉 🎈

You'll miss me when I'm gone ♥️


Initial idea by Tom Witkowski on Twitter

Cover Photo by Birti Ishar on Unsplash

Top comments (5)

Collapse
 
graysonlang profile image
Grayson Lang • Edited

Thanks, this is great! Minor tweak to use the --filter option to make sure we're not possibly matching on commit string contents (as unlikely as that may be):

[alias]
    gone = "!f() { git fetch --all --prune; git branch --format '%(refname:short) %(upstream:track)' | awk '/\\[gone\\]/{print $1}' | xargs git branch -D; }; f"
Enter fullscreen mode Exit fullscreen mode
Collapse
 
chadidi profile image
Abdellah Chadidi

Some WIP branches be like: you'll gonna miss me when i'm gone 😄.

Collapse
 
iamandrewluca profile image
Andrei L

😀

Collapse
 
louispineaushift profile image
louis-pineau-shift

Great article ! But it seems that it is not working with the git config remote.origin.prune true enabled because it looks like that this config also remove the reference to the remote branch :/

Collapse
 
gaetanrdn profile image
Gaëtan Redin

Great :-)