With git remote prune origin
I can remove the local branches that are not on the remote any more.
But I also want to remove local branches that were created from those remote branches (a check if they are unmerged would be nice).
How can I do this?
This question is related to
git
Based on the answers above I'm using this shorter one liner:
git remote prune origin | awk 'BEGIN{FS="origin/"};/pruned/{print $2}' | xargs -r git branch -d
Also, if you already pruned and have local dangling branches, then this will clean them up:
git branch -vv | awk '/^ .*gone/{print $1}' | xargs -r git branch -d
If using Windows and Powershell, you can use the following to delete all local branches that have been merged into the branch currently checked out:
git branch --merged | ? {$_[0] -ne '*'} | % {$_.trim()} | % {git branch -d $_}
Explanation
git
output for each remaining branch nameIt's worth running git branch --merged
by itself first just to make sure it's only going to remove what you expect it to.
(Ported/automated from http://railsware.com/blog/2014/08/11/git-housekeeping-tutorial-clean-up-outdated-branches-in-local-and-remote-repositories/.)
You can use this command:
git branch --merged master | grep -v "\* master" | xargs -n 1 git branch -d
Git Clean: Delete Already-Merged Branches including break down of command
Here is my solution :
git fetch -p
git branch -vv | grep ": gone" | awk '{print $1}' | xargs git branch -d
-p is to remove any remote-tracking references that no longer exist on the remote. So first step will remove references to remote branches.
-vv is for showing sha1 and commit subject line for each head, along with relationship to upstream branch (if any). 2nd step will get all the local branches and grep command will filter out branches that have been deleted.
There doesn't seem to be a safe one-liner, too many edge cases (like a branch having "master" as part of its name, etc). Safest is these steps:
git branch -vv | grep 'gone]' > stale_branches.txt
awk '{print $1}' stale_branches.txt | xargs git branch -d
As @tzacks notes... there is an npm package that is handy for this. Just do:
npx git-removed-branches --prune
(I would have commented but not enough reputation)
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 an 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: Use of the -D
flag to git branch
can be very dangerous. So, in the config command above 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.
The Powershell Version of git branch --merged master | grep -v '^[ *]*master$' | xargs git branch -d
git branch --merged master | %{ if($_ -notmatch '\*.*master'){ git branch -d "$($_.Trim())" }}
This will remove any local branches that have been merged into master, while you are on the master branch.
git checkout master
to switch.
There's a neat NPM package that does it for you (and it should work cross platform).
Install it with: npm install -g git-removed-branches
And then git removed-branches
will show you all the stale local branches, and git removed-branches --prune
to actually delete them.
I'm pretty sure that git remote prune origin
is what you want.
You can run it as git remote prune origin --dry-run
to see what it would do without making any changes.
I reached this page seeking the answer for "how do I delete locally checked out branches that no longer have an upstream branch"
I also did not care whether or not the local branch had been merged in yet, since piping into git branch -d
will simply warn instead of deleting unmerged local branches.
git branch -a | grep origin | tr -s ' ' | cut -d '/' -f3 | egrep -v -f /dev/fd/0 <(git branch -a | grep -v origin) | grep branch_prefix_that_I_care_about | xargs git branch -d
# translation
# git branch -a | grep origin | tr -s ' ' | cut -d '/' -f3
## this finds all remote branch names minus the "remote/origin/" part
#
# <(git branch -a | grep -v origin)
## this finds all local branch names and redirects it into the previous command
#
# egrep -v -f /dev/fd/0 STUFF
## this is doing some weird magic that I'm grokking as "take the set difference from whatever was piped in"
#
#
# overall translation: (STUFF TO CONSIDER) | egrep magic <(STUFF TO REMOVE FROM CONSIDERATION) | do cool things with resulting stuff
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...
One can configure Git to automatically remove references to deleted remote branches when fetching:
git config --global fetch.prune true
When calling git fetch
or git pull
afterwards, references to deleted remote branches get removed automatically.
In Powershell:
git branch -D (git branch --merged |% { $_.trim() } )
This works for me using git 2.21.0 - it deletes local tracking branches which are merged into HEAD
where I have previously --set-upstream
on push (I use push.default=upstream
because it works best with multiple remotes) and that upstream branch has since been deleted by a fetch --prune
(or implicitly if fetch.prune=true
in git config):
git branch -vv --merged | grep ': gone]' | awk '{print $1}' | xargs git branch -d
The use of --merged
and -d
make this a very 'safe' delete. A more aggressive version could drop the --merged
and use -D
I did not find the answers here usefull when the remote itself does not exist anymore. I kept seing branches of remotes that did not exist anymore, but did not find a git command to delete them.
The solution for me was to go to the .git\refs\remotes
directory and directly delete the files that are not relevant any more. The file structure is very easy to understand. It is the same structure as what you see with git branch -r
.
not sure how to do it all at once, but git git branch -d <branchname>
will delete a local branch ONLY if it is completely merged. Note the lowercase d.
git branch -D <branchname>
(note the capital D) will delete a local branch regardless of its merged status.
Try this in git bash, to fetch and prune references to deleted branches, and then prune the local branches that were tracking the removed ones:
git fetch -p && git branch -d `git branch -vv | grep ': gone]' | awk '{print $1}' | xargs`
Remember to checkout first a branch that won't be deleted, so that does not block the deleting of the branch.
Delete any branch that isn't up to date with master
git co master && git branch | sed s/\*/\ / | xargs git branch -d 2> /dev/null
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
Using a variant on @wisbucky's answer, I added the following as an alias to my ~/.gitconfig
file:
pruneitgood = "!f() { \
git remote prune origin; \
git branch -vv | perl -nae 'system(qw(git branch -d), $F[0]) if $F[3] eq q{gone]}'; \
}; f"
With this, a simple git pruneitgood
will clean up both local & remote branches that are no longer needed after merges.
Even shorter and safer one-liner:
git branch -d $(git branch --merged | cut -c 3- | grep -v master)
Be sure to checkout to branch that is not merged yet, before run it. Because you can not delete branch that you are currently checked in.
Following is an adaptation of @wisbucky's answer for Windows users:
for /f "tokens=1" %i in ('git branch -vv ^| findstr ": gone]"') DO git branch %i -d
I use posh-git and unfortunately PS doesn't like the naked for
, so I created a plain 'ol command script named PruneOrphanBranches.cmd:
@ECHO OFF
for /f "tokens=1" %%i in ('git branch -vv ^| findstr ": gone]"') DO CALL :ProcessBranch %%i %1
GOTO :EOF
:ProcessBranch
IF /I "%2%"=="-d" (
git branch %1 %2
) ELSE (
CALL :OutputMessage %1
)
GOTO :EOF
:OutputMessage
ECHO Will delete branch [%1]
GOTO :EOF
:EOF
Call it with no parameters to see a list, and then call it with "-d" to perform the actual deletion or "-D" for any branches that are not fully merged but which you want to delete anyway.
To remove remote branches:
$git remote prune origin
To remove local branches that are already merged:
$git branch -D $(git branch --merged)
Schleis' variant does not work for me (Ubuntu 12.04), so let me propose my (clear and shiny :) variants:
Variant 1 (I would prefer this option):
git for-each-ref --format='%(refname:short) %(upstream)' refs/heads/ | awk '$2 !~/^refs\/remotes/' | xargs git branch -D
Variant 2:
a. Dry-run:
comm -23 <( git branch | grep -v "/" | grep -v "*" | sort ) <( git br -r | awk -F '/' '{print $2}' | sort ) | awk '{print "git branch -D " $1}'
b. Remove branches:
comm -23 <( git branch | grep -v "/" | grep -v "*" | sort ) <( git br -r | awk -F '/' '{print $2}' | sort ) | xargs git branch -D
This will delete the local branches for which the remote tracking branches have been pruned. (Make sure you are on master
branch!)
git checkout master
git branch -vv | grep ': gone]' | awk '{print $1}' | xargs git branch -d
Details:
git branch -vv
displays "gone" for local branches that the remote has been pruned.
mybranch abc1234 [origin/mybranch: gone] commit comments
-d
will check if it has been merged (-D
will delete it regardless)
error: The branch 'mybranch' is not fully merged.
check for targets
for target in $(git branch | grep -Eiv "master|develop|branchYouWantToLive"); do echo $target; done
run with for & subcommands
for target in $(git branch | grep -Eiv "master|develop|branchYouWantToLive"); do git branch -D $target; done
you can extend other something works about branches.
It will list the local branches whose remote tracking branch is deleted from remote
$ git remote prune origin --dry-run
If you want to de-reference these local branches from local which are un tracked
$ git remote prune origin
I have turned the accepted answer into a robust script. You'll find it in my git-extensions repository.
$ git-prune --help
Remove old local branches that do not exist in <remote> any more.
With --test, only print which local branches would be deleted.
Usage: git-prune [-t|--test|-f|--force] <remote>
Based on the answers above I came with this one line solution:
git remote prune origin; git branch -r | awk '{print $1}' | egrep -v -f /dev/fd/0 <(git branch -vv | grep origin) | awk '{print $1}' | xargs git branch -d
For Microsoft Windows Powershell:
git checkout master; git remote update origin --prune; git branch -vv | Select-String -Pattern ": gone]" | % { $_.toString().Trim().Split(" ")[0]} | % {git branch -d $_}
git checkout master
switches to the master branch
git remote update origin --prune
prunes remote branches
git branch -vv
gets a verbose output of all branches (git reference)
Select-String -Pattern ": gone]"
gets only the records where they have been removed from remote.
% { $_.toString().Split(" ")[0]}
get the branch name
% {git branch -d $_}
deletes the branch
Using the GUI? Manual procedure, but quick and easy.
$ git gui
Select "Branch -> Delete". You can select multiple branches with ctrl-click (windows) and remove all of them.
Source: Stackoverflow.com