554

I'd like to clean up my local repository, which has a ton of old branches: for example 3.2, 3.2.1, 3.2.2, etc.

I was hoping for a sneaky way to remove a lot of them at once. Since they mostly follow a dot release convention, I thought maybe there was a shortcut to say:

git branch -D 3.2.*

and kill all 3.2.x branches.

I tried that command and it, of course, didn't work.

Nathaniel Ford
  • 20,545
  • 20
  • 91
  • 102
Doug
  • 6,831
  • 5
  • 19
  • 9
  • 38
    `git branch -D $(git branch | grep 3.2*)` - this worked for me. It deletes the branches whose name starts with "3.2". `grep` - pattern matching in the output (of `git branch` in this case). `$()` - means execute and place the result. `|` - chaining. – Eduard Aug 05 '18 at 09:37
  • 9
    Worth noting for those that don't know, that `-D` is a *force* delete, should use `-d` in most cases to be safer first. – redfox05 Feb 06 '19 at 17:25
  • This blog contains a short answer https://medium.com/@rajsek/deleting-multiple-branches-in-git-e07be9f5073c Just ```git branch | grep "" | xargs git branch -D``` much easier – SARAN SURYA Jan 25 '22 at 17:37

34 Answers34

503

Not with that syntax. But you can do it like this:

git branch -D 3.2 3.2.1 3.2.2

Basically, git branch will delete multiple branch for you with a single invocation. Unfortunately it doesn't do branch name completion. Although, in bash, you can do:

git branch -D `git branch | grep -E '^3\.2\..*'`
slebetman
  • 109,858
  • 19
  • 140
  • 171
  • 6
    The completion on `git branch -D/-d` works fine for me. Might want to update yours (maybe from the most recent git.git contrib directory). – Cascabel Sep 08 '10 at 23:04
  • 28
    Instead of `git branch | ...` you could use `$(git for-each-ref --format='%(refname:short)' refs/heads/3.*)`. It's longer, I know, but it's guaranteed to be suitable output, while `git branch` has pretty output with things like `*` and `->` (for symrefs) which can mess you up in scripts/one-liners. – Cascabel Sep 08 '10 at 23:05
  • 3
    Maybe I'm the only one with this issue, but I have `grep` aliased to always include the flag `--color=always` -- `git branch -D` was throwing `error: branch 'my_branch' not found.` until I ran without the color flag. – eebbesen Apr 08 '15 at 13:52
  • @eebbesen Did you disable it globally? I run into the same issue when running `git branch --merged ${1-$(current_branch)} | grep -v ${1-$(current_branch)} | xargs git branch -d` – qmmr Aug 10 '16 at 10:40
  • 5
    With brace expansion you could write `git branch -D 3.2{,.1,.2}` to delete all three branches https://www.gnu.org/software/bash/manual/html_node/Brace-Expansion.html – robstarbuck Jul 05 '17 at 10:10
  • @eebbesen : You can do git branch | grep --color=auto '' | xargs git branch -d – hsuk Jul 13 '17 at 15:22
  • To do the same thing using power-shell, you can run the following command: `PS> git branch -D ( ( git branch | Select-String -Pattern '3.*') | foreach{$_.ToString().Trim() } )` – Imtiaz Shakil Siddique Mar 18 '19 at 10:56
  • It only deleteds local though? Because I want to delte only local copies, not remote – John Demetriou Jan 11 '21 at 09:40
  • @JohnDemetriou Yes. `git branch -D` only deletes the local copy. If you ever need to delete the remote copy you'd need to do `git push origin --delete` – slebetman Jan 11 '21 at 09:55
  • Simple tip: You can use `git pull --prune` to remove local branches that were merged on the remote – Sebastien H. Jul 20 '21 at 10:11
  • `xargs` works fine too: `git branch | grep [options] | xargs git branch -D` – a_girl Jul 10 '23 at 18:29
330

You can use git branch --list to list the eligible branches, and use git branch -D/-d to remove the eligible branches.

One liner example:

