2152

I have many Git branches. How do I delete branches which have already been merged? Is there an easy way to delete them all instead of deleting them one by one?

Peter Mortensen
  • 28,342
  • 21
  • 95
  • 123
Nyambaa
  • 31,433
  • 9
  • 27
  • 34
  • 48
    To be slightly more specific `git branch -D` deletes any branch whether it as been merged or not. – PhilT Feb 08 '17 at 09:48
  • 13
    You can also do this directly from GitHub, if you go to the 'branches' section of your repo (e.g. https://github.com///branches). There should be a list of all your branches, with a red trashcan icon on the side which will delete the selected branch. Much faster than doing it in the terminal! Will also show how far ahead/behind `master` each branch is. However, your local client will still list the old branches if you run `git branch -a`; use `git fetch --prune` to remove them (as per [this answer](http://stackoverflow.com/a/17029936/5359531) ). – user5359531 Feb 24 '17 at 16:13
  • 3
    Script to do this locally or remotely - with safety checks and pre-configured "safe branches": https://github.com/fatso83/dotfiles/tree/master/utils/scripts#git-delete-merged `git delete-merged --doit origin` or `git delete-merged --doit --local` – oligofren Jun 27 '17 at 15:10
  • You could also use [this app](https://probot.github.io/apps/delete-merged-branch/) to auto delete merged branches. – Sebass van Boxel Aug 07 '18 at 16:16
  • 3
    `rm -fr work && git clone http://example.com/work.git` over the years has become the easiest way to get out of a pickle with git. – Reactgular Apr 19 '20 at 11:33
  • More recent question [How can I delete all git branches which have been “Squash and Merge” via GitHub?](https://stackoverflow.com/q/43489303/873282), because "squashing and merging" was not available when this question was asked. – koppor Mar 28 '21 at 16:22

47 Answers47

3435

UPDATE:

You can add other branches to exclude like master and dev if your workflow has those as a possible ancestor. Usually I branch off of a "sprint-start" tag and master, dev and qa are not ancestors.

First, list locally-tracking branches that were merged in remote (you may consider to use -r flag to list all remote-tracking branches as suggested in other answers).

git branch --merged

You might see few branches you don't want to remove. we can add few arguments to skip important branches that we don't want to delete like master or a develop. The following command will skip master branch and anything that has dev in it.

git branch --merged| egrep -v "(^\*|master|main|dev)"

If you want to skip, you can add it to the egrep command like the following. The branch skip_branch_name will not be deleted.

git branch --merged| egrep -v "(^\*|master|main|dev|skip_branch_name)"

To delete all local branches that are already merged into the currently checked out branch:

git branch --merged | egrep -v "(^\*|master|main|dev)" | xargs git branch -d

You can see that master and dev are excluded in case they are an ancestor.


You can delete a merged local branch with:

git branch -d branchname

If it's not merged, use:

git branch -D branchname

To delete it from the remote use:

git push --delete origin branchname

git push origin :branchname    # for really old git

Once you delete the branch from the remote, you can prune to get rid of remote tracking branches with:

git remote prune origin

or prune individual remote tracking branches, as the other answer suggests, with:

git branch -dr branchname
Michael Freidgeim
  • 21,559
  • 15
  • 127
  • 153
Adam Dymitruk
  • 109,813
  • 21
  • 138
  • 137
  • 3
    yeah, I know how delete a branch. But I have 100 branches and 50 of them already merged to the master and another 50 is not merget yet. So I want to delete the branches which are merged to the master. So I'm asking here, how delete them faster than delete one by one. – Nyambaa May 26 '11 at 01:44
  • 1
    git checkout master; for branch in $(git branch --raw); do git branch --contains $branch && git branch -d $branch; done – Adam Dymitruk May 26 '11 at 21:55
  • 2
    git branch --merged | sed 's/\\*/ /' | xargs -n 1 git branch -d --Gets rid of that pesky asteryx – Gary Oct 07 '11 at 18:21
  • 61
    WARNING: If you just created a branch it will also delete that one. Make sure to not have a newly created branch in the list before you run the top most command. – Gary Haran May 24 '13 at 14:01
  • I'd like to see an example on how to do this with git push --delete as the output of the grep is something like origin/feature/branch, but the push command doesn't want the origin/ prefix. – Sam Aug 09 '13 at 01:07
  • So, what I see as a good solution is the following if you want to remove merged branches from both your remote and your local `git branch --merged | grep -v "\*" | xargs -n 1 git push --delete origin` `git branch --merged | grep -v "\*" | xargs -n 1 git branch -d` – General Redneck Oct 17 '13 at 14:52
  • Yeah I was about the use the same...I think there should be a warning at the top of answer –  Aug 18 '14 at 15:37
  • 176
    OPPOSITE OF WARNING: reflog will save your bacon. So don't worry. – Adam Dymitruk Aug 20 '14 at 01:05
  • 36
    Keep in mind that the first command only deletes local branches, so it isn't as 'dangerous' as some have pointed out. – ifightcrime Sep 15 '14 at 23:21
  • OPPOSITE OF OPPOSITE OF WARNING: (why are we shouting???) - annoying to get 'pathspec 'master' did not match any file(s) known to git...' and have to `git checkout master origin/master` at some later point. `git branch --merged | grep -E -v "\*|master" | xargs -n 1 git branch -d` FTW – Stephen Mar 23 '15 at 04:42
  • 1
    reflog won't save your bacon. deleting a branch deletes its reflog. You can get the most recent branch tip back, but you can no longer say `master@{1}` or `master@{yesterday noon}` – jthill Apr 01 '15 at 19:34
  • 1
    Add `--no-color` if you use color by default. Example: ```git branch --merged develop --no-color | cat | grep -v "\* develop" | xargs -n 1 git branch -d``` – Rushabh Mehta Jul 03 '15 at 07:00
  • 92
    PowerShell variant, so that I could find it here next time I googled the answer: `git branch --merged | %{$_.trim()} | ?{$_ -notmatch 'develop' -and $_ -notmatch 'master'} | %{git branch -d $_}` – vorou Dec 20 '15 at 08:12
  • 25
    This produces an error `fatal: branch name required` if you have no branches that should be deleted. To avoid that you can pass `-r` to `xargs` so it won't run `git branch -d` if the stdin is empty. (This a GNU xargs extension, according to the man page). – Marius Gedminas Feb 09 '16 at 14:40
  • I created [a bash function](https://github.com/jessepinho/dotfiles/blob/15a8239dcb4aad2d72e641650e541555b79201e8/.bash_profile#L61-L68) to prune both merged branches and remote merged branches, if this helps anyone. – jessepinho Jun 23 '16 at 12:29
  • 1
    PowerShell variant (based on @vorou's) for deleting remote branches: `git branch -r --merged | %{$_.trim()} | ?{$_ -match '/bug/' -or $_ -match '/feature/'} | %{$_ -replace 'origin/',''} | %{git push --delete origin $_}` – gregmac Sep 23 '16 at 22:32
  • Thanks! I just added an `alias` to my `~/.profile`! Very helpful answer! – danielricecodes Apr 19 '17 at 13:05
  • @danielricecodes How did you add an alias? `clean-branches = !git branch --merged | egrep -v "(^\*|master|dev)" | xargs git branch -d` doesn't work for me (bad config file error) – knuhol Jun 09 '17 at 11:10
  • 2
    @Akarienta - `alias git-branch-clean="git branch --merged | egrep -v \"(^\*|master|dev|staging|production)\" | xargs git branch -d"` – danielricecodes Jun 28 '17 at 19:53
  • `git branch --merged | egrep -v "(^\*|master|dev)" | xargs -I % echo 'git branch -d % ; git push --delete freephile % ;'` Using *echo* helps you look before you leap. % is the replacement string in xargs. Change 'echo' to 'sh -c' to execute. Does both local and remote prunes. – Greg Rundlett Sep 06 '17 at 06:28
  • 1
    Warning: `git branch --merged` without further arguments will show all branches which are merged into the current checkedout branch. You should always use something like `git branch --merged origin/master` – Daniel Alder Oct 25 '17 at 08:43
  • 1
    Full command, better then pipe because it will use one transaction: `git push origin --delete $(git branch -r --merged origin/master | grep origin | egrep -v '>|master|develop' | cut -d/ -f2-)` – voiski Jan 31 '18 at 21:03
  • If you have ui colours set in git, you may need to disable them temporarily to avoid encoding errors - just set `ui = never` under the `[color]` section in .gitconfig – lamplightdev Mar 13 '18 at 10:26
  • I had to add the `--no-color` switch before `--merged`: `git branch --no-color --merged | egrep -v "(^\*|master|dev)" | xargs git branch -d` – Robert Pankowecki May 04 '18 at 08:18
  • 3
    I come here about once a week – DanSingerman Jul 06 '18 at 16:30
  • It would be better if the regexp explicitly marked the end of line character, i.e. `git branch --merged | egrep -v "(^\*|master)$"`. – Alex Harvey Jul 30 '18 at 05:49
  • 1
    The egrep pattern excludes all branches containing master, not just master itself, fix by using `egrep -v "^(\* .*| *master| *dev)$"` – carl verbiest Sep 12 '18 at 09:34
  • 1
    I think it's worth noting that branches that have been cherry-picked to the current branch wont show as merged using this solution. Even though OP said merged, many people only care for merged branches to know whether they can safely delete a branch so as to not lose any data. Even branches not returned by this solution, could be safely removed if `git log upstream...currentBranch --cherry-pick --right-only` doesn't return anything – Danilo Souza Morães Sep 13 '18 at 04:46
  • I use the following command as my daily basis ```bash git branch --merged | egrep -v "(^\*|master|dev)" | xargs git branch -d ``` But I was tired to run it every time so I added an alias in my .bash_profile. I have an article about how to do it [here](https://www.boobo94.xyz/tutorials/cleanup-merged-branches-git/) – Bogdan Alexandru Militaru Jan 10 '19 at 21:24
  • Combining with kuboons answer below to replicate the branch deletion (excluding master and dev) on remote: ```git branch -r --merged | egrep -v "(^\*|master|dev)" | sed 's/origin\//:/' | xargs -n 1 git push origin``` - disclaimer: My bash skills aren't great, so check you are happy with what this does before running. Looked to work for me. – gb2d Mar 21 '19 at 09:13
  • My 2 cents: In case you'd want to delete merged branches on remote, while excluding `master` and/or `dev`, you will need to trim some of the output since `git push` does not work with paths. The command that I've been using lately: `git branch -r | egrep -v "^\*|master|dev" | cut -d '/' -f 2 | xargs git push --delete origin` – 0CDc0d3r Mar 09 '20 at 08:04
  • Naturally, this won't work on Windows since it uses `egrep`... – Dr_Zaszuś Jul 13 '20 at 14:02
  • Thnx! I made a bash one-liner of it `for i in \`git branch --merged| egrep -v "(^\*|master|dev)"\`; do git branch -d ${i}; done;` – Samantha Adrichem Jul 30 '20 at 10:11
509

To delete all branches on remote that are already merged:

git branch -r --merged | grep -v master | sed 's/origin\//:/' | xargs -n 1 git push origin

In more recent versions of Git

git branch -r --merged | grep -v master | sed 's/origin\///' | xargs -n 1 git push --delete origin

UPDATE (by @oliver; since does not fit in comment, but enough answers already): if you are on branch ABC then ABC will appear in the results of git branch -r --merged because the branch is not specified, so branch defaults to current branch, and a branch always qualifies as merged to itself (because there are no differences between a branch and itself!).

So either specify the branch:

git branch -r --merged master | grep -v master ...

OR first checkout master:

git checkout master | git branch -r --merged | grep -v ...
Oliver
  • 21,908
  • 4
  • 55
  • 73
kuboon
  • 8,145
  • 3
  • 34
  • 30
  • 19
    Best answer by far. Just a note, my master branch is named `dev` so I had to change that – Dorian Feb 13 '14 at 21:33
  • 41
    I had to add `| grep origin` after `grep -v master` to prevent pushing branches of other remotes to origin. Highly recommending testing the output beforehand, using `git branch -r --merged | grep -v master | grep origin | sed 's/origin\//:/' | xargs -n 1 echo` – L0LN1NJ4 Jun 08 '15 at 08:06
  • 9
    I slightly modified to exclude `develop` branch as well. `git branch -r --merged | grep -v master | grep -v develop | sed 's/origin\///' | xargs -n 1 git push --delete origin`. Now this turned out to be my alias. – sarat Aug 15 '15 at 12:19
  • 9
    What made this the best answer I've read, is the `-r` argument, which I've not seen mentioned anywhere else. It's taken for granted that only local branches are worth doing some housekeeping on. But remotes are full of garbage too. – Asbjørn Ulsberg Nov 02 '15 at 17:49
  • 1
    Apart from `| grep origin` you can also add `--no-verify` at the end to skip git pre-push hook – jakub.g Jan 26 '16 at 13:46
  • 19
    Caution - just realized: this will obviously find branches merged to *current branch*, not master, so if you are on `myFeatureBranch` it will wipe `origin/myFeatureBranch`. Probably it's best to `git checkout master` first. – jakub.g Feb 05 '16 at 14:40
  • 1
    This works great. Except, it doesn't delete branches with the word 'master' in their name. (e.g. master-TRIAG-873). I've tried the solution below (`grep -v '^ master$'`), but that still includes the actual master branch when I try it. – Vyskol Jun 22 '16 at 18:50
  • @kuboon - I really think your answer should be added to Adam's answer as an edit, because both your answer and his pertain to the question. I would do it myself, but most of my edits to date have been rejected and it should be to your credit anyway. – Sean Sep 09 '16 at 19:09
  • @kuboon Branch is deleting but im getting error -> remote: fatal: bad object 0000000000000000 remote: remote: Syntax checker hook is malfunctioning - can't execute git ls-tree. Failing gracefully and allowing this push. remote: fatal: bad object 0000000000000000000000000000000000000000 remote: fatal: Invalid revision range ed2b135a69b9f3594b7631b70fed6b82a8dc1ad4..0000000000000000000000000000000000000000 remote: fatal: git cat-file 0000000000000000000000000000000000000000: bad file To git@git.cfteam.in:root/myproj.git - [deleted] shield_square_removal – LOKESH K V Nov 02 '16 at 10:35
  • 3
    WARNING: This also closes open pull requests. – scones Jul 20 '17 at 09:10
  • `git branch -r --merged | grep -v master | grep -v develop | sed 's/origin\///' | xargs -n 1 git push --delete origin` WARNING: This command will delete and close open pull requests. – Diego Aug 14 '17 at 15:19
  • 2
    You can eliminate the `sed` step by using the `--format` to include only the needed part of the ref `git branch --format "%(refname:lstrip=3)" --remotes --merged` The available field names are documented [here](https://git-scm.com/docs/git-for-each-ref#_field_names). They are *not* the same as the format for other git sub commands. – efx Sep 10 '19 at 19:01
  • In the last command, it should be `git checkout master &&`, not `git checkout master |`. – user137369 Apr 09 '20 at 16:57
  • Is it possible to add a git alias for this? – DarVar Jul 08 '20 at 13:42
  • @DarVar, yes. `drm = !git checkout master && git branch -r --merged | grep -v master | sed \"s/origin\\///\" | xargs -n 1 git push --delete origin` should work as an alias in `.gitconfig` – vinnymac Nov 04 '20 at 18:31
  • @scones, can you clarify your warning about closing open pull requests ?https://stackoverflow.com/questions/65444886/how-clean-up-merged-git-branches-can-delete-pull-requests – Michael Freidgeim Dec 25 '20 at 03:02
  • @MichaelFreidgeim sure. if you execute the commands, your pull requests will be closed. not merged tho. – scones Feb 25 '21 at 09:33
  • Changing the `-n 1` to a higher value deletes more branches at once – M. Reza Nasirloo Mar 01 '21 at 08:51
219

Just extending Adam's answer a little bit:

Add this to your Git configuration by running git config -e --global

[alias]
    cleanup = "!git branch --merged | grep  -v '\\*\\|master\\|develop' | xargs -n 1 git branch -d"

And then you can delete all the local merged branches doing a simple git cleanup.

real_ate
  • 9,106
  • 3
  • 26
  • 48
  • 13
    shouldn't the first command be: `git branch --merged master` since you want to look at what has been merged into master, not currently checked out branch? – Joe Phillips Aug 12 '16 at 16:23
  • @JoePhilllips Some people has the main branch not master but instead `develop` or `dev` and in that case the command will fail with `fatal: malformed object name` it's better to have a generic command and you have the responsibility to run it – smohamed Aug 13 '16 at 01:14
  • @SKandeel Yes I agree but most people can figure out to change that for their particular case. It's a little odd to have to be sitting on a certain branch in order for cleanup to work – Joe Phillips Aug 15 '16 at 19:39
  • 1
    @JoePhilllips the point of this answer is to package up Adam's answer (the top answer for this question) in helpful git alias. Adam's answer doesn't have what you are suggesting and so many people have found that useful so I would be inclined not to change mine. I would recommend opening the discussion on Adam's answer if you feel strongly about it – real_ate Aug 16 '16 at 07:39
  • @Adam's answer was updated/simplified a little bit. Just thought you might want to know in case you want to update your answer as well because *"the point of this answer is to package up Adam's answer"*. – Jeff Puckett Sep 08 '16 at 15:56
  • @SKandeel it might also be interesting to note that on another [one of Adam's very similar answers](http://stackoverflow.com/a/8236216/4233593), he does qualify it with `master` – Jeff Puckett Sep 08 '16 at 16:19
  • 15
    Adding `-r` to `xargs` will prevent unnecessary errors (`branch name required`) when running this alias multiple times or when there is no branch left to be deleted. My alias looks like this: `cleanup = "!git branch --merged | grep -v -P '^\\*|master|develop' | xargs -n1 -r git branch -d"` – spezifanta Jun 23 '17 at 09:14
  • Is that going to be the case for all versions of xargs? I know there are some differences between linux and mac on this and I want to make sure this works for all cases. Also I've never come across this issue before :/ example: https://i.stack.imgur.com/QAY2H.png – real_ate Jun 23 '17 at 14:58
  • `nuke = "!sh -c \"git branch --merged master | grep -v -P '\\*|master' | xargs -n1 -r git branch -D\""` For windows users, this is what ended up finally working for me: Thanks @spezifanta for getting me almost all the way there. – lanierhall Feb 14 '18 at 02:43
  • 2
    Current command doesn't filter out master and develop branches – Andriy F. Mar 02 '19 at 09:52
  • @AndriyF. what platform are you using? the current command works well for me and does filter out master and develop :) – real_ate Mar 04 '19 at 11:00
  • @real_ate Linux OpensSuse git 2.16.4 grep 3.1 – Andriy F. Mar 05 '19 at 12:33
89

You'll want to exclude the master, main & develop branches from those commands.

Local git clear:

git branch --merged | grep -v '\*\|master\|main\|develop' | xargs -n 1 git branch -d

Remote git clear:

git branch -r --merged | grep -v '\*\|master\|main\|develop' | sed 's/origin\///' | xargs -n 1 git push --delete origin

Sync local registry of remote branches:

git fetch -p
Guido Bouman
  • 2,367
  • 3
  • 20
  • 31
  • 3
    +1 for the remote version as well (but less needed as we have remote --prune). Also worth noting that thoose won't work with older git version – malko Jun 11 '15 at 08:09
  • 5
    ``git config --global --add fetch.prune true`` to prune automatically on fetch or pull. – T3rm1 Dec 18 '15 at 14:51
  • 2
    Mind you, prune is not the same as the remote clear. The remote clear actually deletes the remote branches that are fully merged with your current branch. Prune only cleans up your local registry of remote branches that are already deleted. – Guido Bouman Jan 05 '17 at 14:07
  • The word fully is a bit misleading, as a branch will be considered merged, when it was merged before, but has new commits after the merge, which were not merged. – scones Jul 20 '17 at 09:15
  • To delete all the origin remotes in one call, I used this: `git branch -r --merged | grep -v '\*\|master\|develop' | grep '^\s*origin/' | sed 's/origin\///' | tr "\n" " " | xargs git push --delete origin` – GPHemsley Oct 03 '18 at 13:51
88

This also works to delete all merged branches except master.

git branch --merged | grep -v '^* master$' | grep -v '^  master$' | xargs git branch -d
mkobit
  • 34,772
  • 9
  • 135
  • 134
Ismael
  • 15,815
  • 6
  • 55
  • 73
  • 3
    Now it won't delete any branch with `master` in it. Try `grep -v ^master$` for the middle. – wchargin Oct 12 '13 at 02:26
  • I'd also let ```| grep -v '^\*'``` to avoid deletting current branch if you are **not on master** – svassr Sep 08 '14 at 19:06
  • 5
    This is great, thanks! One caveat for anyone using this: note that there are two spaces in `grep -v '^ master$'`. If you type it in yourself and miss one, you'll delete `master` if you're not on it. – styger Oct 23 '14 at 20:51
  • 3
    @Mr.Polywhirl your edit breaks the command and you should revert it. The two spaces are necessary, since `git branch` will list each branch name on a new line with two spaces to the left if it is not the currently checked out branch. You have essentially guaranteed that anyone who runs this command will delete their master branch unless it is the currently checked out branch. – styger Dec 08 '15 at 21:49
62

For those of you that are on Windows and prefer PowerShell scripts, here is one that deletes local merged branches:

function Remove-MergedBranches
{
  git branch --merged |
    ForEach-Object { $_.Trim() } |
    Where-Object {$_ -NotMatch "^\*"} |
    Where-Object {-not ( $_ -Like "*master" or $_ -Like "*main")} |
    ForEach-Object { git branch -d $_ }
}

Or the short version:

git branch --merged | %{$_.trim()}  | ?{$_ -notmatch 'dev' -and $_ -notmatch 'master' -and $_ -notmatch 'main'} | %{git branch -d $_.trim()}
Roelant
  • 3,185
  • 1
  • 18
  • 49
Klas Mellbourn
  • 35,589
  • 18
  • 119
  • 143
  • 17
    For curiosity sake, this can be shortened to `git branch --merged | ?{-not ($_ -like "*master")} | %{git branch -d $_.trim()}` – Iain Ballard Oct 08 '14 at 08:27
  • 5
    @IainBallard Sure, I could have used aliases. That is not recommended when you want to maximize readability. https://github.com/darkoperator/PSStyleGuide/blob/master/English.md – Klas Mellbourn Oct 08 '14 at 11:36
  • 2
    sure. I found your answer very helpful :-) However sometimes the long-form powershell syntax gets in the way of what's going on in the blocks. But primarily, I was putting forward something you might copy/paste or type as a one-off. Thanks again. – Iain Ballard Oct 08 '14 at 11:56
  • 5
    Here's a one-liner for Windows cmd shell that preserves master and your current branch: `for /f "usebackq" %B in (``git branch --merged^|findstr /v /c:"* " /c:"master"``) do @git branch -d %B` (sigh, replace double-backquotes with single, I'm not sure how to format a literal that contains backquotes) – yoyo Jan 16 '17 at 23:37
52

I've used Adam's answer for years now. That said, that there are some cases where it wasn't behaving as I expected:

  1. branches that contained the word "master" were ignored, e.g. "notmaster" or "masterful", rather than only the master branch
  2. branches that contained the word "dev" were ignored, e.g. "dev-test", rather than only the dev branch
  3. deleting branches that are reachable from the HEAD of the current branch (that is, not necessarily master)
  4. in detached HEAD state, deleting every branch reachable from the current commit

1 & 2 were straightforward to address, with just a change to the regex. 3 depends on the context of what you want (i.e. only delete branches that haven't been merged into master or against your current branch). 4 has the potential to be disastrous (although recoverable with git reflog), if you unintentionally ran this in detached HEAD state.

Finally, I wanted this to all be in a one-liner that didn't require a separate (Bash|Ruby|Python) script.

TL;DR

Create a git alias "sweep" that accepts an optional -f flag:

git config --global alias.sweep '!git branch --merged $([[ $1 != "-f" ]] \
&& git rev-parse master) | egrep -v "(^\*|^\s*(master|develop)$)" \
| xargs git branch -d'

and invoke it with:

git sweep

or:

git sweep -f

The long, detailed answer

It was easiest for me to create an example git repo with some branches and commits to test the correct behavior:

Create a new git repo with a single commit

mkdir sweep-test && cd sweep-test && git init
echo "hello" > hello
git add . && git commit -am "initial commit"

Create some new branches

git branch foo && git branch bar && git branch develop && git branch notmaster && git branch masterful
git branch --list
  bar
  develop
  foo
* master
  masterful
  notmaster

Desired behavior: select all merged branches except: master, develop or current

The original regex misses the branches "masterful" and "notmaster" :

git checkout foo
git branch --merged | egrep -v "(^\*|master|dev)"
  bar

With the updated regex (which now excludes "develop" rather than "dev"):

git branch --merged | egrep -v "(^\*|^\s*(master|develop)$)"
bar
masterful
notmaster

Switch to branch foo, make a new commit, then checkout a new branch, foobar, based on foo:

echo "foo" > foo
git add . && git commit -am "foo"
git checkout -b foobar
echo "foobar" > foobar
git add . && git commit -am "foobar"

My current branch is foobar, and if I re-run the above command to list the branches I want to delete, the branch "foo" is included even though it hasn't been merged into master:

git branch --merged | egrep -v "(^\*|^\s*(master|develop)$)"
  bar
  foo
  masterful
  notmaster

However, if I run the same command on master, the branch "foo" is not included:

git checkout master && git branch --merged | egrep -v "(^\*|^\s*(master|develop)$)"
  bar
  masterful
  notmaster

And this is simply because git branch --merged defaults to the HEAD of the current branch if not otherwise specified. At least for my workflow, I don't want to delete local branches unless they've been merged to master, so I prefer the following variant using git rev-parse:

git checkout foobar
git branch --merged $(git rev-parse master) | egrep -v "(^\*|^\s*(master|develop)$)"
  bar
  masterful
  notmaster

Detached HEAD state

Relying on the default behavior of git branch --merged has even more significant consequences in detached HEAD state:

git checkout foobar
git checkout HEAD~0
git branch --merged | egrep -v "(^\*|^\s*(master|develop)$)"
  bar
  foo
  foobar
  masterful
  notmaster

This would have deleted the branch I was just on, "foobar" along with "foo", which is almost certainly not the desired outcome. With our revised command, however:

git branch --merged $(git rev-parse master) | egrep -v "(^\*|^\s*(master|develop)$)"
  bar
  masterful
  notmaster

One line, including the actual delete

git branch --merged $(git rev-parse master) | egrep -v "(^\*|^\s*(master|develop)$)" | xargs git branch -d

All wrapped up into a git alias "sweep":

git config --global alias.sweep '!git branch --merged $([[ $1 != "-f" ]] \
&& git rev-parse master) | egrep -v "(^\*|^\s*(master|develop)$)" \
| xargs git branch -d'

The alias accepts an optional -f flag. The default behavior is to only delete branches that have been merged into master, but the -f flag will delete branches that have been merged into the current branch.

git sweep
Deleted branch bar (was 9a56952).
Deleted branch masterful (was 9a56952).
Deleted branch notmaster (was 9a56952).
git sweep -f
Deleted branch foo (was 2cea1ab).
Michael Freidgeim
  • 21,559
  • 15
  • 127
  • 153
eddies
  • 5,179
  • 27
  • 36
  • Why do you need to create a function? Isn't `git config` atomic? – VasiliNovikov Jun 08 '19 at 15:40
  • To deal with the optional '-f' argument (if I understand your question correctly) – eddies Jun 09 '19 at 05:04
  • 1
    but how does it help? I mean the start of the expression, `!f(){ git branch ...`. It's a function declaration, right? Why not start directly with `git branch ...` ? – VasiliNovikov Jun 09 '19 at 07:47
  • 1
    You're absolutely right. Edited my answer accordingly. Thanks for the pointer! – eddies Jun 10 '19 at 14:56
  • Would the following not do the same as the non-force-mode? `git checkout master && git branch -d \`git branch --merged\` && git checkout -` Except that it would delete `develop`, but might be a simpler approach. – Guido Bouman Dec 11 '19 at 16:29
  • @GuidoBouman yes, but with notable caveats: one you already mentioned (deleting `develop`); other caveats would be related to switching back and forth between branches, e.g.: uncommitted changes need to be handled before switching branches; depending on what you have going on in other tools (editors, profiler, running app server from your branch, etc.) switching branches might disrupt your flow. – eddies Jan 15 '20 at 02:04
22

Git Sweep does a great job of this.

Peter Mortensen
  • 28,342
  • 21
  • 95
  • 123
paul
  • 279
  • 2
  • 4
  • right now, this project is no longer maintained. See https://github.com/arc90/git-sweep/pull/43 – Earlee May 15 '19 at 10:15
20

Using Git version 2.5.0:

git branch -d `git branch --merged`
Peter Mortensen
  • 28,342
  • 21
  • 95
  • 123
drautb
  • 437
  • 4
  • 12
16

You can add the commit to the --merged option. This way you can make sure only to remove branches which are merged into i.e. the origin/master

Following command will remove merged branches from your origin.

git branch -r --merged origin/master | grep -v "^.*master" | sed s:origin/:: |xargs -n 1 git push origin --delete 

You can test which branches will be removed replacing the git push origin --delete with echo

git branch -r --merged origin/master | grep -v "^.*master" | sed s:origin/:: |xargs -n 1 echo
Jörn Reimerdes
  • 689
  • 6
  • 10
15

If you're on Windows you can use Windows Powershell or Powershell 7 with Out-GridView to have a nice list of branches and select with mouse which one you want to delete:

git branch --format "%(refname:short)" --merged  | Out-GridView -PassThru | % { git branch -d $_ }

enter image description here after clicking OK Powershell will pass this branches names to git branch -d command and delete them enter image description here

Mariusz Pawelski
  • 18,550
  • 7
  • 54
  • 71
12

I use the following Ruby script to delete my already merged local and remote branches. If I'm doing it for a repository with multiple remotes and only want to delete from one, I just add a select statement to the remotes list to only get the remotes I want.

#!/usr/bin/env ruby

current_branch = `git symbolic-ref --short HEAD`.chomp
if current_branch != "master"
  if $?.exitstatus == 0
    puts "WARNING: You are on branch #{current_branch}, NOT master."
  else
    puts "WARNING: You are not on a branch"
  end
  puts
end

puts "Fetching merged branches..."
remote_branches= `git branch -r --merged`.
  split("\n").
  map(&:strip).
  reject {|b| b =~ /\/(#{current_branch}|master)/}

local_branches= `git branch --merged`.
  gsub(/^\* /, '').
  split("\n").
  map(&:strip).
  reject {|b| b =~ /(#{current_branch}|master)/}

if remote_branches.empty? && local_branches.empty?
  puts "No existing branches have been merged into #{current_branch}."
else
  puts "This will remove the following branches:"
  puts remote_branches.join("\n")
  puts local_branches.join("\n")
  puts "Proceed?"
  if gets =~ /^y/i
    remote_branches.each do |b|
      remote, branch = b.split(/\//)
      `git push #{remote} :#{branch}`
    end

    # Remove local branches
    `git branch -d #{local_branches.join(' ')}`
  else
    puts "No branches removed."
  end
end
Peter Mortensen
  • 28,342
  • 21
  • 95
  • 123
mmrobins
  • 10,669
  • 7
  • 37
  • 40
  • Mind if I steal this tidbit for a little git helper library? https://github.com/yupiq/git-branch-util – logan Dec 19 '12 at 22:28
  • 1
    Go for it, I wouldn't have put it here if I cared about people reusing the code in some way – mmrobins May 20 '13 at 20:56
  • @mmrobins You have an extra `\/` at the beginning of the reject statement for the `remote_branches` line. Is that a typo or does it serve a purpose? – Jawwad Jan 27 '16 at 17:46
  • @mmrobins, oh never mind I see the `b.split(/\//)` line now – Jawwad Jan 27 '16 at 17:52
  • If you want to do basically this but via vanilla bash rather than ruby: http://stackoverflow.com/a/37999948/430128 – Raman Jun 23 '16 at 19:14
11

How to delete merged branches in PowerShell console

git branch --merged | %{git branch -d $_.Trim()}

If you want to exclude master or any other branch names, you can pipe with PowerShell Select-String like this and pass the result to git branch -d:

git branch -d $(git branch --merged | Select-String -NotMatch "master" | %{$_.ToString().Trim()})
Community
  • 1
  • 1
Konstantin Tarkus
  • 35,208
  • 14
  • 127
  • 117
  • 1
    Higher answers are suggesting filtering master or other branches. For those looking to do that in powershell: git branch --merged | findstr /v "master" | %{git branch -d $_.trim()} – tredzko Jul 28 '15 at 15:03
  • @tredzko Good point. FTR the higher answer is http://stackoverflow.com/questions/6127328/how-can-i-delete-all-git-branches-which-have-been-merged#comment41181501_24143004 - you could repost your comment with that linked and I'd then delete this – Ruben Bartelink Feb 23 '16 at 11:40
  • it also tries to delete `* master` :) – iesen Dec 15 '17 at 08:37
9

kuboon's answer missed deleting branches which have the word master in the branch name. The following improves on his answer:

git branch -r --merged | grep -v "origin/master$" | sed 's/\s*origin\///' | xargs -n 1 git push --delete origin

Of course, it does not delete the "master" branch itself :)

Paras
  • 632
  • 6
  • 15
9

Note: I am not happy with previous answers, (not working on all systems, not working on remote, not specifying the --merged branch, not filtering exactly). So, I add my own answer.

There are two main cases:

Local

You want to delete local branches that are already merged to another local branch. During the deletion, you want to keep some important branches, like master, develop, etc.

git branch --format "%(refname:short)" --merged master | grep -E -v '^master$|^feature/develop$' | xargs -n 1 git branch -d

Notes:

  • git branch output --format ".." is to strip whitespaces and allow exact grep matching
  • grep -E is used instead of egrep, so it works also in systems without egrep (i.e.: git for windows).
  • grep -E -v '^master$|^feature/develop$' is to specify local branches that I don't want to delete
  • xargs -n 1 git branch -d: perform the deletion of local branches (it won't work for remote ones)
  • of course you get an error if you try deleting the branch currently checked-out. So, I suggest to switch to master beforehand.

Remote

You want to delete remote branches that are already merged to another remote branch. During the deletion, you want to keep some important branches, like HEAD, master, releases, etc.

git branch -r --format "%(refname:short)" --merged origin/master | grep -E -v '^*HEAD$|^*/master$|^*release' | cut -d/ -f2- | xargs -n 1 git push --delete origin

Notes:

  • for remote, we use the -r option and provide the full branch name: origin/master
  • grep -E -v '^*HEAD$|^*/master$|^*release' is to match the remote branches that we don't want to delete.
  • cut -d/ -f2- : remove the unneeded 'origin/' prefix that otherwise is printed out by the git branch command.
  • xargs -n 1 git push --delete origin : perform the deletion of remote branches.
psuzzi
  • 1,709
  • 1
  • 16
  • 18
8

There is no command in Git that will do this for you automatically. But you can write a script that uses Git commands to give you what you need. This could be done in many ways depending on what branching model you are using.

If you need to know if a branch has been merged into master the following command will yield no output if myTopicBranch has been merged (i.e. you can delete it)

$ git rev-list master | grep $(git rev-parse myTopicBranch)

You could use the Git branch command and parse out all branches in Bash and do a for loop over all branches. In this loop you check with above command if you can delete the branch or not.

Peter Mortensen
  • 28,342
  • 21
  • 95
  • 123
ralphtheninja
  • 107,622
  • 20
  • 101
  • 118
7

git branch --merged | grep -Ev '^(. master|\*)' | xargs -n 1 git branch -d will delete all local branches except the current checked out branch and/or master.

Here's a helpful article for those looking to understand these commands: Git Clean: Delete Already Merged Branches, by Steven Harman.

styger
  • 410
  • 3
  • 12
7

You can use gbda alias if you're using OhMyZSH with git plugin.

Dan K.K.
  • 4,999
  • 2
  • 26
  • 33
6

You can use git-del-br tool.

git-del-br -a

You can install it via pip using

pip install git-del-br

P.S: I am the author of the tool. Any suggestions/feedback are welcome.

tusharmakkar08
  • 656
  • 1
  • 11
  • 31
5

If you'd like to delete all local branches that are already merged in to the branch that you are currently on, then I've come up with a safe command to do so, based on earlier answers:

git branch --merged | grep -v \* | grep -v '^\s*master$' | xargs -t -n 1 git branch -d

This command will not affect your current branch or your master branch. It will also tell you what it's doing before it does it, using the -t flag of xargs.

chrismendis
  • 71
  • 1
  • 2
5

I use a git-flow esque naming scheme, so this works very safely for me:

git branch --merged | grep -e "^\s\+\(fix\|feature\)/" | xargs git branch -d

It basically looks for merged commits that start with either string fix/ or feature/.

Peter Mortensen
  • 28,342
  • 21
  • 95
  • 123
Chad M
  • 784
  • 8
  • 20
5

Alias version of Adam's updated answer:

[alias]
    branch-cleanup = "!git branch --merged | egrep -v \"(^\\*|master|dev)\" | xargs git branch -d #"

Also, see this answer for handy tips on escaping complex aliases.

Community
  • 1
  • 1
Eliot
  • 4,685
  • 3
  • 28
  • 28
5

On Windows with git bash installed egrep -v will not work

git branch --merged | grep -E -v "(master|test|dev)" | xargs git branch -d

where grep -E -v is equivalent of egrep -v

Use -d to remove already merged branches or -D to remove unmerged branches

Community
  • 1
  • 1
DevWL
  • 11,946
  • 5
  • 71
  • 69
4

Based on some of these answers I made my own Bash script to do it too!

It uses git branch --merged and git branch -d to delete the branches that have been merged and prompts you for each of the branches before deleting.

merged_branches(){
  local current_branch=$(git rev-parse --abbrev-ref HEAD)
  for branch in $(git branch --merged | cut -c3-)
    do
      echo "Branch $branch is already merged into $current_branch."
      echo "Would you like to delete it? [Y]es/[N]o "
      read REPLY
      if [[ $REPLY =~ ^[Yy] ]]; then
        git branch -d $branch
      fi
  done
}
Peter Mortensen
  • 28,342
  • 21
  • 95
  • 123
earlonrails
  • 4,448
  • 2
  • 28
  • 47
4

Try the following command:

git branch -d $(git branch --merged | grep -vw $(git rev-parse --abbrev-ref HEAD))

By using git rev-parse will get the current branch name in order to exclude it. If you got the error, that means there are no local branches to remove.

To do the same with remote branches (change origin with your remote name), try:

git push origin -vd $(git branch -r --merged | grep -vw $(git rev-parse --abbrev-ref HEAD) | cut -d/ -f2)

In case you've multiple remotes, add grep origin | before cut to filter only the origin.

If above command fails, try to delete the merged remote-tracking branches first:

git branch -rd $(git branch -r --merged | grep -vw $(git rev-parse --abbrev-ref HEAD))

Then git fetch the remote again and use the previous git push -vdcommand again.

If you're using it often, consider adding as aliases into your ~/.gitconfig file.

In case you've removed some branches by mistake, use git reflog to find the lost commits.

HK boy
  • 1,380
  • 11
  • 16
  • 21
kenorb
  • 118,428
  • 63
  • 588
  • 624
4

Below query works for me

for branch in  `git branch -r --merged | grep -v '\*\|master\|develop'|awk 'NR > 0 {print$1}'|awk '{gsub(/origin\//, "")}1'`;do git push origin --delete $branch; done

and this will filter any given branch in the grep pipe.

Works well over http clone, but not so well for the ssh connection.

4

The accepted solution is pretty good, but has the one issue that it also deletes local branches that were not yet merged into a remote.

If you look at the output of you will see something like

$ git branch --merged master -v
  api_doc                  3a05427 [gone] Start of describing the Java API
  bla                      52e080a Update wording.
  branch-1.0               32f1a72 [maven-release-plugin] prepare release 1.0.1
  initial_proposal         6e59fb0 [gone] Original proposal, converted to AsciiDoc.
  issue_248                be2ba3c Skip unit-for-type checking. This needs more work. (#254)
  master                   be2ba3c Skip unit-for-type checking. This needs more work. (#254)

Branches bla and issue_248 are local branches that would be deleted silently.

But you can also see the word [gone], which indicate branches that had been pushed to a remote (which is now gone) and thus denote branches can be deleted.

The original answer can thus be changed to (split into multiline for shorter line length)

git branch --merged master -v | \
     grep  "\\[gone\\]" | \
     sed -e 's/^..//' -e 's/\S* .*//' | \
      xargs git branch -d

to protect the not yet merged branches. Also the grepping for master to protect it, is not needed, as this has a remote at origin and does not show up as gone.

Heiko Rupp
  • 28,212
  • 13
  • 79
  • 118
4

As of 2018.07

Add this to [alias] section of your ~/.gitconfig:

sweep = !"f() { git branch --merged | egrep -v \"(^\\*|master|dev)\" || true | xargs git branch -d; }; f"

Now you can just call git sweep to perform that needed cleanup.

sorin
  • 137,198
  • 150
  • 472
  • 707
4

I've been using the following method to remove merged local AND remote branches in one cmd.

I have the following in my bashrc file:

function rmb {
  current_branch=$(git branch --no-color 2> /dev/null | sed -e '/^[^*]/d' -e 's/* \(.*\)/\1/')
  if [ "$current_branch" != "master" ]; then
    echo "WARNING: You are on branch $current_branch, NOT master."
  fi
  echo "Fetching merged branches..."
  git remote prune origin
  remote_branches=$(git branch -r --merged | grep -v '/master$' | grep -v "/$current_branch$")
  local_branches=$(git branch --merged | grep -v 'master$' | grep -v "$current_branch$")
  if [ -z "$remote_branches" ] && [ -z "$local_branches" ]; then
    echo "No existing branches have been merged into $current_branch."
  else
    echo "This will remove the following branches:"
    if [ -n "$remote_branches" ]; then
      echo "$remote_branches"
    fi
    if [ -n "$local_branches" ]; then
      echo "$local_branches"
    fi
    read -p "Continue? (y/n): " -n 1 choice
    echo
    if [ "$choice" == "y" ] || [ "$choice" == "Y" ]; then
      # Remove remote branches
      git push origin `git branch -r --merged | grep -v '/master$' | grep -v "/$current_branch$" | sed 's/origin\//:/g' | tr -d '\n'`
      # Remove local branches
      git branch -d `git branch --merged | grep -v 'master$' | grep -v "$current_branch$" | sed 's/origin\///g' | tr -d '\n'`
    else
      echo "No branches removed."
    fi
  fi
}

original source

This doesn't delete the master branch, but removes merged local AND remote branches. Once you have this in you rc file, just run rmb, you're shown a list of merged branches that will be cleaned and asked for confirmation on the action. You can modify the code to not ask for confirmation as well, but it's probably good to keep it in.

Nelu
  • 11,174
  • 7
  • 61
  • 72
Prashant
  • 984
  • 10
  • 28
3

Write a script in which Git checks out all the branches that have been merged to master.

Then do git checkout master.

Finally, delete the merged branches.

for k in $(git branch -ra --merged | egrep -v "(^\*|master)"); do
  branchnew=$(echo $k | sed -e "s/origin\///" | sed -e "s/remotes\///")
  echo branch-name: $branchnew
  git checkout $branchnew
done

git checkout master

for k in $(git branch -ra --merged | egrep -v "(^\*|master)"); do
  branchnew=$(echo $k | sed -e "s/origin\///" | sed -e "s/remotes\///")
  echo branch-name: $branchnew
  git push origin --delete $branchnew
done
Peter Mortensen
  • 28,342
  • 21
  • 95
  • 123
Komu
  • 11,516
  • 2
  • 24
  • 21
3

For me git branch --merged doesn't show branches that were merged via GitHub PR. I'm not sure of the reasons, but I use the following line to delete all local branches that do not have remote tracking branch:

diff <(git branch --format "%(refname:short)") <(git branch -r | grep -v HEAD | cut -d/ -f2-) | grep '<' | cut -c 3- | xargs git branch -D

Explanation:

  • git branch --format "%(refname:short)" gives a list of local branches
  • git branch -r | grep -v HEAD | cut -d/ -f2- gives a list of remote branches, filtering out HEAD
  • diff <(...) <(...) gives a diff of output of two commands inside parentheses
  • grep '<' filters branches that exist in first list, but not in the second
  • cut -c 3- gives line starting from 3rd character, thus removing prefix <
  • xargs git branch -D executes git branch -D against each branch name

Alternatively, you can avoid grep -v '<' like this:

diff --old-line-format="%L" --new-line-format="" --unchanged-line-format="" <(git branch --format "%(refname:short)") <(git branch -r | grep -v HEAD | cut -d/ -f2-) | xargs git branch -D
folex
  • 4,672
  • 1
  • 22
  • 43
2

To avoid accidentally running the command from any other branch than master I use the following bash script. Otherwise, running git branch --merged | grep -v "\*" | xargs -n 1 git branch -d from a branch that has been merged of off master could delete the master branch.

#!/bin/bash

branch_name="$(git symbolic-ref HEAD 2>/dev/null)" ||
branch_name="(unnamed branch)"     # detached HEAD
branch_name=${branch_name##refs/heads/}

if [[ $branch_name == 'master' ]]; then
   read -r -p "Are you sure? [y/N] " response
   if [[ $response =~ ^([yY][eE][sS]|[yY])$ ]]; then
       git branch --merged | grep -v "\*" | xargs -n 1 git branch -d
   fi
else
   echo "Refusing to delete branches that are not merged into '$branch_name'. Checkout master first."
fi
Robert Kajic
  • 7,605
  • 3
  • 41
  • 42
1

To delete local branches that have been merged to master branch I'm using the following alias (git config -e --global):

cleanup = "!git branch --merged master | grep -v '^*\\|master' | xargs -n 1 git branch -D"

I'm using git branch -D to avoid error: The branch 'some-branch' is not fully merged. messages while my current checkout is different from master branch.

dgt
  • 842
  • 7
  • 9
1

Let's say I have a remote named upstream and an origin (GitHub style, my fork is origin, upstream is upstream).

I don't want to delete ANY masters, HEAD, or anything from the upstream. I also don't want to delete the develop branch as that is our common branch we create PRs from.

List all remote branches, filtered by ones that were merged:

git branch -r

Remove lines from that list that contain words I know are in branch names I don't want to remove:

sed '/develop\|master\|HEAD\|upstream/d'

Remove the remote name from the reference name (origin/somebranch becomes somebranch):

sed 's/.*\///'

Use xargs to call a one-liner:

xargs git push --delete origin

Pipe it all together you get:

git branch -r --merged | sed '/develop\|master\|HEAD\|upstream/d' |  sed 's/.*\///' | xargs git push --delete origin

This will leave me with only some branches that I have worked on, but have not merged. You can then remove them one by one as there shouldn't be too many.

Find branches you no longer want:

git branch -ar

Say you find branch1, branch2, and branch3 you want to delete:

git push --delete origin branch1 branch2 branch3
Peter Mortensen
  • 28,342
  • 21
  • 95
  • 123
miigotu
  • 937
  • 11
  • 13
1
$ git config --global alias.cleanup
'!git branch --merged origin/master | egrep -v "(^\*|master|staging|dev)" | xargs git branch -d'

(Split into multiple lines for readability)

Calling "git cleanup" will delete local branches that have already been merged into origin/master. It skips master, staging, and dev because we don't want to delete those in normal circumstances.

Breaking this down, this is what it's doing:

  1. git config --global alias.cleanup
    • This is creating a global alias called "cleanup" (across all your repos)
  2. The ! at the beginning of the command is saying that we will be using some non-git commands as part of this alias so we need to actually run bash commands here
  3. git branch --merged origin/master
    • This command returns the list of branch names that have already been merged into origin/master
  4. egrep -v "(^\*|master|staging|dev)"
    • This removes the master, staging, and dev branch from the list of branches that have already been merged. We don't want to remove these branches since they are not features.
  5. xargs git branch -d
    • This will run the git branch -d xxxxx command for each of the unmerged branches. This deletes the local branches one by one.
Joe Phillips
  • 44,686
  • 25
  • 93
  • 148
1

For Windows you can install Cygwin and remove all remote branches using following command:

git branch -r --merged | "C:\cygwin64\bin\grep.exe" -v master | "C:\cygwin64\bin\sed.exe" 's/origin\///' | "C:\cygwin64\bin\xargs.exe" -n 1 git push --delete origin
Seyed Morteza Mousavi
  • 6,257
  • 8
  • 38
  • 63
1

The simplest way I found to do it removing only local branches, not remote ones:

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

This command will delete only branches already merged in your master one. Be careful if you don't want to delete other branches, such as a staging.

lucianosousa
  • 7,548
  • 4
  • 17
  • 25
1

Just created python script for that:

import sys
from shutil import which
import logging
from subprocess import check_output, call

logger = logging.getLogger(__name__)

if __name__ == '__main__':
    if which("git") is None:
        logger.error("git is not found!")
        sys.exit(-1)

    branches = check_output("git branch -r --merged".split()).strip().decode("utf8").splitlines()
    current = check_output("git branch --show-current".split()).strip().decode("utf8")
    blacklist = ["master", current]

    for b in branches:
        b = b.split("/")[-1]

        if b in blacklist:
            continue
        else:
            if input(f"Do you want to delete branch: '{b}' [y/n]\n").lower() == "y":
                call(f"git branch -D {b}".split())
                call(f"git push --delete origin {b}".split())

RedEyed
  • 1,576
  • 1
  • 16
  • 24
1

To delete merged branches, git-delete-merged-branches is more robust and more convenient than shell hacks. It also detects rebase merges and squash merges. Its readme has more details.

Sebastian
  • 61
  • 1
  • 3
1

git cleanup script from the git-toolbelt

Deletes all branches that have already been merged into master or develop. Keeps other branches lying around. Will be most conservative with deletions.

Removes branches both locally and in the origin remote.

Lu55
  • 17,620
  • 4
  • 65
  • 60
0

Windoze-friendly Python script (because git-sweep choked on Wesnoth repository):

#!/usr/bin/env python
# Remove merged git branches. Cross-platform way to execute:
#
#   git branch --merged | grep -v master | xargs git branch -d
#
# Requires gitapi - https://bitbucket.org/haard/gitapi
# License: Public Domain

import gitapi

repo = gitapi.Repo('.')
output = repo.git_command('branch', '--merged').strip()
for branch in output.split('\n'):
  branch = branch.strip()
  if branch.strip(' *') != 'master':
    print(repo.git_command('branch', '-d', branch).strip())

https://gist.github.com/techtonik/b3f0d4b9a56dbacb3afc

anatoly techtonik
  • 17,421
  • 8
  • 111
  • 131
0

If you are using branching model like HubFlow or GitFlow you can use this command to remove the merged feature branches:

git branch --merged | grep feature.* | grep -v "\*" | xargs -n 1 git branch -d
HK boy
  • 1,380
  • 11
  • 16
  • 21
bedrin
  • 3,939
  • 25
  • 48
0

If you wish to delete local branches that have been merged as well as delete their remotes here's the one-liner I prefer:

git branch --merged | xargs -I_br -- sh -c 'git branch -d _br; git push origin --delete _br'
Ikar Pohorský
  • 3,559
  • 2
  • 29
  • 49
0

My Bash script contribution is based loosely on mmrobin's answer.

It takes some useful parameters specifying includes and excludes, or to examine/remove only local or remote branches instead of both.

#!/bin/bash

# exclude branches regex, configure as "(branch1|branch2|etc)$"
excludes_default="(master|next|ag/doc-updates)$"
excludes="__NOTHING__"
includes=
merged="--merged"
local=1
remote=1

while [ $# -gt 0 ]; do
  case "$1" in
  -i) shift; includes="$includes $1" ;;
  -e) shift; excludes="$1" ;;
  --no-local) local=0 ;;
  --no-remote) remote=0 ;;
  --all) merged= ;;
  *) echo "Unknown argument $1"; exit 1 ;;
  esac
  shift   # next option
done

if [ "$includes" == "" ]; then
  includes=".*"
else
  includes="($(echo $includes | sed -e 's/ /|/g'))"
fi

current_branch=$(git branch --no-color 2> /dev/null | sed -e '/^[^*]/d' -e 's/* \(.*\)/\1/')
if [ "$current_branch" != "master" ]; then
  echo "WARNING: You are on branch $current_branch, NOT master."
fi
echo -e "Fetching branches...\n"

git remote update --prune
remote_branches=$(git branch -r $merged | grep -v "/$current_branch$" | grep -v -E "$excludes" | grep -v -E "$excludes_default" | grep -E "$includes")
local_branches=$(git branch $merged | grep -v "$current_branch$" | grep -v -E "$excludes" | grep -v -E "$excludes_default" | grep -E "$includes")
if [ -z "$remote_branches" ] && [ -z "$local_branches" ]; then
  echo "No existing branches have been merged into $current_branch."
else
  echo "This will remove the following branches:"
  if [ "$remote" == 1 -a -n "$remote_branches" ]; then
    echo "$remote_branches"
  fi
  if [ "$local" == 1 -a -n "$local_branches" ]; then
    echo "$local_branches"
  fi
  read -p "Continue? (y/n): " -n 1 choice
  echo
  if [ "$choice" == "y" ] || [ "$choice" == "Y" ]; then
    if [ "$remote" == 1 ]; then
      remotes=$(git remote)
      # Remove remote branches
      for remote in $remotes
      do
        branches=$(echo "$remote_branches" | grep "$remote/" | sed "s/$remote\/\(.*\)/:\1 /g" | tr -d '\n')
        git push $remote $branches
      done
    fi

    if [ "$local" == 1 ]; then
      # Remove local branches
      locals=$(echo "$local_branches" | sed 's/origin\///g' | tr -d '\n')
      if [ -z "$locals" ]; then
        echo "No branches removed."
      else
        git branch -d $(echo "$locals" | tr -d '\n')
      fi
    fi
  fi
fi
Peter Mortensen
  • 28,342
  • 21
  • 95
  • 123
Raman
  • 13,024
  • 3
  • 72
  • 95
0

git-delete-merged-branches from git-extras repo.

https://github.com/tj/git-extras/blob/master/Commands.md#git-delete-merged-branches

holys
  • 11,255
  • 12
  • 40
  • 50
0

Given you want to delete the merged branches, you need to delete the remote-tracking branches only, unless you state otherwise.

So to delete those branches you can do it by

git branch --remote --merged origin/master | egrep -v "(^\*|master|development)" | cut -b 10- | xargs git push --delete origin

This will delete all merged branches (merged to master) except master and development.

Paulo Fidalgo
  • 19,844
  • 7
  • 85
  • 108
0

I use this:

git branch --delete $(git branch --format '%(refname:short)' --merged)

It lists all merged branched in the specified format, then it feeds that list to git branch --delete.

Elmer
  • 8,198
  • 1
  • 41
  • 34