How can I delete all Git branches which have been merged?
Solution 1
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
Solution 2
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 ...
Solution 3
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 -r git branch -d"
And then you can delete all the local merged branches doing a simple git cleanup
.
Solution 4
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
Solution 5
This also works to delete all merged branches except master.
git branch --merged | grep -v '^* master$' | grep -v '^ master$' | xargs git branch -d
Comments
-
Nyambaa almost 2 years
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?
-
Nyambaa almost 13 yearsyeah, 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.
-
Adam Dymitruk almost 13 yearsgit checkout master; for branch in $(git branch --raw); do git branch --contains $branch && git branch -d $branch; done
-
Gary over 12 yearsgit branch --merged | sed 's/\*/ /' | xargs -n 1 git branch -d --Gets rid of that pesky asteryx
-
logan over 11 yearsMind if I steal this tidbit for a little git helper library? github.com/yupiq/git-branch-util
-
mmrobins almost 11 yearsGo for it, I wouldn't have put it here if I cared about people reusing the code in some way
-
Gary Haran almost 11 yearsWARNING: 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.
-
Sam almost 11 yearsI'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.
-
wchargin over 10 yearsNow it won't delete any branch with
master
in it. Trygrep -v ^master$
for the middle. -
General Redneck over 10 yearsSo, 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
-
Dorian over 10 yearsBest answer by far. Just a note, my master branch is named
dev
so I had to change that -
Admin over 9 yearsYeah I was about the use the same...I think there should be a warning at the top of answer
-
Adam Dymitruk over 9 yearsOPPOSITE OF WARNING: reflog will save your bacon. So don't worry.
-
svassr over 9 yearsI'd also let
| grep -v '^\*'
to avoid deletting current branch if you are not on master -
ifightcrime over 9 yearsKeep in mind that the first command only deletes local branches, so it isn't as 'dangerous' as some have pointed out.
-
Iain Ballard over 9 yearsFor curiosity sake, this can be shortened to
git branch --merged | ?{-not ($_ -like "*master")} | %{git branch -d $_.trim()}
-
Klas Mellbourn over 9 years@IainBallard Sure, I could have used aliases. That is not recommended when you want to maximize readability. github.com/darkoperator/PSStyleGuide/blob/master/English.md
-
Iain Ballard over 9 yearssure. 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.
-
styger over 9 yearsThis 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 deletemaster
if you're not on it. -
Stephen about 9 yearsOPPOSITE 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 -
jthill about 9 yearsreflog 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}
ormaster@{yesterday noon}
-
L0LN1NJ4 almost 9 yearsI had to add
| grep origin
aftergrep -v master
to prevent pushing branches of other remotes to origin. Highly recommending testing the output beforehand, usinggit branch -r --merged | grep -v master | grep origin | sed 's/origin\//:/' | xargs -n 1 echo
-
malko almost 9 years+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
-
Rushabh Mehta almost 9 yearsAdd
--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
-
tredzko almost 9 yearsHigher 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()}
-
sarat almost 9 yearsI 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. -
iwein over 8 yearsI like the test option
-
Wazery over 8 yearsThis can delete the
master
branch btw! -
drautb over 8 yearsTrue. I only use it when I'm sure I'm on
master
. -
Asbjørn Ulsberg over 8 yearsWhat 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. -
styger over 8 years@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. -
T3rm1 over 8 years
git config --global --add fetch.prune true
to prune automatically on fetch or pull. -
vorou over 8 yearsPowerShell 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 $_}
-
jakub.g over 8 yearsApart from
| grep origin
you can also add--no-verify
at the end to skip git pre-push hook -
Jawwad over 8 years@mmrobins You have an extra
\/
at the beginning of the reject statement for theremote_branches
line. Is that a typo or does it serve a purpose? -
Jawwad over 8 years@mmrobins, oh never mind I see the
b.split(/\//)
line now -
jakub.g over 8 yearsCaution - just realized: this will obviously find branches merged to current branch, not master, so if you are on
myFeatureBranch
it will wipeorigin/myFeatureBranch
. Probably it's best togit checkout master
first. -
Marius Gedminas over 8 yearsThis produces an error
fatal: branch name required
if you have no branches that should be deleted. To avoid that you can pass-r
toxargs
so it won't rungit branch -d
if the stdin is empty. (This a GNU xargs extension, according to the man page). -
Raymond about 8 years@tredzko Good point. FTR the higher answer is stackoverflow.com/questions/6127328/… - you could repost your comment with that linked and I'd then delete this
-
Vyskol almost 8 yearsThis 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. -
jessepinho almost 8 yearsI created a bash function to prune both merged branches and remote merged branches, if this helps anyone.
-
Raman almost 8 yearsIf you want to do basically this but via vanilla bash rather than ruby: stackoverflow.com/a/37999948/430128
-
Joe Phillips almost 8 yearsshouldn'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? -
smohamed almost 8 years@JoePhilllips Some people has the main branch not master but instead
develop
ordev
and in that case the command will fail withfatal: malformed object name
it's better to have a generic command and you have the responsibility to run it -
Joe Phillips almost 8 years@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
-
real_ate almost 8 years@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
-
Jeff Puckett over 7 years@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 over 7 years@SKandeel it might also be interesting to note that on another one of Adam's very similar answers, he does qualify it with
master
-
Sean over 7 years@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.
-
John over 7 yearsPowerShell 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 $_}
-
tusharmakkar08 over 7 years@stackoverflow.com/users/100297/martijn-pieters : Why was this answer deleted and downvoted?
-
LOKESH K V over 7 years@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 [email protected]:root/myproj.git - [deleted] shield_square_removal
-
Guido Bouman over 7 yearsMind 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.
-
yoyo over 7 yearsHere'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) -
danielricecodes about 7 yearsThanks! I just added an
alias
to my~/.profile
! Very helpful answer! -
Knut Holm almost 7 years@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) -
spezifanta almost 7 yearsAdding
-r
toxargs
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"
-
real_ate almost 7 yearsIs 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: i.stack.imgur.com/QAY2H.png
-
danielricecodes almost 7 years@Akarienta -
alias git-branch-clean="git branch --merged | egrep -v \"(^\*|master|dev|staging|production)\" | xargs git branch -d"
-
scones almost 7 yearsWARNING: This also closes open pull requests.
-
scones almost 7 yearsThe 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.
-
Diego almost 7 years
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. -
Greg Rundlett over 6 years
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. -
Daniel Alder over 6 yearsWarning:
git branch --merged
without further arguments will show all branches which are merged into the current checkedout branch. You should always use something likegit branch --merged origin/master
-
SpoiledTechie.com over 6 yearsYour answer and tool don't work. I spend a couple hours on it. Nothing.
-
tusharmakkar08 over 6 years@SpoiledTechie.com: Can you tell me what problem are you facing exactly? I am using it on a regular basis.
-
SpoiledTechie.com over 6 yearsI can share a screenshot if you want to take this offline? spoiledtechie at that google mail thing. :)
-
iesen over 6 yearsit also tries to delete
* master
:) -
voiski over 6 yearsFull 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-)
-
lanierhall over 6 years
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. -
lamplightdev about 6 yearsIf 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 -
alexg about 6 years
git branch -d $(git branch --merged | grep -v master)
-
Stuart Axon about 6 yearsThis doesn't work if you have branches named like feature/my-feature as it eats the slash.
-
Robert Pankowecki about 6 yearsI had to add the
--no-color
switch before--merged
:git branch --no-color --merged | egrep -v "(^\*|master|dev)" | xargs git branch -d
-
Victor Moraes almost 6 yearsFor me, calling git sweep only lists the branches that should be cleaned up, but it does not remove them
-
DanSingerman almost 6 yearsI come here about once a week
-
Joe Phillips almost 6 yearsegrep -v works for me. I'm using gitbash from the gitextensions installer though
-
Alex Harvey almost 6 yearsIt would be better if the regexp explicitly marked the end of line character, i.e.
git branch --merged | egrep -v "(^\*|master)$"
. -
carl verbiest over 5 yearsThe egrep pattern excludes all branches containing master, not just master itself, fix by using
egrep -v "^(\* .*| *master| *dev)$"
-
Danilo Souza Morães over 5 yearsI 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 -
GPHemsley over 5 yearsTo 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
-
Bogdan Alexandru Militaru over 5 yearsI 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 -
Andriy F. about 5 yearsCurrent command doesn't filter out master and develop branches
-
real_ate about 5 years@AndriyF. what platform are you using? the current command works well for me and does filter out master and develop :)
-
Andriy F. about 5 years@real_ate Linux OpensSuse git 2.16.4 grep 3.1
-
g9ncom about 5 yearsCombining 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. -
Rip3rs about 5 yearsThis is dangerous if you have a flow, imagine you have master <- stage <- dev. Still easiest solution imo
-
Earlee about 5 yearsright now, this project is no longer maintained. See github.com/arc90/git-sweep/pull/43
-
VasiliNovikov almost 5 yearsWhy do you need to create a function? Isn't
git config
atomic? -
eddies almost 5 yearsTo deal with the optional '-f' argument (if I understand your question correctly)
-
VasiliNovikov almost 5 yearsbut how does it help? I mean the start of the expression,
!f(){ git branch ...
. It's a function declaration, right? Why not start directly withgit branch ...
? -
eddies almost 5 yearsYou're absolutely right. Edited my answer accordingly. Thanks for the pointer!
-
efx over 4 yearsYou can eliminate the
sed
step by using the--format
to include only the needed part of the refgit branch --format "%(refname:lstrip=3)" --remotes --merged
The available field names are documented here. They are not the same as the format for other git sub commands. -
Guido Bouman over 4 yearsWould 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 deletedevelop
, but might be a simpler approach. -
eddies over 4 years@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. -
0CDc0d3r about 4 yearsMy 2 cents: In case you'd want to delete merged branches on remote, while excluding
master
and/ordev
, you will need to trim some of the output sincegit 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
-
user137369 about 4 yearsIn the last command, it should be
git checkout master &&
, notgit checkout master |
. -
DarVar almost 4 yearsIs it possible to add a git alias for this?
-
Dr_Zaszuś almost 4 yearsNaturally, this won't work on Windows since it uses
egrep
... -
mutoe almost 4 yearsIf you using zsh, you can type
gbda
to apply this command -
Samantha Adrichem almost 4 yearsThnx! I made a bash one-liner of it
for i in `git branch --merged| egrep -v "(^\*|master|dev)"`; do git branch -d ${i}; done;
-
vinnymac over 3 years@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
-
Michael Freidgeim over 3 years@scones, can you clarify your warning about closing open pull requests ?stackoverflow.com/questions/65444886/…
-
scones about 3 years@MichaelFreidgeim sure. if you execute the commands, your pull requests will be closed. not merged tho.
-
M. Reza Nasirloo about 3 yearsChanging the
-n 1
to a higher value deletes more branches at once -
Trent almost 3 yearsThis is a seriously undervoted answer. Combine this approach with the verbosity of the top answer and it's a winner: git branch --merged| egrep -v "(^*|master|main|dev|skip_branch_name)"
-
Elmer almost 3 yearsye I sometimes do it like that! included it in the answer!
-
David Millar almost 3 yearsNote that you should be on the fully updated master branch when you run the remote one, otherwise you risk deleting the branch you're currently on from remote and losing some pull requests and such.
-
Guido Bouman over 2 yearsUhmm... How would that happen? If master is not updated, the branches are not merged in, and thus do not get removed.
-
cDitch over 2 yearsThanks for this!
-
Viktor Ivliiev over 2 yearsdelete all but the selected ones
git branch | grep -E -v "(master|develop|other)" | xargs git branch -D
-
Stefan over 2 yearsDoes this delete all branches merged by the current user or by any user?
-
Jacob Eggers about 2 yearsI like this, but had to change it a bit to work with multiple remotes:
git branch -r --merged | sed '/main/d' | sed 's/\//\n/' | cat | xargs -L2 bash -c 'git push --delete $0 $1'
-
ted about 2 yearsThis uses hardcoded branch names, shameless selfplug, I added an answer which avoids this problem, and where the alias can be created from the command line rather than be editing the config file (simple copy paste).