2

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?

8
  • Try git remote show, stackoverflow.com/a/15630478/7976758 May be git remote show origin | grep -Fv tracked Found in stackoverflow.com/search?q=%5Bgit%5D+list+remote+branches Commented Nov 27, 2022 at 9:02
  • You may need to define exactly what you mean by "don't have a corresponding local branch". However, note that there's no need to have branch names in Git: it's possible to do work in Git with no branch names at all. Don't create branch names you don't need: there's no point. Do create branch names you want, as many as you want, because there's no disk-space cost to branch names, but don't create ones you don't need, because there's your-brain-space problems with having a ton of branch names. :-) Commented Nov 27, 2022 at 9:08
  • 1
    @phd: Your suggestion seems to return local branches which track remote branches, but I'm looking to show remote branches without a local tracking branch. I've added an example to the question to help clarify. Commented Nov 27, 2022 at 9:46
  • @countermeasure grep -v filters out tracked so the entire command returns both local branches that don't have upstream and remote branches that are not yet fetched. Commented Nov 27, 2022 at 10:11
  • 1
    @GinoMempin A Git command would be ideal, but I also suspect that there may not be one, so I'd be happy with a shell script. Commented Nov 30, 2022 at 9:05

1 Answer 1

2

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:

  • This only compares branches by name, specifically refname's, and assumes that you always track a remote branch with a similarly named local branch, which may not always be the case.
  • The command uses Bash 5.x and it uses process substition (<(...)) 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.
  • The target of 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.

Sign up to request clarification or add additional context in comments.

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.