1470

Is there a simple way to delete all tracking branches whose remote equivalent no longer exists?

Example:

Branches (local and remote)

  • master
  • origin/master
  • origin/bug-fix-a
  • origin/bug-fix-b
  • origin/bug-fix-c

Locally, I only have a master branch. Now I need to work on bug-fix-a, so I check it out, work on it, and push changes to the remote. Next I do the same with bug-fix-b.

Branches (local and remote)

  • master
  • bug-fix-a
  • bug-fix-b
  • origin/master
  • origin/bug-fix-a
  • origin/bug-fix-b
  • origin/bug-fix-c

Now I have local branches master, bug-fix-a, bug-fix-b. The Master branch maintainer will merge my changes into master and delete all branches he has already merged.

So the current state is now:

Branches (local and remote)

  • master
  • bug-fix-a
  • bug-fix-b
  • origin/master
  • origin/bug-fix-c

Now I would like to call some command to delete branches (in this case bug-fix-a, bug-fix-b), which are no longer represented in the remote repository.

It would be something like the existing command git remote prune origin, but more like git local prune origin.

Andrew Spencer
  • 12,045
  • 4
  • 24
  • 44
Mailo Světel
  • 17,483
  • 5
  • 27
  • 40

37 Answers37

1607

git remote prune origin prunes tracking branches not on the remote.

git branch --merged lists branches that have been merged into the current branch.

xargs git branch -d deletes branches listed on standard input.

Be careful deleting branches listed by git branch --merged. The list could include master or other branches you'd prefer not to delete.

To give yourself the opportunity to edit the list before deleting branches, you could do the following in one line:

git branch --merged >/tmp/merged-branches && \
  vi /tmp/merged-branches && xargs git branch -d </tmp/merged-branches
SomeGuyOnAComputer
  • 3,408
  • 3
  • 27
  • 52