git branch -d `git branch --list '3.2.*'`
50shadesofbae
  • 3,299
  • 1
  • 9
  • 10
  • When I try this, I get a bunch of error messages like `error: branch 'package.json' not found.`. It seems that the * is expanded too early, and it tries to delete a branch corresponding to the name of every file and directory. – Antimony Mar 26 '18 at 17:26
  • This works well! I am having problem using this as an alias with `gitconfig` though... – whomaniac May 29 '18 at 08:56
  • 31
    This answer needs to be higher in the list, super clean, works, no grep – jemiloii Jun 29 '18 at 19:02
  • 2
    One use case I found useful: If you use feature branch model, you can use `git branch -d ``git branch --merged master | grep -v master`` ` to delete branches that have been merged into master – 50shadesofbae Aug 21 '18 at 12:59
  • 2
    Nice that this one is easy to test first by just issuing `git branch --list '3.2.*'` – Will Jan 26 '19 at 01:21
  • I wonder if the `"Do not use output from git branch in scripts"` applies here. As technically, this is not grep'ing the output, but it's still using it recursively, and a one-liner recursive is still a 'script' – redfox05 Feb 06 '19 at 17:31
  • 28
    On windows `git branch -d (git branch --list '3.2.*').trim()` – Mattias Josefsson May 16 '19 at 11:38
  • On mac, I used `-D` instead of `-d` to make it work – Rannie Aguilar Peralta Dec 03 '19 at 01:16
  • 2
    @RannieAguilarPeralta -D delete is a force delete branch, this isn't a OS variation. See https://stackoverflow.com/a/2003515/5799029 – 50shadesofbae Jan 16 '20 at 16:36
  • 1
    This is the best answer especially for Windows users – d4c0d312 Jun 11 '20 at 10:09
  • I modified your command and deleted all the branches except `master` and `development`. Thanks a Ton – Shadman Akhtar Sep 30 '21 at 05:41
208

Well, in the worst case, you could use:

git branch | grep '3\.2' | xargs git branch -D
Boken
  • 4,825
  • 10
  • 32
  • 42
Carl Norum
  • 219,201
  • 40
  • 422
  • 469
  • 26
    This is pretty much the perfect method for anyone who uses a standardized prefix notation for branch names (e.g. "fix/..." or "feature/..."). – Haz Apr 29 '15 at 22:03
  • 10
    Simple and efficient! I'd recommend though running first without the `| xargs git branch -d` part to check what's actually going to be deleted. – mathielo Jul 19 '18 at 14:32
  • It's recommended not to `grep` the output of `git branch`, as its meant for reading, not parsing. Could change any time. use the `for-each-ref` together with the `--format` params, as suggested in other answers, and then combine with the suggestions in this answer. – redfox05 Feb 06 '19 at 17:34
  • Shouldn't that say, "in the *best* case" ? ;) – TTT Mar 04 '21 at 18:24
161
git branch  | cut -c3- | egrep "^3.2" | xargs git branch -D
  ^                ^                ^         ^ 
  |                |                |         |--- create arguments
  |                |                |              from standard input
  |                |                |
  |                |                |---your regexp 
  |                |
  |                |--- skip asterisk 
  |--- list all 
       local
       branches

EDIT:

A safer version (suggested by Jakub Narębski and Jefromi), as git branch output is not meant to be used in scripting:

git for-each-ref --format="%(refname:short)" refs/heads/3.2\* | xargs git branch -D

... or the xargs-free:

git branch -D `git for-each-ref --format="%(refname:short)" refs/heads/3.2\*`
gawi
  • 13,940
  • 7
  • 42
  • 78
  • 14
    Do not use `git branch` output for scripting. Use `git for-each-ref`. – Jakub Narębski Sep 09 '10 at 17:12
  • 1
    To delete tags with the @ symbol: `git for-each-ref --format="%(refname:short)" refs/tags/\*@\* | xargs git tag -d` – thaddeusmt Apr 06 '12 at 15:27
  • Has a typo. Should be "/3.2/*" not "/3.2\*". Also, appears you've copy pasted other answers into your own. – Max MacLeod Feb 27 '14 at 11:05
  • No typo here. From the man page: `If one or more patterns are given, only refs are shown that match against at least one pattern, either using fnmatch(3) or literally, in the latter case matching completely or from the beginning up to a slash` – gawi Mar 01 '14 at 00:02
  • Don't know if this has changed over time, but - this works for me without the "\*" but doesn't work with it. – GlyphGryph Apr 29 '16 at 19:38
  • @jakub i'd love to know why "Do not use git branch output for scripting. Use git for-each-ref" – danyamachine Aug 18 '16 at 17:18
  • @danyamachine: `git branch` output is meant for end user, and can change without warning / deprecation period. For example current branch might stop be marked with asterisk '\*' and start with Unicode bullet '•'. Or amount of indent might change. Or... This is not something theoretical - the output for *detached HEAD* in `git branch` **did** change. – Jakub Narębski Aug 18 '16 at 17:42
  • I feel like the `git branch` answer should be removed completely in favor of the `for-each-ref` answer. – Patrick Michaelsen May 28 '18 at 19:19
  • The exargs free approached worked great for me, but with -d. – redfox05 Feb 06 '19 at 17:25
  • 2
    Worth noting for those that don't know, that `-D` is a *force* delete, should use `-d` in most cases to be safer first. – redfox05 Feb 06 '19 at 17:25
47

Recently, I was looking for solution of same problem, finally i found one answer and it is working very well:

  1. Open the terminal, or equivalent.
  2. Type in git branch | grep " pattern " for a preview of the branches that will be deleted.
  3. Type in git branch | grep " pattern " | xargs git branch -D

This solution is awesome and if you want full explanation of each command and how it is working, its given here.

K J Gor
  • 750
  • 5
  • 17
37

To delete multiple branches based on a specified pattern do the following:

Open the terminal, or equivalent and type in following commands:

git branch | grep "<pattern>" (preview of the branches based on pattern)

git branch | grep "<pattern>" | xargs git branch -D (replace the <pattern> with a regular expression to match your branch names)

Remove all 3.2.x branches, you need to type

git branch | grep "3.2" | xargs git branch -D

That's all!

You are good to go!

Ankit Jindal
  • 3,672
  • 3
  • 25
  • 37
33

Use

git for-each-ref --format='%(refname:short)' 'refs/heads/3.2.*' |
   xargs git branch -D
Jakub Narębski
  • 309,089
  • 65
  • 217
  • 230
29

Maybe You will find this useful:

If You want to remove all branches that are not for example 'master', 'foo' and 'bar'

git branch -D `git branch | grep -vE 'master|foo|bar'`

grep -v 'something' is a matcher with inversion.

NHG
  • 5,807
  • 6
  • 34
  • 45
Adrian
  • 490
  • 5
  • 7
  • I personally like `-D` option compare to other answer. Thanks for the answer here @Adi. Solutions works for me. – AMIC MING May 03 '20 at 04:05
20

If you want to delete multiple branches for cleanup, this will work

 git branch -d branch1 branch2 branch3

also if you want to reflect the deletion action to remote, you can use this to push them to the origin

 git push origin --delete branch1 branch2 branch3
mcvkr
  • 3,209
  • 6
  • 38
  • 63
17

I put my initials and a dash (at-) as the first three characters of the branch name for this exact reason:

git branch -D `git branch --list 'at-*'`
Alan Tweedie
  • 317
  • 2
  • 5
17

Here is a general solution:

git branch | grep "<pattern>" | xargs git branch -D

I would suggest running the following command line before executing the above for a preview of the branches that will be deleted.

git branch | grep "<pattern>"

In this case

git branch | grep "^3\.2\..*" | xargs git branch -D
Francis Bacon
  • 4,080
  • 1
  • 37
  • 48
16

Keep "develop" and delete all others in local

    git branch | grep -v "develop" | xargs git branch -D 
