Reputation: 522
I'd like to list all the remote Git branches which don't have a corresponding local branch.
For example, if the output of git branch --all
is:
remotes/origin/alpha
* beta
main
remotes/origin/beta
remotes/origin/main
What I'd like to end up with is:
remotes/origin/alpha
What's the best way to do that?
Upvotes: 2
Views: 1107
Reputation: 29636
As far as I know and at the time of posting this answer, there is no direct Git command or option for this.
But, inspired by the answers from grep using output from another command, you can use grep
to get a list of local branch refname
's that are missing from the list of remote branch refname
's:
$ grep -v -F -f <(git for-each-ref --format='%(refname:lstrip=2)' refs/heads) <(git for-each-ref --format='%(refname:lstrip=3)' refs/remotes/origin) | grep -vF HEAD
Example:
$ git branch
feature/C
feature/D # local-only branch, not pushed to remote
* master
$ git branch -r
origin/HEAD -> origin/master
origin/develop # no corresponding branch on local
origin/feature/A # no corresponding branch on local
origin/feature/B # no corresponding branch on local
origin/feature/C # is already on local
origin/master # is already on local
$ grep -v -F -f <(git for-each-ref --format='%(refname:lstrip=2)' refs/heads) <(git for-each-ref --format='%(refname:lstrip=3)' refs/remotes/origin) | grep -vF HEAD
develop
feature/A
feature/B
The structure of the command is:
$ grep -v -F -f <(command 2) <(command 1)
command 2
lists all the local branches
$ git for-each-ref --format='%(refname:lstrip=2)' refs/heads
feature/C
feature/D
master
command 1
lists all fetched remote branches
$ git for-each-ref --format='%(refname:lstrip=3)' refs/remotes/origin
HEAD
develop
feature/A
feature/B
feature/C
master
The -f <(command 2)
tells grep
to search for the patterns from the output of command 2
(the local branch patterns) from the output of command 1
(the remote branch patterns). That should have returned remote branches that already have corresponding local branches, then the -v
option inverts the result. The piped git -vF HEAD
is just for excluding HEAD
.
You can also use git branch
but I prefer using git for-each-ref
for scripting and automation. See related post on the difference between Git's "plumbing" vs "porcelain" commands.
This may not always work because:
refname
's, and assumes that you always track a remote branch with a similarly named local branch, which may not always be the case.<(...)
) to allow the command's output to be referred to as a filename to be used with grep
's -f
option. This makes it a bit non-portable and is quite problematic to be put into a git alias.for-each-ref
for remote branches is refs/heads/remotes/origin
, where origin
is the commonly assumed remote name. Change it as necessary if origin
is not your remote name.For convenience, I turned it into a regular shell alias with a git fetch
call:
$ alias git-new-branches="git fetch; grep -v -F -f <(git for-each-ref --format='%(refname:lstrip=2)' refs/heads) <(git for-each-ref --format='%(refname:lstrip=3)' refs/remotes/origin) | grep -vF HEAD"
$ git-new-branches
develop
feature/A
feature/B
You might prefer turning that into a shell script instead, and embed that into a Git alias.
Upvotes: 2