aubreypwd
  • 16,557
  • 2
  • 13
  • 13
  • 19
    The first line of the merged branches is `* master` on my system. The following command worked for me: `git branch -d $(git branch --merged |tail -n +2)` – Trendfischer Jun 03 '15 at 16:31
  • 113
    If I'm on `develop` then `git branch --merged` includes `master`! You probably (definitely!) don't want to delete that. Also I think it should be `git branch -d` where lowercase `-d` means "safe delete" e.g. only delete if merged. – thom_nic Jun 09 '15 at 14:33
  • 14
    It seems an improved solution is provided [there](http://stackoverflow.com/a/16906759/490018). – Sergey Brunov Mar 24 '16 at 09:58
  • 43
    Removed merged is useful, but not the same as "remove branches not on remote." – dlsso Jul 15 '16 at 19:12
  • 2
    Somehow for me this also tries to delete branches that have the same names as all my root directories and files. Any way to exclude those? – Bono Aug 19 '16 at 07:37
  • This just deleted master for me. Perhaps the advice should be `git checkout master; git branch...`? – Alex Oct 13 '16 at 09:45
  • Please update this answer git branch -d $(git branch --merged) should not be used as it deletes all merged branches including master... this is not the intended behavior asked by the OP... Ideally branches which have been deleted in the remote should be the only ones deleted – tsar2512 Nov 23 '16 at 14:38
  • 1
    This does not remove deleted (without merging) branches. It also removes master. – BlueRaja - Danny Pflughoeft Dec 02 '16 at 17:28
  • 19
    Just use grep to exclude master: `git branch --merged | grep -v "master" >/tmp/merged-branches && vi /tmp/merged-branches && xargs git branch -d – geniass Feb 27 '18 at 12:42
  • 1
    To delete all branches but "master" and "develop" you can use: `git branch --merged | sed '/^\** *develop$/d' | sed '/^\** *master$/d' | xargs git branch -d` – Guto Marrara Marzagao Jan 22 '19 at 21:47
  • 1
    You can also use moreutils `vipe` to do the same as `git branch --merged >/tmp/merged-branches && vi /tmp/merged-branches && xargs git branch -d – Joshua Klein Jun 28 '19 at 18:54
  • Why not deleting the temp file at the end ? ``git branch --merged >/tmp/merged-branches && vi /tmp/merged-branches && xargs git branch -d – lasofivec Sep 17 '19 at 09:33
  • 2
    If this can help, here is my favorite one-liner without intermediate files: `git branch --merged | egrep -v "(^\*|master|develop)" | xargs git branch -d` – Sÿl Sep 02 '20 at 13:37
  • My more aggressive version, if it helps someone: `git branch --format "%(refname:short)" >/tmp/merged-branches && vim /tmp/merged-branches && xargs git branch -D – Infinity Sep 28 '20 at 14:25
  • Consider an explicit branch - eg. `git branch --merged origin/develop` - so that this command is agnostic to the current checkout. – user2864740 Oct 08 '20 at 17:15
  • Use either the command line or the git bash to run these commands. The built in terminals might not work. – Upulie Han Oct 16 '20 at 11:47
  • @schwobaseggl Hi there, future me: When will you finally make an alias command for this, huh? – schwobaseggl Dec 18 '20 at 09:41
802

After the command

git fetch -p

removes the remote references, when you run

git branch -vv

it will show 'gone' as the remote status. For example,

$ git branch -vv
  master                 b900de9 [origin/master: behind 4] Fixed bug
  release/v3.8           fdd2f4e [origin/release/v3.8: behind 2] Fixed bug
  release/v3.9           0d680d0 [origin/release/v3.9: behind 2] Updated comments
  bug/1234               57379e4 [origin/bug/1234: gone] Fixed bug

So you can write a simple script to remove local branches that have gone remotes:

git fetch -p && for branch in $(git branch -vv | grep ': gone]' | awk '{print $1}'); do git branch -D $branch; done

Note that the above uses the "porcelain" command git branch to get the upstream status.

Another way to obtain this status is to use the "plumbing" command git for-each-ref with the interpolation variable %(upstream:track), which will be [gone] just like above.

This approach is somewhat safer, because there is no risk of accidentally matching on part of the commit message.

git fetch -p && for branch in $(git for-each-ref --format '%(refname) %(upstream:track)' refs/heads | awk '$2 == "[gone]" {sub("refs/heads/", "", $1); print $1}'); do git branch -D $branch; done
jason.rickman
  • 9,714
  • 1
  • 18
  • 13
  • 9
    @KrzysztofWende - not on Solaris and some BSDs and some OS X :) – jww Jun 11 '16 at 23:21
  • 5
    It looks like this will also remove any branch that has "gone" in the last commit message. – dlsso Jul 15 '16 at 19:23
  • 14
    @dlsso If the last commit message contains the string ": gone]" then yes it will be removed as well. You can make it more robust at the expense of simplicity by having an additional awk/gawk to strip off the commit message. `git branch -vv | gawk '{print $1,$4}' | grep 'gone]' | gawk '{print $1}'` – jason.rickman Jul 18 '16 at 14:22
  • The script in the answer worked for me but with an odd twist. It returned all of the file and folder names in addition to branch names. I ran this in the bash shell that was included with git (downloaded from Atlassian along with SourceTree). I think it is some kind of quirk in the shell because the script looks perfectly fine to me. But it would interesting to know if anybody else saw this. – rhaben Aug 22 '16 at 23:40
  • 2
    In reply to my previous comment (question), the current branch has \* as the first field. If it happens to also be in the list of "gone" branches, $1 will be assigned \* and will be interpreted as a filespec with awk spitting out file and folder names. I eliminated the grep expression and had awk do all of the filtering: `awk '/: gone]/{if ($1!="*") print $1}'`. This now works as expected. – rhaben Aug 23 '16 at 17:29
  • it would be better to do `git branch -d` to delete a fully merged branch – Timo Sep 09 '16 at 11:13
  • `git fetch -p &&git branch -vv|grep ': gone]'|awk '{print $1}'|xargs git branch -D` – Frederic Yesid Peña Sánchez Sep 13 '16 at 14:54
  • I tried to add the script to gitconfig file as an alias but the after executing the alias it return `fatal: Invalid refspec ': disparue]' ` – famas23 May 19 '18 at 11:14
  • @ahmedbhs what does your complete alias line look like? – jason.rickman May 21 '18 at 19:21
  • I addede this line into gitconfig ```test = 'git fetch -p && for branch in `git branch -vv | grep ': gone]' | awk '{print $1}'`; do git branch -D $branch; done'``` then I got this error when I try to execute `git test` `fatal: Invalid refspec ': gone]'` – famas23 May 22 '18 at 11:08
  • 6
    @ahmedbhs since the command uses single quote ' you need to use double quote " to surround the entire command. Also, git aliases that are shell commands (like this one) require ! at the beginning. This works for me: `test = "!git fetch -p && for branch in \`git branch -vv | grep ': gone]' | awk '{print $1}'\`; do git branch -D $branch; done"` – jason.rickman May 24 '18 at 17:40
  • Can you explain to me the story of adding `!` to the bash command, any online reference that explain the trick plz – famas23 Jun 18 '18 at 12:38
  • Here's a more definitive but less informative source: https://git-scm.com/book/en/v2/Git-Basics-Git-Aliases – jason.rickman Jun 18 '18 at 16:12
  • Here's a more informative but less definitive source: https://www.atlassian.com/blog/git/advanced-git-aliases – jason.rickman Jun 18 '18 at 16:13
  • 2
    my version: ```git branch -vv | grep ': gone]' | awk '{print $1}' | xargs -n1 echo git branch -d``` – fiorentinoing Sep 13 '18 at 14:08
  • 2
    As mentioned by @fiorentinoing, I would rather use `-d` than `-D`, in order to keep not-yet-merged branches that might still hold some valuable, albeit possibly experimental, code. I'll add to the bikeshedding here with my own spin of it: `git branch -v|grep gone|awk '{print $1}'| xargs git branch -d` – Marcello Romani Dec 31 '18 at 15:12
  • How about using "cut" to remove the * before the checked-out branch? I.e. `git branch -vv | cut -c 3- | gawk '{print $1,$4}' | grep 'gone]' | gawk '{print $1}'`? – Robin Jan 18 '19 at 10:43
  • No, this still doesn't work if the second word of the commit comment is "gone]". – Robin Jan 18 '19 at 11:00
  • 1
    @MarcelloRomani use of `-d` and `-D` depends on context: git doesn't detect merged branches via "squash and merge" in GH. – Alex Gyoshev Aug 16 '19 at 16:09
  • Yes, but it would require that the develop or master branch be tracking a remote branch that was deleted. With typical develop/master workflows, this shouldn't happen. – jason.rickman Nov 25 '19 at 15:15
  • 1
    @jason.rickman, more robust - and more efficient - is to filter in `awk` directly: `git branch -vv | awk '$4 = "gone]" {print $1}'`. – Toby Speight Mar 05 '20 at 16:31
  • Fish shell version: `git fetch -p && for branch in (git for-each-ref --format '%(refname) %(upstream:track)' refs/heads | awk '$2 == "[gone]" {sub("refs/heads/", "", $1); print $1}'); git branch -D $branch; end` – Kosta Sep 16 '20 at 15:13
  • I've put together a `bash` snippet, hope it can be useful to others as well. It `dry-run`s by default, requires `--delete` to actually remove branches: https://github.com/marcelloromani/scratchpad/blob/master/bash_profile_snippets/git_delete_gone_branches.sh – Marcello Romani Jan 21 '21 at 15:32
  • thank you, this is the only answer here that cleaned up my branches on OS X – c_breeez May 07 '21 at 12:59
371

Most of these answers do not actually answer the original question. I did a bunch of digging and this was the cleanest solution I found. Here is a slightly more thorough version of that answer:

  1. Check out your default branch. Usually git checkout master
  2. Run git fetch -p && git branch -vv | awk '/: gone]/{print $1}' | xargs git branch -d

Explanation:

Works by pruning your tracking branches then deleting the local ones that show they are "gone" in git branch -vv.

Notes:

If your language is set to something other than English you will need to change gone to the appropriate word. Branches that are local only will not be touched. Branches that have been deleted on remote but were not merged will show a notification but not be deleted on local. If you want to delete those as well change -d to -D.

dlsso
  • 5,303
  • 1
  • 16
  • 29
  • 6
    should add LANG=en_US before git branch to force english : git fetch --prune && LANG=en_US git branch -vv | awk '/: gone]/{print $1}' | xargs git branch -d – Mohamed EL HABIB Jul 12 '17 at 04:55
  • 3
    I'd add `git checkout master && ...` at the beginning of the command. – iarroyo Nov 02 '17 at 15:15
  • 5
    This is dangerous when you're on a branch that's supposed to be deleted - in that case the first column is '\*', which is then passed to xargs. To improve this, add strip the '*' character before passing the output to awk: sed -e 's/^\*//' – meeee Jan 19 '18 at 09:15
  • @MohamedELHABIB This doesn't work on my machine, and I think the better approach is to adjust the original command to your own language. Thanks for pointing it out though, I will update my answer. – dlsso Jan 20 '18 at 14:23
  • @iarroyo Not everyone's default is `master` so that exact suggestion isn't safe, but yes, I forgot to mention it should be run from your default branch so I will do that. Thanks! – dlsso Jan 20 '18 at 14:30
  • @meeee Right, but we don't want people to run this at all when they're on a branch that should be deleted. Running this from the default branch is the best solution because it addresses the root cause, I just forgot to mention it. Thanks for pointing it out! – dlsso Jan 20 '18 at 14:46
  • 1
    @dlsso Why do we not want people to run it when they're on a branch that should be deleted? Git just warns about that and skips the branch. In this case, switching to another branch and re-running solves the problem. If you're making people _always_ switch to master, you make them do unnecessary work in case they're on a non-master branch that shouldn't be deleted. Also, I'd say the command filtering out the '*' is safer - it's easy to copy & paste and not think about what 'default branch' means. – meeee Jan 21 '18 at 12:36
  • @meeee Because it doesn't work. I want the instructions to be simple, and always work. To your other points, checking out a branch takes literally 2 seconds, and I think people who ignore the instructions would benefit from the learning experience. – dlsso Jan 29 '18 at 03:19
  • 2
    @dlsso These instructions work for most people, but not for everyone (see comment above). Saying that people should learn from an accidentally deleted branch (that they might not easily know how to restore) is patronizing, when you can make the instructions more safe. You, yourself wrote above 'that exact suggestion isn't safe'. I still argue that safety is more important than always working. It's better for people to learn from 'not working' instead of learning from a deleted branch. – meeee Feb 01 '18 at 15:17
  • 2
    @meeee The instructions *do* work for everyone, and the rest is just a difference in philosophy. I chose to prioritize a working answer over safety for those who ignore instructions because I see stack overflow as a place to learn, not a place to publish a product. And I don't know about you, but I'd rather learn to follow instructions by deleting something that's a `git checkout` away than `rm -rf`ing a system directory. :) – dlsso Feb 03 '18 at 01:58
  • To switch to a head branch first: `git remote show origin | grep "HEAD branch" | cut -d ":" -f 2 | xargs git checkout` – Rafał Cieślak Jul 04 '18 at 09:31
  • 11
    Careful! There is an edge case that will result in deleting all your local branches: If you are currently on a branch that was deleted on remote the output of `git branch -vv` will start with an asterisk which will in the end result in executing `git branch -d *`. Here is a patched version which will ignore lines with asterisk: `git branch -vv | grep ': gone]'| grep -v "\*" | awk '{ print $1; }' | xargs -r git branch -d` – kcm Sep 25 '18 at 08:45
  • 1
    @kcm That can only happen if you skip step 1. – dlsso Sep 25 '18 at 14:51
  • 2
    @disso your default branch could be deleted on remote too. I wouldn't rely on that. As soon as an asterisk appears in the branch list, all your local branches will get deleted. – kcm Sep 25 '18 at 16:02
  • @kcm Not in any system I'm aware of. Github and Bitbucket certainly won't let you. The point of step 1 is to make sure no one tries to remove a branch they are on, and I still think it's foolproof. If you think you can make it clearer let me know, but I think "checkout default" is easier to read than "checkout a branch that you know is present on your remote." – dlsso Sep 26 '18 at 16:32
  • I've been on projects where the default branch has changed. That would also trigger the situation @kcm is talking about. – Adam Millerchip Jul 14 '20 at 14:03
  • 1
    @AdamMillerchip Still only happens if you skip step 1. – dlsso Jul 18 '20 at 20:13
  • You can set the default branch locally. Safety is important and a what? 20 character change to your answer isn't going to change its clarity or usefulness. Quite the opposite. If this is a "difference of philosophy", remind me to check with my programmers about their "philosophy" before I hire them for a job :p – DylanYoung Jul 22 '20 at 18:28
278

I wouldn't normally answer a question that already has 16 answers, but all the other answers are wrong, and the right answer is so simple. The question says, "Is there a simple way to delete all tracking branches whose remote equivalent no longer exists?"

If "simple" means deleting them all in one go, not fragile, not dangerous, and without reliance on tools that not all readers will have, then the right answer is: no.

Some answers are simple, but they don't do what was asked. Others do what was asked, but are not simple: all rely on parsing Git output through text-manipulation commands or scripting languages, which may not be present on every system. On top of that, most of the suggestions use porcelain commands, whose output is not designed to be parsed by script ("porcelain" refers to the commands intended for human operation; scripts should use the lower-level "plumbing" commands).

Further reading:


If you want to do this safely, for the use case in the question (garbage-collect tracking branches which have been deleted on the server but still exist as local branches) and with high-level Git commands only, you have to

  • git fetch --prune (or git fetch -p, which is an alias, or git prune remote origin which does the same thing without fetching, and is probably not what you want most of the time).
  • Note any remote branches that are reported as deleted. Or, to find them later on, git branch -v (any orphaned tracking branch will be marked "[gone]").
  • git branch -d [branch_name] on each orphaned tracking branch

(which is what some of the other answers propose).

If you want to script a solution, then for-each-ref is your starting point, as in Mark Longair's answer here and this answer to another question, but I can't see a way to exploit it without writing a shell script loop, or using xargs or something.


Background explanation

To understand what's happening, you need to appreciate that, in the situation of tracking branches, you have not one branch, but three. (And recall that "branch" means simply a pointer to a commit.)

Given a tracking branch feature/X, the remote repository (server) will have this branch and call it feature/X. Your local repository has a branch remotes/origin/feature/X which means, "This is what the remote told me its feature/X branch was, last time we talked," and finally, the local repository has a branch feature/X which points to your latest commit, and is configured to "track" remotes/origin/feature/X, meaning that you can pull and push to keep them aligned.

At some point, someone has deleted the feature/X on the remote. From that moment, you are left with your local feature/X (which you probably don't want any more, since work on feature X is presumably finished), and your remotes/origin/feature/X which is certainly useless because its only purpose was to remember the state of the server's branch.

And Git will let you automatically clean up the redundant remotes/origin/feature/X -- that's what git fetch --prune does -- but for some reason, it doesn't let you automatically delete your own feature/X... even though your feature/X still contains the orphaned tracking information, so it has the information to identify former tracking branches that have been fully merged. (After all, it can give you the information that lets you do the operation by hand yourself.)

Andrew Spencer
  • 12,045
  • 4
  • 24
  • 44
  • 3
    This is a much safer answer. In addition, it will work if you use a "Squash and Merge" workflow, unlike the selected answer. – Jake Levitt May 22 '18 at 13:33
  • 5
    This really only answers the easy part of the question "how to find gone branches" (and that with the same command as already posted by jason.rickman in 2015) but then tells you to delete all the branches manually which is exactly what the OP doesn't want to do. – Voo Nov 27 '18 at 09:37
  • 6
    @Voo That's the point of the answer: not to tell you how to do it (that's just a bonus) but to tell you that the answer is that there is no easy, simple way to do it. Which is the correct answer to the question as it was formulated. – Andrew Spencer Nov 27 '18 at 13:12
  • 2
    @Andrew It just seemed very unlikely that if you have a porcelain command that does exactly what you want, you couldn't use a plumbing command to get the same output reliably. I did ask a question about this and got [an answer](https://stackoverflow.com/questions/53503591/git-branch-status-via-plumbing-command?noredirect=1#comment93879166_53503591) in less than an hour. Probably should post an answer (#17?) along those lines. – Voo Nov 27 '18 at 18:05
  • @Voo Absolutely, and I did look at the plumbing commands, and found `for-each-ref`, but couldn't figure out a way to pass the output to a branch-deletion command without OS-specific tools like a looping script or xargs. Indeed I'm convinced the sense of the question was, "Does Git itself provide a [porcelain] command to do this in 1 line?" and it doesn't (though IMO it should). – Andrew Spencer Nov 28 '18 at 12:35
  • @Voo p.s. updated answer to clarify the pb with porcelain, and link to your question. – Andrew Spencer Nov 28 '18 at 12:44
  • I think you're wrong, there is a simple way, this answer :D – Davos Jun 03 '19 at 07:19
  • 1
    "If you want to do this safely, for the use case in the question.." - which negates most claims of the first paragraph. "[Git] can give you the information that lets you do the operation by hand yourself" - we're programmers, so given the information as a list (which is shown) the task is still simple (eg. `xargs`). There is also `git alias` to simplify a number of cases. – user2864740 Jun 13 '19 at 17:01
  • 4
    @user2864740 Some readers may consider that writing a small bash script falls within their definition of "simple", and that's a perfectly defensible position, but I gave my own interpretation of "simple" in the 2nd paragraph and the rest of the answer is consistent with it. And in defense of my admittedly restrictive interpretation, not all Git users have `xargs` or bash, and they probably aren't here looking for a micro-coding challenge, so much as a quick answer they can apply safely without distracting themselves further from their real goal. – Andrew Spencer Jun 14 '19 at 09:51
  • 1
    I think using Git the answer to the question "is there a simple way to..." is pretty much always no. – Neutrino Oct 14 '20 at 12:06
62

Windows Solution

For Microsoft Windows Powershell:

git checkout master; git remote update origin --prune; git branch -vv | Select-String -Pattern ": gone]" | % { $_.toString().Trim().Split(" ")[0]} | % {git branch -d $_}

Explaination

git checkout master switches to the master branch

git remote update origin --prune prunes remote branches

git branch -vv gets a verbose output of all branches (git reference)

Select-String -Pattern ": gone]" gets only the records where they have been removed from remote.

% { $_.toString().Trim().Split(" ")[0]} get the branch name

% {git branch -d $_} deletes the branch

chris31389
  • 5,798
  • 2
  • 44
  • 55
  • 3
    Thanks for this, though I had to add a `.Trim()` after `.toString()` in order to remove two spaces before the branch name. – Matthew Apr 12 '18 at 15:42
  • 2
    Thanks for this command. I had to change the `git branch -d` to `git branch -D` else I get the error the branch is not fully merged. – markieo May 23 '19 at 07:51
  • 2
    @markieo You probably know this already, but for anyone else - `git branch -D` is **destructive** and will delete local work that you have not yet pushed. `-d` is always safe, just be careful with `-D`. – Nate Barbettini Oct 24 '19 at 22:20
59

I found the answer here: How can I delete all git branches which have been merged?

git branch --merged | grep -v "\*" | xargs -n 1 git branch -d

Make sure we keep master

You can ensure that master, or any other branch for that matter, doesn't get removed by adding another grep after the first one. In that case you would go:

git branch --merged | grep -v "\*" | grep -v "YOUR_BRANCH_TO_KEEP" | xargs -n 1 git branch -d

So if we wanted to keep master, develop and staging for instance, we would go:

git branch --merged | grep -v "\*" | grep -v "master" | grep -v "develop" | grep -v "staging" | xargs -n 1 git branch -d

Make this an alias

Since it's a bit long, you might want to add an alias to your .zshrc or .bashrc. Mine is called gbpurge (for git branches purge):

alias gbpurge='git branch --merged | grep -v "\*" | grep -v "master" | grep -v "develop" | grep -v "staging" | xargs -n 1 git branch -d'

Then reload your .bashrc or .zshrc:

. ~/.bashrc

or

. ~/.zshrc
Community
  • 1
  • 1
karlingen
  • 11,886
  • 5
  • 37
  • 65
40

The pattern matching for "gone" in most of the other solutions was a little scary for me. To be safer, this uses the --format flag to pull out each branch's upstream tracking status.

I needed a Windows-friendly version, so this deletes all branches that are listed as "gone" using Powershell:

git branch --list --format "%(if:equals=[gone])%(upstream:track)%(then)%(refname:short)%(end)" | 
    ? { $_ -ne "" } | 
    % { git branch -D $_ }

The first line lists the name of local branches whose upstream branch is "gone". The next line removes blank lines (which are output for branches that aren't "gone"), then the branch name is passed to the command to delete the branch.

Patrick Quirk
  • 21,498
  • 1
  • 51
  • 85
  • 7
    The `--format` option seems to be fairly new; I needed to upgrade git from 2.10.something to 2.16.3 to get it. This is my modification for Linux-ish systems: `git branch --list --format "%(if:equals=[gone])%(upstream:track)%(then)%(refname)%(end)" | sed 's,^refs/heads/,,' | grep . | xargs git branch -D` – bxm Mar 27 '18 at 15:01
  • 3
    This is the best solution so far. One suggestion is to use `refname:short`. Then you can delete the line `% { $_ -replace '^refs/heads/', '' }` – ioudas Jul 18 '18 at 05:06
  • 3
    This is a great solution for windows. I am using it like this cause it is more readable `git branch --list --format "%(if:equals=[gone])%(upstream:track)%(then)%(refname:short)%(end)" | where { $_ -ne "" } | foreach { git branch -d $_ }` Also probably a good idea to use `-d` instead of `-D`. Force delete should not be necessary for branches that are no longer on remote. – Rubanov Sep 04 '19 at 08:14
  • 1
    While obvious to some of us, probably worth mentioning that you should be running "git remote update origin --prune" first. – MattyMatt Sep 18 '20 at 17:10
33

Remove all branches that have been merged into master, but don't try to remove master itself:

git checkout master && git pull origin master && git fetch -p && git branch -d $(git branch --merged | grep master -v)

or add an alias:

alias gitcleanlocal="git checkout master && git pull origin master && git fetch -p && git branch -d $(git branch --merged | grep master -v)"

Explanation:

git checkout master checkout master branch

git pull origin master ensure local branch has all remote changes merged

git fetch -p remove references to remote branches that have been deleted

git branch -d $(git branch master --merged | grep master -v) delete all branches that have been merged into master, but don't try to remove master itself

cs01
  • 4,081
  • 24
  • 24
  • 3
    One note, this is very helpful but it will also remove those branches that never have been pushed to the remote. It is safer to only list differences and then copy what you really want to delete into `git branch -D` command – Zefiryn Dec 12 '14 at 07:41
  • Just to clarify, Zefiryn is referring to using the -D option which is not part of the one-liner. – cs01 Dec 12 '14 at 18:22
  • 1
    Or juse the lowercase `git branch -d` which should issue a warning about not pushed branches. – acme Apr 27 '16 at 11:41
25

You could do this:

git branch -vv | grep 'origin/.*: gone]' | awk '{print $1}' | xargs git branch -d

P.S.: as pointed out by Sam H.

execute this first:

git remote prune origin
Sven Dhaens
  • 1,146
  • 1
  • 11
  • 10
24

TL;DR:

Remove ALL local branches that are not on remote

git fetch -p && git branch -vv | grep ': gone]' | awk '{print $1}' | xargs git branch -D

Remove ALL local branches that are not on remote AND that are fully merged AND that are not used as said in many answers before.

git fetch -p && git branch --merged | grep -v '*' | grep -v 'master' | xargs git branch -d

Explanation

  • git fetch -p will prune all branches no longer existing on remote
  • git branch -vv will print local branches and pruned branch will be tagged with gone
  • grep ': gone]' selects only branch that are gone
  • awk '{print $1}' filter the output to display only the name of the branches
  • xargs git branch -D will loop over all lines (branches) and force remove this branch

Why git branch -D and not git branch -d else you will have for branches that are not fully merged.

error: The branch 'xxx' is not fully merged.
Jeff Puckett
  • 28,726
  • 15
  • 96
  • 149
noraj
  • 2,073
  • 17
  • 31
21

Yet another answer, because none of the solutions suit my needs on elegance and cross-platformness:

Command to delete local branches not on remote:

for b in $(git for-each-ref --format='%(if:equals=[gone])%(upstream:track)%(then)%(refname:short)%(end)' refs/heads); do git branch -d $b; done

To integrate it with gitconfig so it can be run with git branch-prune:

Bash

git config --global alias.branch-prune '!git fetch -p && for b in $(git for-each-ref --format='\''%(if:equals=[gone])%(upstream:track)%(then)%(refname:short)%(end)'\'' refs/heads); do git branch -d $b; done'

PowerShell

git config --global alias.branch-prune '!git fetch -p && for b in $(git for-each-ref --format=''%(if:equals=[gone])%(upstream:track)%(then)%(refname:short)%(end)'' refs/heads); do git branch -d $b; done'

(Need help in finding a universal command for PowerShell and bash)

Why this answer is the best?

  • Offers a complete solution: adds a git branch-prune command to your git
  • Works fine from Windows PowerShell
  • The core idea is @jason.rickman's bulletproof method using git for-each-ref
  • Parsing and filtering is done with --filter so no external dependencies needed

Explanation:

  • Adds a new alias to your ~\.gitconfig. After executing this you can simply do git branch-prune
  • Inside this alias:
    • Fetches branches with the --prune flag, which "prunes remote-tracking branches no longer on remote"
    • Uses git for-each-ref and --filter, to get a list of the branches are [gone] (no remote)
    • Loops through this list and deletes the branch safely
Himura
  • 976
  • 1
  • 8
  • 17
  • 1
    Thank you, [@jerry-wu](https://stackoverflow.com/users/8917446/jerry-wu) for improving the awesomeness of this solution to infinity. – Himura Apr 20 '20 at 12:12
  • [@jerry-wu](https://stackoverflow.com/users/8917446/jerry-wu) and your last edit of git config command does not work in PowerShell (( – Himura Apr 21 '20 at 11:00
  • Does this also remove local branches not yet pushed to remote? (a.k.a Work in Progress) – Ariel Mirra Oct 07 '20 at 16:08
  • 1
    The short answer is NO. If a branch is not merged, the `git branch -d branch-name` command used here will not remove it. It will send a notification that the branch is not merged, and show the command to delete it anyway (which is `git branch -D branch-name`) – Himura Oct 08 '20 at 20:49
  • For me this does report errors that the branch is not merged, even if the branch indeed is fully merged and was deleted from remote after the merge. error: The branch 'feature/...' is not fully merged. - Any suggestions? – LukeSolar Nov 03 '20 at 09:21
  • check `git log --graph --all` ? Try `git branch -d feature/...` manually? – Himura Nov 09 '20 at 15:02
20
git fetch -p

This will prune any branches that no longer exist on the remote.

noraj
  • 2,073
  • 17
  • 31
ckirksey3
  • 795
  • 5
  • 12
  • 76
    this removes remote references, but not the local branches themselves. While a useful command, I don't think this answers OP's question. – thataustin Nov 14 '14 at 21:32
  • What? This deletes local branches for me. – Alex Hall Aug 05 '18 at 13:33
  • 2
    @AlexHall The remote repository has a branch `X`; you `git checkout X`; now your repository has a (local) tracking branch `X` and a remote branch `origin/X`; the remote repository deletes `X`; you `git fetch-p`; in your local repository, not only `origin/X` but also `X` have been deleted. Is that what you're saying? – Andrew Spencer Aug 17 '18 at 08:49
19

Yet-another-answer for the pile, drawing heavily from Patrick's answer (which I like because it seems to do away with any ambiguity about where gone] will match in the git branch output) but adding a *nix bent.

In its simplest form:

git branch --list --format \
  "%(if:equals=[gone])%(upstream:track)%(then)%(refname:short)%(end)" \
  | xargs git branch -D

I have this wrapped up in a git-gone script on my path:

#!/usr/bin/env bash

action() {
  ${DELETE} && xargs git branch -D || cat
}

get_gone() {
  git branch --list --format \
    "%(if:equals=[gone])%(upstream:track)%(then)%(refname:short)%(end)"
}

main() {
  DELETE=false
  while [ $# -gt 0 ] ; do
    case "${1}" in
      (-[dD] | --delete) DELETE=true ;;
    esac
    shift
  done
  get_gone | action
}

main "${@}"

NB - The --format option seems to be fairly new; I needed to upgrade git from 2.10.something to 2.16.3 to get it.

EDIT: tweaked to include suggestion about refname:short from Benjamin W.

NB2 - I've only tested in bash, hence the hashbang, but probably portable to sh.

bxm
  • 384
  • 2
  • 8
  • Can't you skip the `sed` part by using `%(refname:short)` in the first line? – Benjamin W. May 01 '19 at 22:31
  • Seems to work for me, and I have it as a neat Git alias now – cleanest solution of all of them here! – Benjamin W. May 01 '19 at 22:38
  • 2.13 introduced `--format`. Another way to skip the `sed` part is to use `git update-ref -d`. Note that this is probably somewhat unsafe, using `git for-each-ref` is safer here (given `--shell`). – gsnedders May 23 '19 at 00:22
  • Great answer, and it's helped me answer my own questions when floundering with `--format` to do this myself. Just one question: why the `#!bash`? Everything here looks like portable `sh` to me. – Toby Speight Mar 06 '20 at 11:52
  • That's just my normal boilerplate, and hadn't tested elsewhere. – bxm Mar 06 '20 at 12:25
  • Should probably use `xargs -r ...` so that `git branch -D` isn't run at all if there are no pruned branches – rcoup Jan 15 '21 at 10:52
  • @rcoup yes that would be a worthwhile modification, if using GNU `xargs`. – bxm Feb 10 '21 at 14:43
