==> git branch -a
* master
test
remotes/origin/master
remotes/origin/test
when someone delete the remotes/origin/test
,I still can see it on my computer.
I know I can do this and remove the test
==> git remote prune
==> git branch -d test
==> git branch -a
* master
remotes/origin/master
But if I have more local branch, and they are not on remote, so how can I remove them quickly?
Remove All Local Branches not on Remote First we get all remote branches using the git branch -r command. Next, we get the local branches not on the remote using the egrep -v -f /dev/fd/0 <(git branch -vv | grep origin) command, Finally we delete the branches using the xargs git branch -d command.
This is how I remove local branches that are not longer relevant:
git branch --merged origin/master | xargs git branch -d
You may need to tweak it according to your specific configuration (e.g. see comments below to exclude particular branches), but the first command here before the pipe should give you a list of all your local branches that have been merged into your master branch.
A simple prune will not delete the local branch.
Here is another approach to achieve a real deletion. Be sure to execute "git fetch -p" first to get the latest status of the remote repositories.
git branch -vv | grep ': gone]'| grep -v "\*" | awk '{ print $1; }' | xargs -r git branch -d
This will check all local branches and their origin and will delete all local branches whose origin was deleted.
In detail:
git branch -vv
will list your local branches and show information about the remote branch, saying “gone” if it is not present anymore.
grep ': gone]'
will fetch the branches that match the “ gone]” phrase.
grep -v "\*"
will fetch only lines that do not contain an asterisk. This will ignore the branch you are currently on and also prevent that the “git branch -d” is executed with a “*” at the end which would result in deleting all your local branches
awk '{print $1}'
will fetch the output until the first white space, which will result in the local branch name.
xargs git branch -d
will use the output (branch name) and append it to the “git branch -d” command to finally delete the branch. If you also want to delete branches that are not fully merged, you can use a capital “D” instead of “d” to force delete.
According to the git-fetch
manual page, git fetch -p
will "After fetching, remove any remote-tracking branches which no longer exist on the remote.` If you have local branches tracking those remote branches, you may need to prune those manually.
I wrote a simple shell script called git-dangling-branches
for this purpose. If you specify -D
option, it will delete all local branches which don't have refs/remotes/origin/<branch_name>
. Of course, you should be careful when you do that.
#!/bin/bash -e
if [[ "$1" == '-D' ]]; then
DELETE=1
else
DELETE=0
fi
REMOTE_BRANCHES="`mktemp`"
LOCAL_BRANCHES="`mktemp`"
DANGLING_BRANCHES="`mktemp`"
git for-each-ref --format="%(refname)" refs/remotes/origin/ | \
sed 's#^refs/remotes/origin/##' > "$REMOTE_BRANCHES"
git for-each-ref --format="%(refname)" refs/heads/ | \
sed 's#^refs/heads/##' > "$LOCAL_BRANCHES"
grep -vxF -f "$REMOTE_BRANCHES" "$LOCAL_BRANCHES" | \
sort -V > "$DANGLING_BRANCHES"
rm -f "$REMOTE_BRANCHES" "$LOCAL_BRANCHES"
if [[ $DELETE -ne 0 ]]; then
cat "$DANGLING_BRANCHES" | while read -r B; do
git branch -D "$B"
done
else
cat "$DANGLING_BRANCHES"
fi
rm -f "$DANGLING_BRANCHES"
I ended up with something very similar to kcm's approach. I wanted something that would purge all local branches that were tracking a remote branch, on origin
, where the remote branch has been deleted (gone
). I did not want to delete local branches that were never set up to track a remote branch (i.e.: my local dev branches). Also I wanted a simple one-liner that just uses git
, or other simple CLI tools, rather than writing custom scripts. I ended up using a bit of grep
and awk
to make this simple command then added it as a alias in my ~/.gitconfig
.
[alias]
prune-branches = !git remote prune origin && git branch -vv | grep ': gone]' | awk '{print $1}' | xargs -r git branch -D
Here is a git config --global ...
command for easily adding this as git prune-branches
:
git config --global alias.prune-branches '!git remote prune origin && git branch -vv | grep '"'"': gone]'"'"' | awk '"'"'{print $1}'"'"' | xargs -r git branch -d'
NOTE: As Matteo pointed out in his earlier comment on another answer, use of the -D
flag to git branch
can be very dangerous. So, in the config command I use the -d
option to git branch
rather than -D
; I use -D
in my actual config. I use -D
because I don't want to hear Git complain about unmerged branches, I just want them to go away. You may want this functionality as well. If so, simply use -D
instead of -d
at the end of that config command.
git fetch -p
git branch -v | grep "\[gone\]"
Then manually check and delete branches in the output.
The simplest manual solution based on the answers in this thread as well as here, is to remove all remote-tracking references that no longer exist on the remote with
git fetch -p
then see what has been removed from remote-tracking, but is still in your local working tree with
git branch -v
and manually delete branches that have [gone]
in the output.
To get a concise list run
git branch -v | grep "\[gone\]"
You can do this by iterating over the refs, I used following command to remove all the local branches which dont have remote branches and it worked. Warning: this operation does a force delete non fully merged branches, use with care.
git branch -D `git for-each-ref --format="%(fieldName)" refs/heads/<branch-name-pattern>`
%(fieldName) = refname:short)
refs/heads/
= can be suffixed if you have a common prefix/suffix in branch names
ex: refs/heads/*abc*
Refer this for more information git-for-each-ref(1) Manual Page
First, do:
git fetch && git remote prune origin
And then:
git branch -a | grep -v ${$(git branch -a | grep remotes | cut -d/" -f3-)/#/-e} | xargs git branch -D
git branch -a | grep remotes | cut -d'/' -f3-
git branch -a | grep v ${<all remotes without prefix>/#/-e}
-D
cause not all have to be marked as merged. For example, squash and merge in Github does not mark them as merged.If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With