Daniel
  • 840
  • 1
  • 8
  • 9
  • This is the best and easiest way! You can add more `grep -v` argument to exclude another branch like this: `git branch | grep -v "develop" | grep -v "master" | xargs git branch -D` – IrvanFza Mar 09 '21 at 22:37
13

If you're not limited to using the git command prompt, then you can always run git gui and use the Branch->Delete menu item. Select all the branches you want to delete and let it rip.

helmbert
  • 35,797
  • 13
  • 82
  • 95
Efpophis
  • 151
  • 1
  • 3
13

You can use git gui to delete multiple branches at once. From Command Prompt/Bash -> git gui -> Remote -> Delete branch ... -> select remote branches you want to remove -> Delete.

Terry Truong
  • 291
  • 3
  • 4
  • 3
    ...or use `Branch`->`Delete` in `git gui` if you want to delete local branches (as the OP asked). – Jpsy Aug 18 '20 at 09:59
13

Powershell Solution:

If you're running windows, you can use PowerShell to remove multiple branches at once...

git branch -D ((git branch | Select-String -Pattern '^\s*3\.2\..*') | foreach{$_.ToString().Trim()})
//this will remove all branches starting with 3.2.

git branch -D ((git branch | Select-String -Pattern 'feature-*') | foreach{$_.ToString().Trim()})
// this will delete all branches that contains the word "feature-" as a substring.

You can also fine tune how the pattern matching should work using Powershell's Select-String command. Take a look at powershell docs.

  • 1
    Thanks, was about to lookup alternatives for grep in powershell when I stumbled upon your solution here :-D Small remark though, if you reverse the order of commands, you only need to pipe once: `git branch --list feature-* | foreach { git branch -d $_.ToString().Trim() }` – Dirk S. Sep 07 '22 at 11:47
  • Here is my PowerShell solution, excluding main branch: ```git branch -l | % { if ($_ -ne "* main") { git branch -d $_.Trim() } }``` – Dan Jan 24 '23 at 21:33
  • 1
    And this is another one, just for record: ```git branch -d $(git branch | findstr ".*").Trim()``` – Dan Jan 24 '23 at 21:49
12

If you really need clean all of your branches, try

git branch -d $(git branch)

It will delete all your local merged branches except the one you're currently checking in.

It's a good way to make your local clean

Yulin
  • 609
  • 7
  • 9
  • This worked well enough for me. It left two branches except the one I was one which I then removed by using the same command but using a capital "-D" instead of "-d". I got a few errors about git not finding files but the branches were deleted. – Lurifaxel Dec 17 '18 at 12:30
  • This works for me. The reason you might be getting error with "-d" because it doesn't delete those branches that aren't merged. While, on the other hand, "-D" flag forcefully delete every branch despite its status – Shamoon97 Jul 04 '23 at 06:29
7

For pure souls who use PowerShell here the small script git branch -d $(git branch --list '3.2.*' | %{$_.Trim() })

codevision
  • 5,165
  • 38
  • 50
7

TL;DR

git branch -D $(git branch | grep '3\.2\..*')

Explanation

  1. git branch lists all the branches on your local system.
  2. grep '3\.2\..*' uses pattern matching to find all files in the current working directory starting with 3.2.. Using \ to escape . as it's a special character for grep.
  3. git branch | grep '3\.2\..*' will pass all the github branch names to the grep command which will then look for branch names starting with the string within the list supplied.
  4. $(git branch | grep '3\.2\..*') Anything enclosed within $() will run it as a separate shell command whose result can then be passed on to a separate command. In our case, we would want the list of files found to be deleted.
  5. git branch -D $(git branch | grep '3\.2\..*') This just does what is explained above in Point 4.
Saurish Kar
  • 576
  • 7
  • 13
5

I made a small function that might be useful based off of the answer provided by @gawi (above).

removeBranchesWithPrefix() {
  git for-each-ref --format="%(refname:short)" refs/heads/$1\* | xargs git branch -d
}