15

This will delete all the merged local branched except local master reference and the one currently being used:

git branch --merged | grep -v "*" | grep -v "master" | xargs git branch -d

And this will delete all the branches having already been removed from the remote repository referenced by "origin", but are still locally available in "remotes/origin".

git remote prune origin
pabloa98
  • 562
  • 6
  • 16
  • 1
    `git branch -vv | grep 'gone]' | grep -v "\*" | awk '{print $1}' | xargs -r git branch -d` **Explanation:** I prefer replacing the `git branch --merged` by `git branch -vv` to show the status (gone) because the previous `git branch --merged` can show also the master – jpmottin Jan 08 '19 at 09:10
15

Might be useful to some, simple one line to clear all local branches except master and develop

git branch | grep -v "master" | grep -v "develop" | xargs git branch -D
Francois
  • 9,539
  • 3
  • 45
  • 59
  • Awesome answer! I like how one can easily play with the `'git branch | grep -v "master" | grep -v "develop"` kind of stuff before committing to adding on the deletion part of the command. – finneycanhelp Mar 08 '19 at 19:49
  • 2
    But this does not answer the question above. This will delete branches even though remote is still there. – Jim.B Mar 18 '20 at 10:26
13

I don't think there is a built-in command to do this, but it is safe to do the following:

git checkout master
git branch -d bug-fix-a

When you use -d, git will refuse to delete the branch unless it is completely merged into HEAD or its upstream remote-tracking branch. So, you could always loop over the output of git for-each-ref and try to delete each branch. The problem with that approach is that I suspect that you probably don't want bug-fix-d to be deleted just because origin/bug-fix-d contains its history. Instead, you could create a script something like the following:

#!/bin/sh

git checkout master &&
for r in $(git for-each-ref refs/heads --format='%(refname:short)')
do
  if [ x$(git merge-base master "$r") = x$(git rev-parse --verify "$r") ]
  then
    if [ "$r" != "master" ]
    then
      git branch -d "$r"
    fi
  fi
done

Warning: I haven't tested this script - use only with care...

Toby Speight
  • 23,550
  • 47
  • 57
  • 84
Mark Longair
  • 385,867
  • 66
  • 394
  • 320
  • I took the liberty to edit the script. Still won't give any guarantees, but, it runs and seems to work now. – cthulhu Feb 07 '14 at 13:45
9
grep gone <(git branch -v) | cut -d ' ' -f 3 | xargs git branch -d

The above command can be used to fetch branches which are merged and deleted in remote and it deletes the local branch which no longer available in remote

thiruclassic
  • 91
  • 1
  • 4
