96

At one point I thought that git fetch origin --prune deleted local branches that were no longer present on the server. Somehow this is not my experience at the moment.

I ran this command, and the local branch was not deleted. It is not currently checked out. I ran git branch -vv to check this info, and I see

feature/MyGreatFeature           f30efc7 [origin/feature/MyGreatFeature: gone]

So it seems to know that it is gone. Why would it not delete my local branch?

Running git version 2.7.4 (Apple Git-66)

yano
  • 4,095
  • 3
  • 35
  • 68
  • Does this answer your question? [Remove tracking branches no longer on remote](https://stackoverflow.com/questions/7726949/remove-tracking-branches-no-longer-on-remote) – Michael Freidgeim May 10 '20 at 00:47
  • @MichaelFreidgeim yes the script on that answer achieves this, similar to the answer below – yano May 11 '20 at 01:04
  • Sorry for the automatically created unintentional question - the comment should be [“Possible duplicate”](https://meta.stackexchange.com/questions/339563/the-auto-comment-does-this-answer-your-question-generated-when-voting-to-clos) – Michael Freidgeim May 11 '20 at 20:47

7 Answers7

92

The following command chain can be used to delete local branches:

git branch --v | grep "\[gone\]" | awk '{print $1}' | xargs git branch -D
  • git branch --v lists the local branches verbosely
  • grep "\[gone\]" finds all the branches whose remote branch is gone
  • awk '{print $1}' outputs only the name of the matching local branches
  • xargs git branch -D deletes all the matching local branches

This should work on MacOS as well as *nix environments.

Flair
  • 2,609
  • 1
  • 29
  • 41
Brent Worden
  • 10,624
  • 7
  • 52
  • 57
  • 4
    this is a great solution, but now git defaults to using system language and [gone] might be a different string – Agos Apr 30 '20 at 16:44
  • This works perfect in MacOS and *nix. If someone is looking for similar functionality of windows, below commands will be useful: 1) git branch --v | find "[gone]" > tmpBranches.txt 2) for /f "tokens=1" %a in (tmpBranches.txt) do git branch -D %a 3) del tmpBranches.txt – Pankaj Dwivedi Apr 27 '21 at 19:21
  • After trying so many solutions on other threads this is what finally worked for me. Thanks a lot! – Harry Dec 10 '21 at 08:25
  • 1
    Nice. I turned this into a git alias: ```purge = !git branch --v | grep '\\[gone\\]' | awk '{print $1}' | xargs git branch -D``` – sitecorepm Aug 09 '23 at 18:15
79

The various prune options (git remote update --prune, git remote prune, git fetch --prune) only delete remote-tracking branches.1

You'll need to manually delete local branches you no longer want, or change or remove their upstream setting if the remote-tracking branch no longer exists. Note that each local branch can record a remote and/or branch that do not now, or even never did, exist. In this case Git mostly acts as if those local branches have no upstream set, except that since version 1.8.5, several commands report the upstream as "gone" or otherwise invalid, and may suggest using --unset-upstream.


1More precisely, they delete destination refs after doing the refspec mapping from the command line or fetch lines from the configuration. Hence, for fetch mirrors, they can delete local branches. Most clones are not set up as fetch mirrors, though.

There were some recent bug fixes for complex mappings, to make sure that Git did not prune a mapped branch in some cases when it should not. For any normal repository—ordinary clone or pure fetch mirror—these fixes have no effect; they matter only if you have complicated fetch configurations.

torek
  • 448,244
  • 59
  • 642
  • 775
  • if there is a branch listed in the `[]` on `git branch -vv` isn't it a remote-tracking branch in that case? – yano Jun 06 '16 at 18:40
  • 1
    Not necessarily: the thing in `[...]` is simply the upstream. If the upstream is a remote-tracking branch, that's when it's likely to get pruned. In your example, you have `[origin/feature/MyGreatFeature: gone]` which looks like a remote-tracking branch that has already been pruned. Git still has local branch `feature/MyGreatFeature`, and in `.git/config`, that branch still has its remote set to `origin` and its upstream set. You can, e.g., delete the local branch (which deletes its tracking info), or `--unset-upstream` on it if you want to keep the local branch with no upstream set. – torek Jun 06 '16 at 19:09
21

This is how I do it with Powershell.

PS> git branch --v | ? { $_ -match "\[gone\]" } | % { -split $_ | select -First 1 } | % { git branch -D $_ }

You can then create an alias like:

PS> Function func_gitprune { git branch --v | ? { $_ -match "\[gone\]" } | % { -split $_ | select -First 1 } | % { git branch -D $_ } }

PS> Set-Alias -Name gitprune -Value func_gitprune

and execute it every time you need by running

PS> gitprune
Juan M. Elosegui
  • 6,471
  • 5
  • 35
  • 48
  • Would this benefit from running a `git fetch` beforehand so you're in sync? something like `& git fetch --prune; & git branch --v | ? { $_ -match "\[gone\]" } | % { -split $_ | select -First 1 } | % { git branch -D $_ }` – sommmen Sep 15 '21 at 09:25
  • I came up with very similar: `git branch --v | ? {$_.contains('[gone]')} | % {$_.trim().split()[0].trim()} | % {git branch -D $_}` – Shanerk Apr 13 '23 at 14:51
8

The command you want is

$ git remote prune origin

This question is almost word for word what you're looking for.

Community
  • 1
  • 1
Jonathan Holmes
  • 438
  • 2
  • 12
  • For more git branching/merging madness, [check this question out](http://stackoverflow.com/questions/13064613/how-to-prune-local-tracking-branches-that-do-not-exist-on-remote-anymore). – Jonathan Holmes Jun 06 '16 at 18:25
  • When you say "not working", what do you mean? It's failing with an error? Does the command succeed but it's not having the desired effect? – Jonathan Holmes Jun 06 '16 at 18:34
  • 7
    right it "succeeds" (there is no output) and nothing happens, the branches still have the "gone" tag – yano Jun 06 '16 at 18:39
  • 20
    @jonathan: `git remote prune origin` only deletes your remote-tracking branch (e.g. `remotes/origin/mybranch`). It does not delete your local branch (e.g. `mybranch`). You have to delete those separately. – wisbucky Jan 25 '18 at 21:51
4

For me this line works:

git branch -vv | grep "gone" | awk '{print $1}' | xargs git branch -D
Flair
  • 2,609
  • 1
  • 29
  • 41
Eliya
  • 119
  • 8
1

In case you need the Windows Command Line version:

git fetch --all --prune
git branch --all --verbose | for /F "tokens=1" %i in ('findstr /c:"[gone]"') do git branch -D %i
0

In case people need the PowerShell version:

git branch --v | Select-String -Pattern ".*\[gone\].*" | ForEach-Object{($_ -split "\s+")[1]} | ForEach-Object{git branch -D $_}
Flair
  • 2,609
  • 1
  • 29
  • 41