git ls-remote --heads/--tags: Query a Remote in CI
git ls-remote --heads origin <name> lists matching branch refs on the remote without cloning, the cheap way for CI to test whether a branch or tag exists upstream.
Before a job clones or pushes, it often needs to know what refs the remote actually has. ls-remote answers that over the network without a working tree, and --symref reveals the remote default branch.
What it does
git ls-remote contacts a remote and prints its advertised refs and SHAs. --heads and --tags filter to branches or tags. A trailing pattern narrows further. --symref additionally shows what symbolic refs like HEAD point to, which tells you the default branch without cloning.
Common usage
git ls-remote --heads origin
# does a branch exist upstream? (empty output = no)
git ls-remote --heads origin release-1.0
# the remote default branch
git ls-remote --symref origin HEAD
# the SHA of a tag on the remote
git ls-remote --tags origin v1.4.0Options
| Flag | What it does |
|---|---|
| --heads | List only branch refs |
| --tags | List only tag refs |
| --symref | Also show symbolic refs (e.g. HEAD -> main) |
| --refs | Filter out peeled tag (^{}) entries |
| --exit-code | Exit 2 if no matching refs are found |
| <remote> <pattern> | Limit to refs matching the pattern |
In CI
ls-remote needs credentials for private repos just like clone; failures here are usually auth, not missing refs. Use --exit-code so a script can branch on "ref absent" cleanly instead of parsing empty output. --symref origin HEAD is the portable way to discover main vs master before checkout.
Common errors in CI
"fatal: Could not read from remote repository." with "Permission denied (publickey)" or HTTPS auth prompts means credentials are missing/wrong, not that the ref is absent. "remote: Repository not found" on a private repo is usually an auth problem masquerading as 404. Empty output is the normal "no such ref" result.