9

Powershell-based solution that I find more legible than many of the implementations here.

# prune deleted remoted branches
git fetch -p

# get all branches and their corresponding remote status
# deleted remotes will be marked [gone]
git branch -v |
  #find ones marked [gone], capture branchName
  select-string -Pattern '^  (?<branchName>\S+)\s+\w+ \[gone\]' | 
  foreach-object{ 
     #delete the captured branchname.
     git branch -D $_.Matches[0].Groups['branchName']
  }
derekbaker783
  • 2,174
  • 1
  • 16
  • 24
Pxtl
  • 661
  • 6
  • 16
8

None of this was really right for me. I wanted something that would purge all local branches that were tracking a remote branch, on origin, where the remote branch has been deleted (gone). I did not want to delete local branches that were never set up to track a remote branch (i.e.: my local dev branches). Also I wanted a simple one-liner that just uses git, or other simple CLI tools, rather than writing custom scripts. I ended up using a bit of grep and awk to make this simple command.

This is ultimately what ended up in my ~/.gitconfig:

[alias]
  prune-branches = !git remote prune origin && git branch -vv | grep ': gone]' | awk '{print $1}' | xargs -r git branch -D

Here is a git config --global ... command for easily adding this as git prune-branches:

git config --global alias.prune-branches '!git remote prune origin && git branch -vv | grep '"'"': gone]'"'"' | awk '"'"'{print $1}'"'"' | xargs -r git branch -d'