Add that to your .bash_profile and restart your terminal. Then you can call from command-line like this:

removeBranchesWithPrefix somePrefix

Note

I have it currently setup for a soft delete, which means it won't delete the branches unless they've already been merged. If you like to live on the edge, change -d to -D and it will delete everything with the prefix regardless!

Logan
  • 52,262
  • 20
  • 99
  • 128
5

git branch -d branch1 branch2 branch3 already works, but will be faster with Git 2.31 (Q1 2021).
Before, when removing many branches and tags, the code used to do so one ref at a time.
There is another API it can use to delete multiple refs, and it makes quite a lot of performance difference when the refs are packed.

See commit 8198907 (20 Jan 2021) by Phil Hord (phord).
(Merged by Junio C Hamano -- gitster -- in commit f6ef8ba, 05 Feb 2021)

8198907795:use delete_refs when deleting tags or branches

Acked-by: Elijah Newren
Signed-off-by: Phil Hord

'git tag -d'(man) accepts one or more tag refs to delete, but each deletion is done by calling delete_ref on each argv.
This is very slow when removing from packed refs.
Use delete_refs instead so all the removals can be done inside a single transaction with a single update.

Do the same for 'git branch -d'(man).

Since delete_refs performs all the packed-refs delete operations inside a single transaction, if any of the deletes fail then all them will be skipped.
In practice, none of them should fail since we verify the hash of each one before calling delete_refs, but some network error or odd permissions problem could have different results after this change.

Also, since the file-backed deletions are not performed in the same transaction, those could succeed even when the packed-refs transaction fails.

After deleting branches, remove the branch config only if the branch ref was removed and was not subsequently added back in.

A manual test deleting 24,000 tags took about 30 minutes using delete_ref.
It takes about 5 seconds using delete_refs.

VonC
  • 1,262,500
  • 529
  • 4,410
  • 5,250
3

You might like this little item... It pulls the list and asks for confirmation of each item before finally deleting all selections...

git branch -d `git for-each-ref --format="%(refname:short)" refs/heads/\* | while read -r line; do read -p "remove branch: $line (y/N)?" answer </dev/tty; case "$answer" in y|Y) echo "$line";; esac; done`

Use -D to force deletions (like usual).

For readability, here is that broken up line by line...

git branch -d `git for-each-ref --format="%(refname:short)" refs/heads/\* |
    while read -r line; do 
        read -p "remove branch: $line (y/N)?" answer </dev/tty;
        case "$answer" in y|Y) echo "$line";; 
        esac; 
    done`

here is the xargs approach...

git for-each-ref --format="%(refname:short)" refs/heads/\* |
while read -r line; do 
    read -p "remove branch: $line (y/N)?" answer </dev/tty;
    case "$answer" in 
        y|Y) echo "$line";; 
    esac; 
done | xargs git branch -D

finally, I like to have this in my .bashrc

alias gitselect='git for-each-ref --format="%(refname:short)" refs/heads/\* | while read -r line; do read -p "select branch: $line (y/N)?" answer </dev/tty; case "$answer" in y|Y) echo "$line";; esac; done'

That way I can just say

gitSelect | xargs git branch -D.
Sir.Nathan Stassen
  • 1,843
  • 4
  • 21
  • 25
Chaos Crafter
  • 640
  • 5
  • 7
3

it works correctly for me:

git branch | xargs git branch -d

git branch | xargs git branch -D

delete all local branches

Suraj Rao
  • 29,388
  • 11
  • 94
  • 103
velastiqui
  • 79
  • 1
  • 4
2

Use the following command to remove all branches (checked out branch will not be deleted).

git branch | cut -d '*' -f 1 | tr -d " \t\r" | xargs git branch -d

Edit: I am using a Mac Os

ILYAS_Kerbal
  • 1,369
  • 11
  • 18
2

If you have installed Git GUI, which is a default add-on for Windows, then it's the simplest. You can use ctrl to choose multiple branches and delete them with one click.

peiz
  • 21
  • 2
