167

I need to do a subtree merge for a specific branch, if it exists on a given remote repository. The problem is that the remote repository is not checked out locally, so I can't use git branch -r. All I have is a remote address, something like this https://github.com/project-name/project-name.git. Is there a way to list remote branches just by a remote address? I couldn't find anything usefull :(

Noufal Ibrahim
  • 71,383
  • 13
  • 135
  • 169
Keen
  • 1,821
  • 2
  • 11
  • 5

18 Answers18

186
$ git ls-remote --heads git@github.com:user/repo.git refs/heads/[branch-name]
# or
$ git ls-remote --heads origin refs/heads/[branch-name]

In case [branch-name] is found you will get the following output:

b523c9000c4df1afbd8371324083fef218669108        refs/heads/branch-name

Otherwise no output will be sent.

So piping it to wc will give you 1 or 0:

$ git ls-remote --heads git@github.com:user/repo.git refs/heads/[branch-name] | wc -l

Alternatively you can set --exit-code flag on git ls-remote which will return exit code 2 in case no matching refs are found. The result can be checked directly in a shell test or by checking the status variable $?.

$ git ls-remote --exit-code --heads git@github.com:user/repo.git refs/heads/[branch-name]

Note that you should prefix the [branch-name] with refs/heads/ otherwise it will do partial matches, e.g. bar will match branches bar and foo/bar.

dimo414
  • 47,227
  • 18
  • 148
  • 244
user487772
  • 8,800
  • 5
  • 47
  • 72
  • 14
    I used `git ls-remote --heads ${REPO} ${BRANCH} | grep ${BRANCH} >/dev/null` followed by `if [ "$?" == "1" ] ; then echo "Branch doesn't exist"; exit; fi` – sibaz Jan 25 '16 at 14:35
  • 1
    I was looking for this neat & precise answer for a few hours, brilliant. – medik Dec 05 '17 at 18:40
  • 3
    You need to specify branch name as `/refs/heads/branch-name`. Otherwise, branch `foo/branch-name` would be returned even when there's no `branch-name`. – FuzzY Mar 13 '19 at 15:27
  • 17
    Note: If you don't want to have to specify the repo URL, you can specify the repo remote name instead, e.g.: `git ls-remote --heads origin branch-name` – daveruinseverything Nov 28 '19 at 01:38
  • 5
    Order matters: `--exit-code` must come before `--heads`. – bishop Dec 02 '21 at 21:39
  • 2
    `/refs/heads/branch-name` appears to not work, but `refs/heads/branch-name` does. – Blaisorblade Jul 12 '22 at 01:18
55
git ls-remote --heads https://github.com/rails/rails.git
5b3f7563ae1b4a7160fda7fe34240d40c5777dcd    refs/heads/1-2-stable
81d828a14c82b882e31612431a56f830bdc1076f    refs/heads/2-0-stable
b5d759fd2848146f7ee7a4c1b1a4be39e2f1a2bc    refs/heads/2-1-stable
c6cb5a5ab00ac9e857e5b2757d2bce6a5ad14b32    refs/heads/2-2-stable
e0774e47302a907319ed974ccf59b8b54d32bbde    refs/heads/2-3-stable
13ad87971cc16ebc5c286b484821e2cb0fc3e3b1    refs/heads/3-0-stable
3df6c73f9edb3a99f0d51d827ef13a439f31743a    refs/heads/3-1-stable
f4db3d72ea564c77d5a689b850751ce510500585    refs/heads/compressor
c5a809e29e9213102351def7e791c3a8a67d7371    refs/heads/deps_refactor
821e15e5f2d9ef2aa43918a16cbd00f40c221e95    refs/heads/encoding
8f57bf207ff4f28fa8da4544ebc573007b65439d    refs/heads/master
c796d695909c8632b4074b7af69a1ef46c68289a    refs/heads/sass-cleanup
afd7140b66e7cb32e1be58d9e44489e6bcbde0dc    refs/heads/serializers
Dogbert
  • 212,659
  • 41
  • 396
  • 397
  • I didn't know about ls-remote also. Thank you! – Keen Nov 22 '11 at 08:42
  • 9
    I needed to do a test in a bash script and so was only really interested in the exit code, so I did the following in a local clone: `git ls-remote --exit-code . origin/branch-name &> /dev/null` then used `$?` as the test operand – Darren Bishop May 30 '12 at 16:33
  • 5
    @Darren, just using the command directly in a conditional, as with `if git ls-remote ...; then ...; fi`, is less error-prone than checking `$?` (which can be changed by logging statements, traps, etc). – Charles Duffy May 08 '14 at 03:46
  • Why the `--heads`? – Steve Mar 18 '16 at 06:05
  • @JohnLinux `--heads` lists branches only. use `--tags` to list tags only. – rymo Mar 20 '16 at 22:58
45

All of the answers here are Linux shell-specific, which doesn't help very much if you're in an environment that doesn't support those sort of operations - for example, Windows' command prompt.

Fortunately git ls-remote accepts an --exit-code argument that returns 0 or 2 depending on whether the branch exists or not, respectively. So:

git ls-remote --exit-code --heads origin <branch-that-exists-in-origin>

will return 0, and

git ls-remote --exit-code --heads origin <branch-that-only-exists-locally>

will return 2.

For PowerShell, you can simply use the built-in truthiness handling semantics:

if (git ls-remote --heads origin <branch-that-exists-in-origin>) { $true } else { $false }

yields $true, while:

if (git ls-remote --heads origin <branch-that-only-exists-locally>) { $true } else { $false }

yields $false.

Ian Kemp
  • 28,293
  • 19
  • 112
  • 138
  • Love the use of exit codes. Thank you for this. Important note: `` would be more accurate description for exit code 2 of `git ls-remote`. As this does not indicate it exists locally. `git branch --list '' | grep --quiet ''` would be a way to utilize exit codes to determine presence of a local branch with a provided name. Here an exit code of `0` indicates the branch exists locally, `1` indicates it does not. EDIT: I see you got to your original answer because you were "on windows". Sorry, as this comment is linux oriented. – Darren Felton Nov 21 '22 at 12:01
36

You can also use this:

git show-branch remotes/origin/<<remote-branch-name>>

returns latest commit and value of $? is 0 otherwise returns "fatal: bad sha1 reference remotes/origin/<>" and value of $? is 128

Ajo Paul
  • 544
  • 4
  • 6
  • 4
    This will not pull branches from remote before checking, so you don't get the latest remote state. – siemanko Aug 09 '19 at 18:26
  • 1
    This is the best one! `git ls-remote --heads origin ` is very slow (it take 3-4 s for me). `git branch -r --list orign/` exists with 0 even if remote branch does not exist. This is fast and exists with 128 if remote branch not exists! – TrueY Feb 08 '23 at 08:49
24

Then no need to manually pass the repository name everytime.

git ls-remote origin <branch>

Instead of

git ls-remote <full repo url> <branch>

Example :

git ls-remote git@bitbucket.org:landmarkgroupme/in-store-application.git  uat_21dec

OR

git ls-remote origin uat_21dec

Both will give same output :

enter image description here

More on Origin : Git has the concept of "remotes", which are simply URLs to other copies of your repository. When you clone another repository, Git automatically creates a remote named "origin" and points to it. You can see more information about the remote by typing git remote show origin .

Amitesh Bharti
  • 14,264
  • 6
  • 62
  • 62
21

Another way you can use in the current folder if it is a git repo to run

git branch -a | egrep 'remotes/origin/${YOUR_BRANCH_NAME}$'
Eduardo Cuomo
  • 17,828
  • 6
  • 117
  • 94
РАВИ
  • 11,467
  • 6
  • 31
  • 40
  • 4
    Use double quotes: `git branch -a | egrep "remotes/origin/${YOUR_BRANCH_NAME}$"` – Ivan Aug 16 '16 at 07:41
  • 4
    This isn't optimal because it will return true even if you only matched part of an existing branch name, but didn't exactly match the target branch. So this can't be safely used in a script to test if the branch exists before checking it out. Thanks for sharing anyway though, as I found it useful. Can be fixed like this: `git branch -a | grep "\b${BRANCH}$"` – EntangledLoops Oct 25 '16 at 22:06
  • 2
    `git fetch` is required if using `git branch -a` so all remotes refs are fetched first. Else use `git ls-remote` as pointed by others. – hIpPy Jun 06 '17 at 23:45
  • `git branch -a --list ''`is also an option. Pipe to grep if you need a return code for your script. – LOAS Aug 03 '17 at 09:31
14

You can do something like this in the Bash terminal. Just replace the echos with the commands you want to execute.

if git ls-remote https://username:password@github.com/project-name/project-name.git | grep -sw "remote_branch_name" 2>&1>/dev/null; then echo "IT EXISTS..START MERGE" ; else echo "NOT FOUND" ; fi

Hope it helps.

sagunms
  • 8,030
  • 5
  • 41
  • 43
10
$ git ls-remote --heads origin <branch> | wc -l

works most of the time.

But will not work if branch matches partially as below,

$ git branch -a
creative/dev
qa/dev

$ git ls-remote --heads origin dev | wc -l
2

Use

git ls-remote --heads origin <branch> | \
    cut -d$'\t' -f2 | \
    sed 's,refs/heads/,,' | \
    grep ^<branch>$ | wc -l

if you want a reliable way.

If you want to use in script and do not want to assume origin as default remote then

git ls-remote --heads $(git remote | head -1) "$branch" | \
    cut -d$'\t' -f2 | \
    sed 's,refs/heads/,,' | \
    grep ^"$branch"$ | wc -l

should work.

Note that git branch -a | grep ... is not reliable as it may be a while since the last fetch was run.

hIpPy
  • 4,649
  • 6
  • 51
  • 65
  • For me, this is the accepted answer, combined with the one from Amitesh (short remote name), combined with the one from James Cache (`grep -x "$branch"` is identical to `grep ^"$branch"$`). Although in scripts I prefer the long-form switches: `--line-regexp`. Also, there is no need to do `wc -l`. Putting empty output in a Bash `if [ -z ] ` effectively evaluates as a true so it means that the branch doesn't exist. That saves you a few milliseconds. – Amedee Van Gasse Jan 11 '19 at 08:57
5

Will return all branches (remote or local) that contain the query in the name.

git branch --all | grep <query>

alexoviedo999
  • 6,761
  • 1
  • 26
  • 17
2

How about just

if [ -e .git/refs/remotes/origin/mybranch ]; then
  echo remote branch still exists - locally at least
else
  echo remote branch is gone
fi

git ls-remote will interact with the remote server, which may or may not be what you want.

Waxrat
  • 510
  • 2
  • 11
1

You can try

git diff --quiet @{u} @{0}

Here @{u} refers to remote/upstream, and @{0} refers to current local HEAD (with newer version of git, @{0} can be shortened as @). If remote does not exist, it errors out.

With git 2.16.2 (I am not sure which version is the first to have this functionality, for example, git 1.7.1 doesn't have it), you can do

git checkout

If a remote branch exists, there will be some output, like

Your branch is up to date with 'origin/master'

Otherwise there is no output.

nos
  • 19,875
  • 27
  • 98
  • 134
1

I'm combining some of the answers above in a script:

BRANCHES=(develop master 7.0 7.0-master)
ORIGIN=bitbucket
REMOTE=github

for BRANCH in "${BRANCHES[@]}"; do
  BRANCH=$(git ls-remote --heads "${ORIGIN}" "${BRANCH}" \
      | cut --delimiter=$'\t' --fields=2 \
      | sed 's,refs/heads/,,' \
      | grep --line-regexp "${BRANCH}")
  if [ -n "${BRANCH}" ]
  then
    git branch --force "${BRANCH}" "${ORIGIN}"/"${BRANCH}"
    git checkout "${BRANCH}"
    git push "${REMOTE}" "${BRANCH}"
  fi
done

git push github --tags

This script will get 4 branches from a remote bitbucket, and push them to a remote github, and will then push all tags to github. I'm using this in a Jenkins job, that's why you don't see any git fetch or git pull, that is already done in the Jenkins job repository config.

I usually prefer long-form options in scripts. I could have combined git branch and git checkout by using git checkout -B.

Amedee Van Gasse
  • 7,280
  • 5
  • 55
  • 101
1

Here is a a simple bash script which does the job

#!/bin/bash

BRANCH="your-branch-name"
# Replace above value with the URL of your git repository
REPO_URL="https://github.com/lsst-dm/qserv-ingest.git"
if git ls-remote --exit-code --heads "$REPO_URL" "$BRANCH"
then
    echo "REMOTE BRANCH EXISTS"
else
    echo "REMOTE BRANCH NOT FOUND"
fi
Fabrice Jammes
  • 2,275
  • 1
  • 26
  • 39
1

You can add the repository you have as a remote using git remote add something https://github.com/project-name/project-name.git and then do a git remote show something to get all information about the remote. This requires a network connection and is useful for human use.

Alternatively, do a git fetch something. This will fetch all branches on the remote called something and keep them in your local repository. You can then merge them into your local branch as you please. I recommend this path since if you finally decide that you have to merge, this is what you need to do.

OT: Your use of "checked out locally" indicates that you're approaching this from a centralised version control system standpoint. That's usually a dead end when you're dealing with git. It uses words like "checkout" etc. differently from how older systems did.

Noufal Ibrahim
  • 71,383
  • 13
  • 135
  • 169
  • Thanks for explanations. I didn't get used to git yet, and it does require different way of thinking. – Keen Nov 22 '11 at 08:48
0

If your branch names are very specific, you might not need to use grep for simple branch name matching:

git ls-remote --heads $(git remote | head -1) "*${BRANCH_NAME}*" | \
    cut -d$'\t' -f2 | \
    sed 's,refs/heads/,,' | \
    wc -l

which works for

BRANCH=master
BRANCH=mas
BRANCH=NonExistingBranch (returns 0)
BRANCH=ISSUE-123

We use unique issue id as branch names and it works fine.

Fabio
  • 491
  • 3
  • 10
0

I just tried this:

git ls-remote --heads 2>/dev/null|awk -F 'refs/heads/' '{print $2}'|grep -x "your-branch"|wc -l

This will return 1 if branch "your-branch" is found and 0 otherwise.

  • Really? `awk` and `grep` and `wc`??? Why not just use awk for all of whis? This can be very slow if a lot of remote branches exist. – TrueY Feb 08 '23 at 08:56
0

This is the simplest way for me. (※ fish shell)

if test (git ls-remote | grep your-branch-name)
  echo exist
else
  echo not_exist
end
kazuwombat
  • 1,515
  • 1
  • 16
  • 19
0

I needed the further requirement to get the name of the remote branch, given input options, e.g. master or main.

~This is someone else's hack but I can't remember where I got it from, sharing here in case it helps another traveler.~ Found it! https://stackoverflow.com/a/68098145, thanks to @Eugene Yarmash

The following will return nothing if neither branch1 or branch2 is extant on the remote and one of the given branch names otherwise.

git branch -l branch1 branch2 | sed 's/^* //'

I use it to set variables for custom git functions, e.g.

branch=$(git branch -l master main | sed 's/^* //')
Jason R Stevens CFA
  • 2,232
  • 1
  • 22
  • 28