NOTE: In the config command, I use the -d option to git branch rather than -D, as I do in my actual config. I use -D because I don't want to hear Git complain about unmerged branches. You may want this functionality as well. If so, simply use -D instead of -d at the end of that config command.

Karl Wilbur
  • 4,826
  • 2
  • 36
  • 45
  • I like the git alias approach. Quick question: Why doing `git branch -vv` and greping for `: gone]` and not do `git branch -v` and grep for `[gone]`? – lalibi Jan 14 '19 at 09:23
  • @lalibi, good question. I don't remember. I suspect that something wasn't showing up with only one `v`. If `git branch -v | grep '[gone]'` works for you, go for it. It does seem a little cleaner. – Karl Wilbur Apr 16 '20 at 18:04
7

Based on info above, this worked for me:

git br -d `git br -vv | grep ': gone] ' | awk '{print $1}' | xargs`

It removes all local branches with are ': gone] ' on remote.

Muthu Ganapathy Nathan
  • 3,006
  • 10
  • 43
  • 72
Joost den Boer
  • 3,321
  • 2
  • 21
  • 33
4

Based on Git Tip: Deleting Old Local Branches, which looks similar to jason.rickman's solution I implemented a custom command for this purpose called git gone using Bash:

$ git gone
usage: git gone [-pndD] [<branch>=origin]
OPTIONS
  -p  prune remote branch
  -n  dry run: list the gone branches
  -d  delete the gone branches
  -D  delete the gone branches forcefully

