Roman Sorin

Deleting Git branches in bulk

Deleting several Git branches at once with commands like git branch -D can become a real headache. At any time, I have between 5-15 branches per project, all of which I may complete at random times based on priority and state. If you forget to delete your local branches after merging your work, you may end up having weeks of stale branches living within your project.

Thankfully, there’s an easier alternative to this, and we can run a single command using commands like a pipe (|) and grep to delete several branches at once.

The command

Deleting branches in bulk can be done in a single line:

git branch | grep -iE 'FIX|FEAT' | xargs git branch -D

Let’s take a look at what’s being done here:

  1. First, we define our first command, git branch, on the left side of the first pipe. This lists all of the branches within your project.
  2. Second, we define a grep command which will search the output of our branch command. Since we are using a pipe, the output of git branch is passed to grep. To match several branch patterns at once, we define the -E flag. This allows us to match several strings while also supporting extended regular expressions. We also may have case variations between “FIX”, and “fix”, meaning our grep should be case-insensitive. We do this with the -i flag.
  3. Third, we define the normal branch deletion command on the right side of the last pipe, and also supply xargs as part of this command. xargs, or extended arguments, will take the left side of the last pipe (our grep command) and pass it as arguments to git branch -D, calling the branch deletion command for each matched branch.
  4. As a result, all branches that start with “FEAT” or “FIX” (case insensitive) are automatically deleted.

Visualizing the deletion

To visualize this, let’s run each of these commands individually:

$ git branch


Running git branch returns all of the existing local branches. Now, let’s try to find all of the branches that we want to delete:

$ git branch | grep -iE 'FIX|FEAT'

* FEAT/RS-123
* FIX/RS-456
* feat/RS-96
* fix/RS-56

Our grep command highlighted the matching branches and each matched phrase. Using the pipe operator, we passed the output of git branch into the grep.

If we typed the deletions manually for each branch, instead of using the full command, it would look something like this:

$ git branch -D FEAT/RS-123
Deleted branch FEAT/RS-123 (was 1b39b22).

$ git branch -D FIX/RS-456
Deleted branch FIX/RS-456 (was ea9973f).

$ git branch -D feat/RS-96
Deleted branch feat/RS-96 (was 6c114fb).

$ git branch -D fix/RS-56
Deleted branch fix/RS-56 (was 5a82faa).

We can now see that instead of a single command that takes advantage of pipes, we had to type 6 different commands, each of which has a standard output of its own – making it tougher to keep track of what was deleted, and what still needs to be cleaned up.

Passing data using pipes

Many resources exist on pipes and their usages, but it may help to visualize usage in the context of deleting this branch deletion command. In our case, the condensed data flow looks something like this:

git branch -> grep -iE 'FIX|FEAT' -> xargs git branch -D

Each side of our pipe has a “standard input” (STDIN) and “standard output” (STDOUT). The STDOUT is the result of running a command and is passed in as STDIN to the next command. In our flow:

git branch (STDOUT) ->
(STDIN) grep -iE 'FIX|FEAT' (STDOUT) ->
(STDIN) xargs git branch -D (STDOUT)

While this is an overly simplistic explanation of what is happening behind the scenes, it hopefully provides an idea of how commands and their outputs can be spliced together using pipes.