Delete local Git branches after deleting them on the remote repo

69,108

Solution 1

The quick way

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

NB: if you're not on master, this has the potential to delete the branch. Keep reading for the "better way".

Make sure we keep master

You can ensure that master, or any other branch for that matter, doesn't get removed by greping for more. In that case you would go:

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

So if we wanted to keep master, develop and staging for instance, we would go:

git branch --merged | grep -v "\*" | grep -Ev "(\*|master|develop|staging)" | xargs -n 1 git branch -d

Make this an alias

Since it's a bit long, you might want to add an alias to your .zshrc or .bashrc. Mine is called gbpurge (for git branches purge):

alias gbpurge='git branch --merged | grep -Ev "(\*|master|develop|staging)" | xargs -n 1 git branch -d'

Then reload your .bashrc or .zshrc:

. ~/.bashrc

or

. ~/.zshrc

Solution 2

I use the same flow with GitHub, and didn't find the previous answers satisfying me, as git branch --merged lists branches which were merged, but not every of them was removed remotely in my case. So, this worked for me:

git fetch --all -p; git branch -vv | grep ": gone]" | awk '{ print $1 }' | xargs -n 1 git branch -d

where:

  • git fetch --all -p: update local branches status
  • git branch -vv: list local branches status
  • grep ": gone]": filter deleted ones
  • awk '{ print $1 }': extract their names
  • xargs -n 1 git branch -d: pass the name to the delete command

Note: if you prefer, you could use -D instead of -d, which enforces the delete.

For example:

someUsr@someHost:~/repo$ git branch -a
basic-testing
integration-for-tests
* master
origin
playground-for-tests
test-services
remotes/origin/HEAD -> origin/master
remotes/origin/basic-testing
remotes/origin/master
remotes/origin/test-services

someUsr@someHost:~/repo$ git fetch --all -p; git branch -vv | grep ": gone]" | awk '{ print $1 }' | xargs -n 1 git branch -d
Fetching origin
Deleted branch integration-for-tests (was fbc609a).
Deleted branch playground-for-tests (was 584b900).

someUsr@someHost:~/repo$ git branch -a
basic-testing
* master
origin
test-services
remotes/origin/HEAD -> origin/master
remotes/origin/basic-testing
remotes/origin/master
remotes/origin/test-services

Reference:

http://git-scm.com/book/en/v2/Git-Branching-Remote-Branches

Solution 3

try:

git pull --prune

which deletes your local branch, if its corresponding remote branch is deleted.

Updated:

The statement above is not that correct.

In fact, running git pull --prune will only REMOVE the remote-tracking branches such like

remotes/origin/fff
remotes/origin/dev
remotes/origin/master

Then, you can run git branch -r to check the remote-tracking branches left on your machine. Suppose the left branches are:

origin/dev
origin/master

which means the branch origin/fff is deleted.

So, after running git pull --prune, just run:

git branch --merged | grep -vFf <(git branch -r | cut -d'/' -f2-)

you can find out all the local branches which:

  1. have no correspoding remote branches any more;
  2. can be removed safely.

then, <the command above> | xargs git branch -d can delete all of them.

Solution 4

This should work to avoid deleting the master and development branches with the accepted solution:

git branch --merged | egrep -v "^\*|master|development" | xargs -n 1 git branch -d

Solution 5

For people using powershell, this is the equivalent to the answer above:

git branch -vv | Select-String -Pattern ': gone]' | ForEach-Object{($_ -split "\s+")[1]} | %{ git branch -D $_ }
  1. Filter all the branches that are marked as gone
  2. Call git branch -D on each of the found branches (using -D to delete a branch irrespective of its merged status).
Share:
69,108

Related videos on Youtube

sf89
Author by

sf89

Updated on October 05, 2020