EXAMPLES
git gone -pn    prune and dry run
git gone -d     delete the gone branches

git gone -pn combines the pruning and listing the "gone" branches:

$ git gone -pn
  bport/fix-server-broadcast         b472d5d2b [origin/bport/fix-server-broadcast: gone] Bump modules
  fport/rangepos                     45c857d15 [origin/fport/rangepos: gone] Bump modules

Then you can pull the trigger using git gone -d or git gone -D.

Notes

  • The regular expression I used is "$BRANCH/.*: gone]" where $BRANCH would normally be origin. This probably won't work if your Git output is localized to French etc.
  • Sebastian Wiesner also ported it to Rust for Windows users. That one is also called git gone.
Eugene Yokota
  • 90,473
  • 43
  • 204
  • 301
  • This should probably be the accepted answer - `git gone` looks like an alias for `git branch -vv | grep 'origin/.*: gone]' | awk '{print $1}' | xargs git branch -d`, which solves the OP's issue. – alex Nov 18 '19 at 16:08
4

Drawing heavily from a number of other answers here, I've ended up with the following (git 2.13 and above only, I believe), which should work on any UNIX-like shell:

git for-each-ref --shell --format='ref=%(if:equals=[gone])%(upstream:track)%(then)%(refname)%(end)' refs/heads | while read entry; do eval "$entry"; [ ! -z "$ref" ] && git update-ref -d "$ref" && echo "deleted $ref"; done

This notably uses for-each-ref instead of branch (as branch is a "porcelain" command designed for human-readable output, not machine-processing) and uses its --shell argument to get properly escaped output (this allows us to not worry about any character in the ref name).

gsnedders
  • 5,084
  • 1
  • 26
  • 38
  • It works for me, but it would also be nice if you could explain what the other steps in the command are doing. For example I don't know what `[ ! -z "$ref" ]` means. I think a multi liner would have helped already. But still thanks for your input! – KevinH Aug 27 '19 at 09:41
3

A simpler solution for Windows or others who don't want to/can't script the command line or who don't want to bother with PowerShell.

