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?
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 -vd
command 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.
git branch -D deletes branches that have NOT been merged! Use with care!
– Dan Solovay
Dec 23 '16 at 14:05