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

732,635

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
Share:
732,635
Nyambaa
Author by

Nyambaa

Software developer, Vim lover

Updated on July 08, 2022

Comments

  • Nyambaa
    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
    Nyambaa almost 13 years
    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.
  • Adam Dymitruk
    Adam Dymitruk almost 13 years
    git checkout master; for branch in $(git branch --raw); do git branch --contains $branch && git branch -d $branch; done
  • Gary
    Gary over 12 years
    git branch --merged | sed 's/\*/ /' | xargs -n 1 git branch -d --Gets rid of that pesky asteryx
  • logan
    logan over 11 years
    Mind if I steal this tidbit for a little git helper library? github.com/yupiq/git-branch-util
  • mmrobins
    mmrobins almost 11 years
    Go for it, I wouldn't have put it here if I cared about people reusing the code in some way
  • Gary Haran
    Gary Haran almost 11 years
    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.
  • Sam
    Sam almost 11 years
    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.
  • wchargin
    wchargin over 10 years
    Now it won't delete any branch with master in it. Try grep -v ^master$ for the middle.
  • General Redneck
    General Redneck over 10 years
    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
  • Dorian
    Dorian over 10 years
    Best answer by far. Just a note, my master branch is named dev so I had to change that
  • Admin
    Admin over 9 years
    Yeah I was about the use the same...I think there should be a warning at the top of answer
  • Adam Dymitruk
    Adam Dymitruk over 9 years
    OPPOSITE OF WARNING: reflog will save your bacon. So don't worry.
  • svassr
    svassr over 9 years
    I'd also let | grep -v '^\*' to avoid deletting current branch if you are not on master
  • ifightcrime
    ifightcrime over 9 years
    Keep in mind that the first command only deletes local branches, so it isn't as 'dangerous' as some have pointed out.
  • Iain Ballard
    Iain Ballard over 9 years
    For curiosity sake, this can be shortened to git branch --merged | ?{-not ($_ -like "*master")} | %{git branch -d $_.trim()}
  • Klas Mellbourn
    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
    Iain Ballard over 9 years
    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.
  • styger
    styger over 9 years
    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.
  • Stephen
    Stephen about 9 years
    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
  • jthill
    jthill about 9 years
    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}
  • L0LN1NJ4
    L0LN1NJ4 almost 9 years
    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
  • malko
    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
    Rushabh Mehta almost 9 years
    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
  • tredzko
    tredzko almost 9 years
    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()}
  • sarat
    sarat almost 9 years
    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.
  • iwein
    iwein over 8 years
    I like the test option
  • Wazery
    Wazery over 8 years
    This can delete the master branch btw!
  • drautb
    drautb over 8 years
    True. I only use it when I'm sure I'm on master.
  • Asbjørn Ulsberg
    Asbjørn Ulsberg over 8 years
    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.
  • styger
    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
    T3rm1 over 8 years
    git config --global --add fetch.prune true to prune automatically on fetch or pull.
  • vorou
    vorou over 8 years
    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 $_}
  • jakub.g
    jakub.g over 8 years
    Apart from | grep origin you can also add --no-verify at the end to skip git pre-push hook
  • Jawwad
    Jawwad over 8 years
    @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
    Jawwad over 8 years
    @mmrobins, oh never mind I see the b.split(/\//) line now
  • jakub.g
    jakub.g over 8 years
    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.
  • Marius Gedminas
    Marius Gedminas over 8 years
    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).
  • Raymond
    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
    Vyskol almost 8 years
    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.
  • jessepinho
    jessepinho almost 8 years
    I created a bash function to prune both merged branches and remote merged branches, if this helps anyone.
  • Raman
    Raman almost 8 years
    If you want to do basically this but via vanilla bash rather than ruby: stackoverflow.com/a/37999948/430128
  • Joe Phillips
    Joe Phillips almost 8 years
    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?
  • smohamed
    smohamed almost 8 years
    @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
  • Joe Phillips
    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
    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
    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
    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
    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
    John over 7 years
    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 $_}
  • tusharmakkar08
    tusharmakkar08 over 7 years
    @stackoverflow.com/users/100297/martijn-pieters : Why was this answer deleted and downvoted?
  • LOKESH K V
    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..000000000000000000‌​00000000000000000000‌​00 remote: fatal: git cat-file 0000000000000000000000000000000000000000: bad file To [email protected]:root/myproj.git - [deleted] shield_square_removal
  • Guido Bouman
    Guido Bouman over 7 years
    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.
  • yoyo
    yoyo over 7 years
    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)
  • danielricecodes
    danielricecodes about 7 years
    Thanks! I just added an alias to my ~/.profile! Very helpful answer!
  • Knut Holm
    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
    spezifanta almost 7 years
    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"
  • real_ate
    real_ate almost 7 years
    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: i.stack.imgur.com/QAY2H.png
  • danielricecodes
    danielricecodes almost 7 years
    @Akarienta - alias git-branch-clean="git branch --merged | egrep -v \"(^\*|master|dev|staging|production)\" | xargs git branch -d"
  • scones
    scones almost 7 years
    WARNING: This also closes open pull requests.
  • scones
    scones almost 7 years
    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.
  • Diego
    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
    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
    Daniel Alder over 6 years
    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
  • SpoiledTechie.com
    SpoiledTechie.com over 6 years
    Your answer and tool don't work. I spend a couple hours on it. Nothing.
  • tusharmakkar08
    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
    SpoiledTechie.com over 6 years
    I can share a screenshot if you want to take this offline? spoiledtechie at that google mail thing. :)
  • iesen
    iesen over 6 years
    it also tries to delete * master :)
  • voiski
    voiski over 6 years
    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-)
  • lanierhall
    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
    lamplightdev about 6 years
    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
  • alexg
    alexg about 6 years
    git branch -d $(git branch --merged | grep -v master)
  • Stuart Axon
    Stuart Axon about 6 years
    This doesn't work if you have branches named like feature/my-feature as it eats the slash.
  • Robert Pankowecki
    Robert Pankowecki about 6 years
    I had to add the --no-color switch before --merged: git branch --no-color --merged | egrep -v "(^\*|master|dev)" | xargs git branch -d
  • Victor Moraes
    Victor Moraes almost 6 years
    For me, calling git sweep only lists the branches that should be cleaned up, but it does not remove them
  • DanSingerman
    DanSingerman almost 6 years
    I come here about once a week
  • Joe Phillips
    Joe Phillips almost 6 years
    egrep -v works for me. I'm using gitbash from the gitextensions installer though
  • Alex Harvey
    Alex Harvey almost 6 years
    It would be better if the regexp explicitly marked the end of line character, i.e. git branch --merged | egrep -v "(^\*|master)$".
  • carl verbiest
    carl verbiest over 5 years
    The egrep pattern excludes all branches containing master, not just master itself, fix by using egrep -v "^(\* .*| *master| *dev)$"
  • Danilo Souza Morães
    Danilo Souza Morães over 5 years
    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
  • GPHemsley
    GPHemsley over 5 years
    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
  • Bogdan Alexandru Militaru
    Bogdan Alexandru Militaru over 5 years
    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
  • Andriy F.
    Andriy F. about 5 years
    Current command doesn't filter out master and develop branches
  • real_ate
    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.
    Andriy F. about 5 years
    @real_ate Linux OpensSuse git 2.16.4 grep 3.1
  • g9ncom
    g9ncom about 5 years
    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.
  • Rip3rs
    Rip3rs about 5 years
    This is dangerous if you have a flow, imagine you have master <- stage <- dev. Still easiest solution imo
  • Earlee
    Earlee about 5 years
    right now, this project is no longer maintained. See github.com/arc90/git-sweep/pull/43
  • VasiliNovikov
    VasiliNovikov almost 5 years
    Why do you need to create a function? Isn't git config atomic?
  • eddies
    eddies almost 5 years
    To deal with the optional '-f' argument (if I understand your question correctly)
  • VasiliNovikov
    VasiliNovikov almost 5 years
    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 ... ?
  • eddies
    eddies almost 5 years
    You're absolutely right. Edited my answer accordingly. Thanks for the pointer!
  • efx
    efx over 4 years
    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. They are not the same as the format for other git sub commands.
  • Guido Bouman
    Guido Bouman over 4 years
    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.
  • eddies
    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
    0CDc0d3r about 4 years
    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
  • user137369
    user137369 about 4 years
    In the last command, it should be git checkout master &&, not git checkout master |.
  • DarVar
    DarVar almost 4 years
    Is it possible to add a git alias for this?
  • Dr_Zaszuś
    Dr_Zaszuś almost 4 years
    Naturally, this won't work on Windows since it uses egrep...
  • mutoe
    mutoe almost 4 years
    If you using zsh, you can type gbda to apply this command
  • Samantha Adrichem
    Samantha Adrichem almost 4 years
    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;
  • vinnymac
    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
    Michael Freidgeim over 3 years
    @scones, can you clarify your warning about closing open pull requests ?stackoverflow.com/questions/65444886/…
  • scones
    scones about 3 years
    @MichaelFreidgeim sure. if you execute the commands, your pull requests will be closed. not merged tho.
  • M. Reza Nasirloo
    M. Reza Nasirloo about 3 years
    Changing the -n 1 to a higher value deletes more branches at once
  • Trent
    Trent almost 3 years
    This 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
    Elmer almost 3 years
    ye I sometimes do it like that! included it in the answer!
  • David Millar
    David Millar almost 3 years
    Note 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
    Guido Bouman over 2 years
    Uhmm... How would that happen? If master is not updated, the branches are not merged in, and thus do not get removed.
  • cDitch
    cDitch over 2 years
    Thanks for this!
  • Viktor Ivliiev
    Viktor Ivliiev over 2 years
    delete all but the selected ones git branch | grep -E -v "(master|develop|other)" | xargs git branch -D
  • Stefan
    Stefan over 2 years
    Does this delete all branches merged by the current user or by any user?
  • Jacob Eggers
    Jacob Eggers about 2 years
    I 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
    ted about 2 years
    This 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).