Dump the branch list into a file git branch > branches.txt
(or git branch --merged > branches.txt, if you're the belt and suspenders type; git branch -d will protect against deleting unmerged branches)

Open that file in your editor and combine all the lines (I used sublime text, so highlight all and press ctrl+j)

Add git branch -d ahead of your branch list.

Select all, copy, and paste (right click in windows cmd window) into the command line.

Tom Pietrosanti
  • 3,774
  • 2
  • 17
  • 26
2

I like using pipes because it makes the command easier to read.

This is my solution if you would like to remove all branches except master.

git branch | grep -v master | xargs -n 1 git branch -D

To delete other branches that match your criteria, modify the first and second block.

git branch --merged | grep feature_name | xargs -n 1 git branch -D
espaciomore
  • 188
  • 1
  • 10
2

May be this command is what you want.

After run:

git remote prune origin

then run:

diff <(git branch | sed -e 's/*/ /g') <(git branch -r | sed -e 's/origin\///g') | grep '^<'

this will show all branch which not in (git branch -r) but in (git branch)

This method have a problem, it will also show the branch in local which have not pushed before

Laobe
  • 91
  • 1
  • 2
1

I came up with this bash script. It always keep the branches develop, qa, master.

git-clear() {
  git pull -a > /dev/null

  local branches=$(git branch --merged | grep -v 'develop' | grep -v 'master' | grep -v 'qa' | sed 's/^\s*//')
  branches=(${branches//;/ })

  if [ -z $branches ]; then
    echo 'No branches to delete...'
    return;
  fi

  echo $branches

  echo 'Do you want to delete these merged branches? (y/n)'
  read yn
  case $yn in
      [^Yy]* ) return;;
  esac

  echo 'Deleting...'

  git remote prune origin
  echo $branches | xargs git branch -d
  git branch -vv
}
BrunoLM
  • 88,362
  • 76
  • 272
  • 427
1

I use a short method to do the trick, I recommend you to do the same as it could save some hours & give you more visibility

Just add the following snippet into your .bashrc (.bashprofile on macos).

git-cleaner() { git fetch --all --prune && git branch --merged | grep -v -E "\bmaster|preprod|dmz\b" | xargs -n 1 git branch -d ;};
  1. Fetch all remotes
  2. Get only merged branches from git
  3. Remove from this list the "protected / important" branches
  4. Remove the rest (e.g, clean and merged branches)

You'll have to edit the grep regex in order to fit to your needs (here, it prevent master, preprod and dmz from deletion)

benftwc
  • 402
  • 5
  • 19
1

This worked for me:

git branch -r | awk '{print $1}' | egrep -v -f /dev/fd/0 <(git branch -vv | grep origin) | awk '{print $1}' | xargs git branch -d
Fareed Alnamrouti
  • 26,439
  • 4
  • 77
  • 71
  • oh, i double posted this on... just saw this when reviewing posts. But you really could point to the guy who provided this command instead of taking this as yours! – Dwza Jun 07 '18 at 08:29
  • I get it from a forum don’t try to be smart just take the answer or ignore it – Fareed Alnamrouti Jun 07 '18 at 08:31
  • Even than you could... anyway... didnt came here to discuss this with you. As you sayed.. .take my comment or ignore it ;) – Dwza Jun 07 '18 at 08:36
0

I am not sure for how long, but I do use git-up now, which takes care of that.

I do git up and it starts to track new branches and deletes the old ones.

Just to make it clear, it is not out-of-box git command — https://github.com/aanand/git-up

BTW it also stashes dirty tree and makes rebases still with just git up.

Hope it'll be useful for someone

Mailo Světel
  • 17,483
  • 5
  • 27
  • 40
  • 2
    This isn't deleting local branches that don't exist on the server. – Ashley Nov 09 '15 at 15:17
  • The tool is not maintained any more. - The maintainer recommends `git config --global alias.up 'pull --rebase --autostash'` as replacement. – koppor Mar 28 '21 at 16:12
0

Here's a solution that I use for the fish shell. Tested on Mac OS X 10.11.5, fish 2.3.0 and git 2.8.3.

function git_clean_branches
  set base_branch develop

  # work from our base branch
  git checkout $base_branch

  # remove local tracking branches where the remote branch is gone
  git fetch -p

  # find all local branches that have been merged into the base branch
  # and delete any without a corresponding remote branch
  set local
  for f in (git branch --merged $base_branch | grep -v "\(master\|$base_branch\|\*\)" | awk '/\s*\w*\s*/ {print $1}')
    set local $local $f
  end

  set remote
  for f in (git branch -r | xargs basename)
    set remote $remote $f
  end

  for f in $local
    echo $remote | grep --quiet "\s$f\s"
    if [ $status -gt 0 ]
      git branch -d $f
    end
  end
end

A few notes:

Make sure to set the correct base_branch. In this case I use develop as the base branch, but it could be anything.

This part is very important: grep -v "\(master\|$base_branch\|\*\)". It ensures that you don't delete master or your base branch.

I use git branch -d <branch> as an extra precaution, so as to not delete any branch that has not been fully merged with upstream or current HEAD.

An easy way to test is to replace git branch -d $f with echo "will delete $f".

I suppose I should also add: USE AT YOUR OWN RISK!

lps
  • 1,245
  • 13
  • 26
0

I have written a Python script using GitPython to do delete local branches which don't exist on remote.

    import git
    import subprocess
    from git.exc import GitCommandError
    import os

    def delete_merged_branches():
        current_dir = input("Enter repository directory:")
        repo = git.Repo(current_dir)
        git_command = git.Git(current_dir)

        # fetch the remote with prune, this will delete the remote references in local.
        for remote in repo.remotes:
            remote.fetch(prune=True)
        
        local_branches = [branch.name for branch in repo.branches]
        deleted_branches = []

        # deleted_branches are the branches which are deleted on remote but exists on local.
        for branch in local_branches:
            try:
                remote_name = 'origin/'+ branch
                repo.git.checkout(remote_name)
            except GitCommandError:
            # if the remote reference is not present, it means the branch is deleted on remote.
                deleted_branches.append(branch)
            
        for branch in deleted_branches:
            print("Deleting branch:"+branch)
            git_command.execute(["git", "branch", "-D",branch])

    
        # clean up the work flow.
        repo.git.checkout('master')
        repo.git.pull()

    if __name__ == '__main__':
        delete_merged_branches()

Hope someone finds it useful, please add comments if I missed anything.

Community
  • 1
  • 1
raviraja
  • 726
  • 6
  • 24
0

If you are using zsh shell with Oh My Zsh installed then the easiest way to do this safely is to use the built in autocomplete.

First determine which branches you want to delete with:

~ git branch --merged

  branch1
  branch2
  branch3
* master

this will show you a list of already merged branches

After you know a few you want to delete then type:

~ git branch -d 

All you have to do is hit [tab] and it will show you a list of local branches. Use tab-complete or just hit [tab] again and you can cycle through them to select a branch with [enter].

Tab Select the branches over and over again until you have a list of branches you wnat to delete:

~ git branch -d branch1 branch2 branch3

Now just press enter to delete your collection of branches.

If you aren't using zsh on your terminal... Get it here.

Noah Gary
  • 580
  • 5
  • 22
0

The real challenge is when the maintainer squashes the commits. Then, the solutions using git built-in functionality such as --merged does not help.

The tool git-delete-merged-branches allows for a convenient deletion of branches. I especially like the interactive mode.

Installation (requires python3):

pip install git-delete-merged-branches

Then execute

git-delete-merged-branches --effort=3

--effort=3 is important to enable deletion of squashed branches.

Alternatives

  • @teppeis/git-delete-squashed: With node.js installed execute npx @teppeis/git-delete-squashed. Supports main branch.
  • git-delete-squashed: Not maintained: Misses functionality for main branch. @teppeis/git-delete-squashed is based on this.
koppor
  • 14,964
  • 11
  • 100
  • 141
-3

This Below Commands Solved My problem.

// To Delete Branch Locally
git branch -d localBranchName


// To Delete Branch Remotely
git push origin --delete remoteBranchName
Chandan Sharma
  • 1,410
  • 16
  • 18
-4

Here's the simple answer that worked for me using a git client:

Delete the repository altogether from your machine then check out again.

No mucking around with risky scripts.

  • 2
    What about the branches I am currently working on :/ – Mailo Světel Sep 16 '19 at 09:36
  • @MailoSvětel if they are on your remote then you can just pull them again (remember to commit and push your latest work to your remote!) – Juan Carlos Ospina Gonzalez Sep 16 '19 at 09:42
  • In my question and in most of the answers, we're trying to avoid unnecessary work. In other words: What I need to do is just remove the branches, I'll not work on anymore. Removing repo, cloning it and start tracking the branches again, is a lot of unnecessary work for me. Besides that, some work could get lost :( – Mailo Světel Sep 17 '19 at 12:59
-5

This is gonna delete all the remote branches that are not present locally (in ruby):

bs = `git branch`.split; bs2 = `git branch -r | grep origin`.split.reject { |b| bs.include?(b.split('/')[1..-1].join('/')) }; bs2.each { |b| puts `git  push origin --delete #{b.split('/')[1..-1].join('/')}` }

Explained:

# local branches
bs = `git branch`.split
# remote branches
bs2 = `git branch -r | grep origin`.split
# reject the branches that are present locally (removes origin/ in front)
bs2.reject! { |b| bs.include?(b.split('/')[1..-1].join('/')) }
# deletes the branches (removes origin/ in front)
bs2.each { |b| puts `git  push origin --delete #{b.split('/')[1..-1].join('/')}` }
Dorian
  • 19,009
  • 8
  • 108
  • 111
-6

I use this method so I can have more control.

git branch -D $(git branch | grep -v "master" | grep -v "develop")

This is remove any branches not named: master or develop.

Corey C
  • 124
  • 1
  • 4