How to prune local tracking branches that do not exist on remote anymore
If you want to delete all local branches that are already merged into master, you can use the following command:
git branch --merged master | grep -v '^[ *]*master$' | xargs git branch -d
If you are using main
as your master branch, you should modify the command accordingly:
git branch --merged main | grep -v '^[ *]*main$' | xargs git branch -d
More info.
Amidst the information presented by git help fetch
, there is this little item:
-p, --prune
After fetching, remove any remote-tracking branches which no longer exist on the remote.
So, perhaps, git fetch -p
is what you are looking for?
EDIT: Ok, for those still debating this answer 3 years after the fact, here's a little more information on why I presented this answer...
First, the OP says they want to "remove also those local branches that were created from those remote branches [that are not any more on the remote]". This is not unambiguously possible in git
. Here's an example.
Let's say I have a repo on a central server, and it has two branches, called A
and B
. If I clone that repo to my local system, my clone will have local refs (not actual branches yet) called origin/A
and origin/B
. Now let's say I do the following:
git checkout -b A origin/A
git checkout -b Z origin/B
git checkout -b C <some hash>
The pertinent facts here are that I for some reason chose to create a branch on my local repo that has a different name than its origin, and I also have a local branch that does not (yet) exist on the origin repo.
Now let's say I remove both the A
and B
branches on the remote repo and update my local repo (git fetch
of some form), which causes my local refs origin/A
and origin/B
to disappear. Now, my local repo has three branches still, A
, Z
, and C
. None of these have a corresponding branch on the remote repo. Two of them were "created from ... remote branches", but even if I know that there used to be a branch called B
on the origin, I have no way to know that Z
was created from B
, because it was renamed in the process, probably for a good reason. So, really, without some external process recording branch origin metadata, or a human who knows the history, it is impossible to tell which of the three branches, if any, the OP is targeting for removal. Without some external information that git
does not automatically maintain for you, git fetch -p
is about as close as you can get, and any automatic method for literally attempting what the OP asked runs the risk of either deleting too many branches, or missing some that the OP would otherwise want deleted.
There are other scenarios, as well, such as if I create three separate branches off origin/A
to test three different approaches to something, and then origin/A
goes away. Now I have three branches, which obviously can't all match name-wise, but they were created from origin/A
, and so a literal interpretation of the OPs question would require removing all three. However, that may not be desirable, if you could even find a reliable way to match them...
After pruning, you can get the list of remote branches with git branch -r
. The list of branches with their remote tracking branch can be retrieved with git branch -vv
. So using these two lists you can find the remote tracking branches that are not in the list of remotes.
This line should do the trick (requires bash
or zsh
, won't work with standard Bourne shell):
git fetch -p ; git branch -r | awk '{print $1}' | egrep -v -f /dev/fd/0 <(git branch -vv | grep origin) | awk '{print $1}' | xargs git branch -d
This string gets the list of remote branches and passes it into egrep
through the standard input. And filters the branches that have a remote tracking branch (using git branch -vv
and filtering for those that have origin
) then getting the first column of that output which will be the branch name. Finally passing all the branch names into the delete branch command.
Since it is using the -d
option, it will not delete branches that have not been merged into the branch that you are on when you run this command.