1

You can use this command: git branch -D $(printf "%s\n" $(git branch) | grep '3.2')

Hieu Dang
  • 343
  • 3
  • 11
  • Welcome to StackoverFlow. Please [take the tour](https://stackoverflow.com/tour), [read about how to ask good questions](https://stackoverflow.com/help/how-to-ask) and learn [how to create a Minimal, Complete and Verifiable Example](https://stackoverflow.com/help/mcve). – Gaurang Dave Mar 29 '18 at 06:56
1

If you had all the branches to delete in a text file (branches-to-del.txt) (one branch per line), then you could do this to delete all such branches from the remote (origin): xargs -a branches-to-del.txt git push --delete origin

code4kix
  • 3,937
  • 5
  • 29
  • 44
1

My specific case was not addressed, so I'm making a new answer...

Scenario:

  • Freshly cloned repo
  • No local branches created
  • Many remote branches (over 100 in my case)
  • I want to delete all the feature branches, feature/myfeature , from the remote

This is the command that I got to work:

git branch  -a | cut -c3- | grep 'origin\/feature' | sed 's/remotes\/origin\///' | xargs git push origin --delete

Thanks to @gwai for putting me on the right track.

David Roussel
  • 5,788
  • 1
  • 30
  • 35
1

Delete local branches with PowerShell

There many answers for BASH shell. Here is a variation for PowerShell.

Search the local branch and use Select-String to filter the list. Join the array into a space delimited string for a list of selected branches. Concatenate the branches to the git delete branch command. Invoke the expression.

iex "git branch -d$((git branch | Select-String MYSEARCHExpression) -join '')"
user2205317
  • 109
  • 2
0

I you're on windows, you can use powershell to do this:

 git branch | grep 'feature/*' |% { git branch -D $_.trim() }

replace feature/* with any pattern you like.

Mo Valipour
  • 13,286
  • 12
  • 61
  • 87
  • 8
    grep is a not recognized cmdlet for me... so I've changed for this git branch | where{$_.Trim().StartsWith("bug")} | %{ git branch -D $_.Trim() } and worked! – Alex Mar 03 '17 at 22:59
0

I just cleaned up a large set of obsolete local/remote branches today.

Below is how I did it:

1. list all branch names to a text file:

git branch -a >> BranchNames.txt

2. append the branches I want to delete to command "git branch -D -r":

git branch -D -r origin/dirA/branch01 origin/dirB/branch02 origin/dirC/branch03 (... append whatever branch names)

3. execute the cmd

And this one works so much faster and reliable than "git push origin --delete".

This may not be the most smart way as listed in other answers, but this one is pretty straight forward, and easy to use.

RainCast
  • 4,134
  • 7
  • 33
  • 47
-1

As in Git all the branches are nothing by references to the git repo, why don't you just delete the branches going to .git/ref and then if anything is left out which is not interesting in the repository will automatically be garbage collected so you don't need to bother.

Debajit
  • 7
  • 3
-1

If you are using Fish shell, you can leverage the string functions:

git branch -d (git branch -l "<your pattern>" | string trim)

This is not much different from the Powershell options in some of the other answers.

mdiin
  • 427
  • 6
  • 12
-3

git branch -D <branchName>

Aakash Pahuja
  • 469
  • 4
  • 10
-4

You can remove all the branches removing all the unnecessary refs:

rm .git/refs/heads/3.2.*

Artur Owczarek
  • 1,146
  • 1
  • 11
  • 22
  • 3
    Downvoted for two reasons: 1. it uses an implementation detail (the fact that current versions of Git store the branches as files in a certain directory). This can change in future versions rendering the answer invalid. 2. It doesn't work if the repository is located in a [separate directory](https://git-scm.com/docs/git-init#git-init---separate-git-dirltgitdirgt). – axiac Oct 12 '17 at 09:17
  • Also, this produces very unexpected results if you run this on a packed repository (`git gc`). Don't do that. – Matthieu Moy Feb 05 '18 at 13:14