List all local branches without a remote
Solution 1:
I recommend using git branch --format
to specify the exact output you want from the git branch
command. By doing that, you can pull out just the refname and the upstream, like this:
git branch --format "%(refname:short) %(upstream)"
It outputs the branches along with the remote branches if they exist, in the following format:
25-timeout-error-with-many-targets
31-target-suggestions refs/remotes/origin/31-target-suggestions
54-feedback-link refs/remotes/origin/54-feedback-link
65-digest-double-publish
Once you have this nicely formatted output, it's as easy as piping it through awk
to get your list:
git branch --format "%(refname:short) %(upstream)" | awk '{if (!$2) print $1;}'
Results in the following output:
25-timeout-error-with-many-targets
65-digest-double-publish
The awk
portion prints the first column if there is no second column.
Bonus: Create an alias
Make it easy to run by creating an alias in your global .gitconfig
file (or wherever):
[alias]
local-branches = "!git branch --format '%(refname:short) %(upstream:short)' | awk '{if (!$2) print $1;}'"
Bonus: Remote Filtering
If for some reason you have multiple tracking remotes for different branches, it's easy enough to specify which remote you want to check against. Just add the remote name to the awk pattern. In my case, it's origin
so I can do this:
git branch --format "%(refname:short) %(upstream)" | awk '$2 !~/\/origin\// { print $1 }'
Important: The backslash needs to be escaped in the alias or else you will have an invalid gitconfig file.
Previous Answer
The previous answer was functionally similar, but used the following as it's starting point. Over time, commenters have pointed out that a regex is unreliable due to the variance possible in a commit message, so I no longer recommend this method. But, here it is for reference:
I recently discovered git branch -vv
which is the "very verbose" version of the git branch
command.
It outputs the branches along with the remote branches if they exist, in the following format:
25-timeout-error-with-many-targets 206a5fa WIP: batch insert
31-target-suggestions f5bdce6 [origin/31-target-suggestions] Create target suggestion for team and list on save
* 54-feedback-link b98e97c [origin/54-feedback-link] WIP: Feedback link in mail
65-digest-double-publish 2de4150 WIP: publishing-state
Once you have this nicely formatted output, it's as easy as piping it through cut
and awk
to get your list:
git branch -vv | cut -c 3- | awk '$3 !~/\[/ { print $1 }'
Solution 2:
git branch
(without any options) lists only local branches, but you don't know if they are tracking a remote branch or not.
Usually those local branches should be deleted once merged into master
(as seen in this issue of git-sweep):
git branch --no-contains master --merged master | xargs git branch -d
This isn't as complete as you want, but it is a start.
With
--merged
, only branches merged into the named commit (i.e. the branches whose tip commits are reachable from the named commit) will be listed.
Solution 3:
I have a similar issue. I want to remove all local branches that were tracking remote branches that are now deleted. I am finding that git remote prune origin
was insufficient to remove the branches that I want gone. Once the remote is deleted, I want the local to go away too. Here is what worked for me:
From 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: I changed the -d
to -D
in my actual configuration, because I don't want to hear Git complain about unmerged branches. You may want this functionality as well. If so, simply use -D
instead of -d
at the end of that command.
Also, FWIW, your global configuration file would almost always be ~/.gitconfig
.
(OS X Fix)
As written, this does not work on OS X because of the use of xargs -r
(thanks, Korny).
The -r
is to prevent xargs
from running git branch -d
without a branch name, which will result in an error message "fatal: branch name required
". If you don't mind the error message, you can simply remove the -r
argument to xargs
and you're all set.
However, if you don't want to see an error message (and really, who could blame you) then you'll need something else that checks for an empty pipe. If you might be able to use ifne from moreutils. You would insert ifne
before xargs
, which will stop xargs
from running with empty data. NOTE: ifne
considers anything to be not empty, this includes blank lines, so you may still see that error message. I've not tested this on OS X.
Here is that git config
line with ifne
:
git config --global alias.prune-branches '!git remote prune origin && git branch -vv | grep '"'"': gone]'"'"' | awk '"'"'{print $1}'"'"' | ifne xargs git branch -d'