How can I delete all Git branches which have been merged?


How can I delete all Git branches which have been merged?



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?





git branch -D deletes branches that have NOT been merged! Use with care!
– Dan Solovay
Dec 23 '16 at 14:05





To be slightly more specific git branch -D deletes any branch whether it as been merged or not.
– PhilT
Feb 8 '17 at 9:48


git branch -D





You can also do this directly from GitHub, if you go to the 'branches' section of your repo (e.g. github.com/<username>/<repo_name>/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 ).
– user5359531
Feb 24 '17 at 16:13



master


git branch -a


git fetch --prune





Script to do this locally or remotely - with safety checks and pre-configured "safe branches": github.com/fatso83/dotfiles/tree/master/utils/… git delete-merged --doit origin or git delete-merged --doit --local
– oligofren
Jun 27 '17 at 15:10



git delete-merged --doit origin


git delete-merged --doit --local




34 Answers
34



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.



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


git branch --merged | egrep -v "(^*|master|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 in old versions of Git use:


git push origin :branchname



In more recent versions of Git use:


git push --delete origin branchname



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



Hope this helps.





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





OPPOSITE OF WARNING: reflog will save your bacon. So don't worry.
– Adam Dymitruk
Aug 20 '14 at 1:05





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





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 8:12


git branch --merged | %{$_.trim()} | ?{$_ -notmatch 'develop' -and $_ -notmatch 'master'} | %{git branch -d $_}





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 9 '16 at 14:40


fatal: branch name required


-r


xargs


git branch -d



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





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


dev





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 8 '15 at 8:06


| grep origin


grep -v master


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





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



develop


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





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 2 '15 at 17:49


-r





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 5 '16 at 14:40


myFeatureBranch


origin/myFeatureBranch


git checkout master



Just extending Adam's answer a little bit:



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


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.


git cleanup





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


git branch --merged master





@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
– SKandeel
Aug 13 '16 at 1:14



develop


dev


fatal: malformed object name





@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





@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 7:39





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 9:14


-r


xargs


branch name required


cleanup = "!git branch --merged | grep -v -P '^\*|master|develop' | xargs -n1 -r git branch -d"



This also works to delete all merged branches except master.


git branch --merged | grep -v '^* master$' | grep -v '^ master$' | xargs git branch -d





Now it won't delete any branch with master in it. Try grep -v ^master$ for the middle.
– wchargin
Oct 12 '13 at 2:26


master


grep -v ^master$





I'd also let | grep -v '^*' to avoid deletting current branch if you are not on master
– svassr
Sep 8 '14 at 19:06



| grep -v '^*'





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



grep -v '^ master$'


master





@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 8 '15 at 21:49


git branch



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


master


develop



Local git clear:


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



Remote git clear:


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



Sync local registry of remote branches:


git fetch -p





+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 8:09





git config --global --add fetch.prune true to prune automatically on fetch or pull.
– T3rm1
Dec 18 '15 at 14:51



git config --global --add fetch.prune true





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 5 '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 9:15



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" )} |
ForEach-Object { git branch -d $_ }
}





For curiosity sake, this can be shortened to git branch --merged | ?{-not ($_ -like "*master")} | %{git branch -d $_.trim()}
– Iain Ballard
Oct 8 '14 at 8:27


git branch --merged | ?{-not ($_ -like "*master")} | %{git branch -d $_.trim()}





@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
– Klas Mellbourn
Oct 8 '14 at 11:36





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 8 '14 at 11:56





@IainBallard You are welcome :)
– Klas Mellbourn
Oct 8 '14 at 14:34





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



for /f "usebackq" %B in (``git branch --merged^|findstr /v /c:"* " /c:"master"``) do @git branch -d %B



Git Sweep does a great job of this.



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





I like the test option
– iwein
Sep 22 '15 at 9:01



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





Mind if I steal this tidbit for a little git helper library? github.com/yupiq/git-branch-util
– logan
Dec 19 '12 at 22:28





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


/


remote_branches





@mmrobins, oh never mind I see the b.split(///) line now
– Jawwad
Jan 27 '16 at 17:52


b.split(///)





If you want to do basically this but via vanilla bash rather than ruby: stackoverflow.com/a/37999948/430128
– Raman
Jun 23 '16 at 19:14



Using Git version 2.5.0:


git branch -d `git branch --merged`





This can delete the master branch btw!
– Islam Wazery
Oct 7 '15 at 13:34



master





True. I only use it when I'm sure I'm on master.
– drautb
Oct 7 '15 at 22:24


master





git branch -d $(git branch --merged | grep -v master)
– alexg
Mar 22 at 13:21



git branch -d $(git branch --merged | grep -v master)



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 :)


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



See GitHub for Windows





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 stackoverflow.com/questions/6127328/… - 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 8:37



* master



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.


for



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.


git branch --merged | grep -Ev '^(. master|*)' | xargs -n 1 git branch -d


master



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



You can use git-del-br tool.


git-del-br


git-del-br -a



You can install it via pip using


pip


pip install git-del-br



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





@stackoverflow.com/users/100297/martijn-pieters : Why was this answer deleted and downvoted?
– tusharmakkar08
Sep 29 '16 at 16:23






Your answer and tool don't work. I spend a couple hours on it. Nothing.
– SpoiledTechie.com
Nov 15 '17 at 18:55





@SpoiledTechie.com: Can you tell me what problem are you facing exactly? I am using it on a regular basis.
– tusharmakkar08
Nov 16 '17 at 9:53





I can share a screenshot if you want to take this offline? spoiledtechie at that google mail thing. :)
– SpoiledTechie.com
Nov 17 '17 at 16:12



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.



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.



Try the following command:



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


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.


git rev-parse



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


origin



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


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.


grep origin |


cut


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))


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.


git fetch


git push -vd



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


~/.gitconfig



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


git reflog



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.


git branch --merged


git branch -d


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
}



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/.


fix/


feature/



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.



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



Then do git checkout master.


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



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.


bla


issue_248



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.


[gone]



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.



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.


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


#!/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



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


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.


git branch -D


error: The branch 'some-branch' is not fully merged.



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


git-sweep


#!/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



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


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



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'


for b in $(git branch -a | grep -v "(master|remotes)"); do
git branch -D $b; done && git fetch -p



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





This doesn't work if you have branches named like feature/my-feature as it eats the slash.
– Stuart Axon
Apr 13 at 9:26






By clicking "Post Your Answer", you acknowledge that you have read our updated terms of service, privacy policy and cookie policy, and that your continued use of the website is subject to these policies.

Popular posts from this blog

List of Kim Possible characters

Audio Livestreaming with Python & Flask

NSwag: Generate C# Client from multiple Versions of an API