Comments

  • sf89
    sf89 over 3 years

    I want to have my local and remote repositories always in sync in terms of branches.

    After a Pull Request review on GitHub, I merge and remove my branch there (remote). How could I fetch this information in my local repository and get Git to remove my local version of the branch as well?

  • Admin
    Admin almost 11 years
    This answer is not quite correct. The --prune flag will only delete remote-tracking branches, not local branches.
  • sf89
    sf89 almost 11 years
    Agreed with @Cupcake here, this doesn't achieve what I'm looking for here.
  • Admin
    Admin almost 11 years
    You can put the commands in an alias and make it a single command. However, since branch is a porcelain and not a plumbing command, watch out for any UI changes in future versions of Git that may break it.
  • Spechal
    Spechal over 10 years
    Not going to upvote, but this is what I needed after having deleted local branches and then deleting from GitHub but them still existing as remotes in my git remote -v command.
  • Rubens Mariuzzo
    Rubens Mariuzzo about 10 years
    Perfect! Note that following the Github Workflow the local branch master will be deleted.
  • sf89
    sf89 about 10 years
    Nope pretty sure it stays there (I'm using it everyday and it doesn't seem to do that).
  • Chad
    Chad almost 10 years
    I copy-pasted the command into my console and it deleted my local master branch
  • sf89
    sf89 almost 10 years
    Yup if your master is not pushed to your remote then it gets deleted like any other branch. Make sure you read carefully the question before you copy and paste anything: as I said, I needed a way to get rid of deleted branches on the remote (branches that no longer existed). That's why your master got blown up buddy.
  • sf89
    sf89 almost 10 years
    Of course it has the potential of deleting master. Please read the question carefully. As I said there, I needed a way to clean things up on my local. That means deleting all the branches that no longer exist on remote. If master is no longer there, then it will disappear on your local machine as well.
  • shashwat
    shashwat over 9 years
    is there really a way to delete local branch for which remote tracking branch is deleted ?
  • Miguelgraz
    Miguelgraz about 9 years
    I took the liberty to ensure that I'll always do that against master, therefore: git checkout master; git pull origin master; git fetch --all -p; git branch -vv | grep gone | awk '{ print $1 }' | xargs -n 1 git branch -d Great script and explanation, thank you for that :)
  • chawkinsuf
    chawkinsuf about 9 years
    Note that branch -vv shows the last commit message from the branch. If you happened to have "gone" in that message the grep gone would hit that branch too. So, grep ": gone]" is probably a little safer to use.
  • Matt Montag
    Matt Montag almost 9 years
    This is exactly the answer I was looking for. The one-liner piped commands that delete branches scare me a bit. This is a nice safe option for routine cleanup.
  • catalyst294
    catalyst294 almost 9 years
    If you want to keep your master you and just add an additional grep of grep -v "master" after the first one. You can follow that pattern with any other branch you might want to keep.
  • e_m0ney
    e_m0ney almost 9 years
    You can also do git fetch --prune, that's my way of choice
  • Andrii Gladkyi
    Andrii Gladkyi over 8 years
    This is the actual answer to the question. Thank you.
  • Andrew Burns
    Andrew Burns over 8 years
    FYI if you want to keep multiple branches you can use a single grep, like so: grep -Ev '(\*|master|important-branch)'
  • profuel
    profuel over 8 years
    I'd add one more thing - make to switch to most relevant branch you have. Otherwise, you will get notices: error: The branch 'feature/SHOP-498' is not fully merged. If you are sure you want to delete it, run 'git branch -D feature/SHOP-498'.
  • Alessio
    Alessio over 8 years
    @profuel I'm not so sure if I get your comment right, whereas you say "most relevant branch". That type of output is exactly the warning I want to see, as it happens for local branches which I didn't push fully - so for me for example they contain some work in progress which is so experimental that is not even worth to be pushed. So either you push it, then it will get deleted, or you delete it manually, but the warning is needed as you've some unpushed commits into it.
  • 3ocene
    3ocene over 8 years
    Why so many downvotes? I mean obviously not efficient, especially with larger repos, but it does what OP asked. Is there some other reason not to do this?
  • dskrvk
    dskrvk about 8 years
    If you want to put this in your ~/.gitconfig instead, add the following to the [alias] section: gbpurge = !"git branch --merged | grep -Ev '\\*|master|develop|staging' | xargs -n 1 git branch -d" (no need to use () in the grep expression).
  • Attila Szeremi
    Attila Szeremi about 8 years
    it would be nice if you could automatically make it so you'd keep any branches whose remote equivalent haven't been deleted; that way you don't have to keep track of master|develop|staging|etc
  • jww
    jww almost 8 years
    Yet another Git error from advice found on Stack overflow... git pull --prune resulted in "You asked to pull from the remote '--prune', but did not specify a branch. Because this is not the default configured remote for your current branch, you must specify a branch on the command line."
  • jww
    jww almost 8 years
    More bad advice on Stack Overflow... You just whacked Master with The quick way. Perhaps you should have stated that the The quick way deletes master even if its not deleted on remote...
  • PapaKai
    PapaKai almost 8 years
    git fetch origin --prune may help in prev. comments case
  • Jakub Bochenski
    Jakub Bochenski over 7 years
    How about getting rid of grep completely in favor of git branch -vv | awk '{ if ($4 == "gone]") print $1 }' -- one less pipe and it's slightly more exact as it only checks for gone] in specific column
  • Jakub Bochenski
    Jakub Bochenski over 7 years
    Even better: awk '$3 $4 ~ /:gone]$/ { print $1 }'
  • sevenseacat
    sevenseacat over 7 years
    Because you'll lose all your local branches, stashes, unpushed commits... it's like fishing with dynamite.
  • Admin
    Admin about 7 years
    The same happens when the laptop you are working on somehow gets corrupted, lost, or stolen, so I tend not to keep nothing crucial locally. It seems better to me to just create a branch and push it, even for small features, and delete it after it is not useful anymore.
  • Alexar
    Alexar almost 7 years
    BE CAREFUL if you're a newbie. Adding a git alias and using it in other repositories requires extra care. Not every git repository would have "master|develop|staging" as main branches. I personally don't recommend this method.
  • Enrico
    Enrico almost 7 years
    this is listing me master too, it doesn't work as expected; be careful
  • Cas
    Cas over 6 years
    Apart from needing -D instead of -d this is the perfect answer!
  • Alessio
    Alessio over 6 years
    @Cas thanks to point that out! I will add a note about it, but given the --force option of -D, I would let the others to choose what's best for them :)
  • A.Wan
    A.Wan over 3 years
    thank you, this worked for me where the other commands using --merged didn't!
  • Alessio
    Alessio over 3 years
    @A.Wan you're welcome, I still use this very same nowadays :)
  • murchu27
    murchu27 about 3 years
    This worked perfectly, except for on a particular shell where my user is not given access to xargs. For anyone else in that situation, you can pipe to a while loop instead of xargs, like so: ...awk '{ print $1 }' | while read -r line; do git branch -D $line; done
  • SomeoneElse
    SomeoneElse over 2 years
    This does have the advantage over the other answers here of "actually answering the question as asked - in the singular: "get Git to remove my local version of the branch as well?".