GitGit

error: src refspec main does not match any

Git cannot find the branch you asked it to push. Usually no commits yet, or a branch actually named master. How to check before guessing.

easy fix5 min read3 causes

the git error
error: src refspec main does not match any
error: failed to push some refs to 'github.com:acme/myapp.git'

error: src refspec refs/heads/main does not match any

Do this first3 steps

Run these in order. Each one tells you what its output means before you change anything.

  1. 1

    Check whether the branch exists and has a commit

    git branch -a && git log --oneline -1 2>&1

    Empty output from git branch means no branch exists yet, because a branch is a pointer to a commit and there are no commits. A "does not have any commits yet" message from git log confirms it.

  2. 2

    If nothing is committed, commit first

    git status --short && git add -A && git commit -m "Initial commit"

    Staging alone is not enough. A branch comes into existence with its first commit, which is why git push fails on a repository where files have only been added.

  3. 3

    If the branch exists under a different name, rename it

    git branch -M main && git push -u origin main

    -M renames the current branch and overwrites an existing name if needed. This is the fix when git init created master and you are pushing main.

All 8 sections

src refspec X does not match any means Git looked for a local ref called X to push and found nothing. The remote is irrelevant here; the problem is local.

git branch -a
git log --oneline -1

Cause 1: No commits yet

git branch
# (no output)

git log --oneline -1
# fatal: your current branch 'main' does not have any commits yet

A branch is a pointer to a commit. With no commits there is no branch, only a HEAD that names one which does not exist yet.

git add is not enough. Staging does not create a commit:

git status --short
# A  README.md        <- staged, still no commit

git commit -m "Initial commit"
git push -u origin main

This is by far the most common cause, and it usually happens when following setup instructions and skipping the commit step.

Cause 2: The branch is called master

git init created master on older Git, and you are pushing main.

git branch
# * master
git branch -M main
git push -u origin main

-M is --move --force, which renames the current branch and overwrites the target name if it exists.

Set the default for new repositories so it stops recurring:

git config --global init.defaultBranch main

Git 2.28 added that setting, and prints a hint about it on git init.

Cause 3: A typo, or a detached HEAD

git branch --show-current

Empty output means detached HEAD: you are on a commit, not a branch, usually after git checkout <sha> or during a rebase.

git switch -c main
git push -u origin main

Pushing something other than a branch

The refspec is <source>:<destination>, and the source has to exist locally:

git push origin main                  # branch
git push origin v1.4.2                # tag
git push origin HEAD:main             # current commit to remote main
git push origin a1b2c3d:main          # a specific commit

HEAD:main is useful in CI, where the checkout is often detached and there is no local branch to name:

script:
  - git push origin HEAD:main

A misspelled tag gives exactly the same error, so check with git tag -l.

Deleting a remote branch

The old syntax looks like this error waiting to happen:

git push origin :feature/old        # empty source means delete
git push origin --delete feature/old

The second is clearer and does not risk a typo becoming a push.

In CI

Most CI systems check out a detached HEAD at a specific commit, so there is no local branch:

git branch --show-current
# (empty)
# GitLab CI
script:
  - git push origin HEAD:$CI_COMMIT_BRANCH
# GitHub Actions: ask for a branch checkout
- uses: actions/checkout@v4
  with:
    ref: ${{ github.head_ref || github.ref_name }}

Also note that actions/checkout defaults to fetch-depth: 1, a shallow clone, which is fine for pushing a new commit and not for anything needing history.

A checklist

  1. git branch -a. Nothing listed → no commits exist.
  2. git log --oneline -1. "does not have any commits yet" confirms it.
  3. git add alone is not enough. Commit.
  4. Branch is mastergit branch -M main.
  5. git config --global init.defaultBranch main to stop it recurring.
  6. git branch --show-current empty → detached HEAD. git switch -c main.
  7. Pushing a tag → confirm it exists with git tag -l.
  8. In CI → git push origin HEAD:<branch>, since the checkout is detached.

Frequently Asked Questions

Why does git push fail on a brand new repository?

Because there are no commits, and therefore no branch to push. A branch in Git is nothing more than a pointer to a commit, so until you make one, main does not exist even though git status shows you on it. Staging files with git add does not create a commit. Run git commit -m "Initial commit" first, then git push -u origin main. This is the single most common cause of this error.

What does the -M flag do in git branch -M main?

It is shorthand for --move --force: rename the current branch to main, overwriting an existing branch of that name if there is one. It is the standard fix when git init created master and your remote expects main. Because it forces, it will overwrite a local main that already exists, so on a repository with several branches check git branch first. Setting git config --global init.defaultBranch main avoids needing it on new repositories.

Why does this happen in CI when it works locally?

Most CI systems check out a detached HEAD at a specific commit rather than a branch, so git branch --show-current returns nothing and there is no local main to push. Use git push origin HEAD:main, which pushes the current commit to the named remote branch without requiring a local branch. In GitHub Actions you can alternatively ask actions/checkout for a branch by passing ref.

What is a refspec?

The <source>:<destination> pair that tells Git what to push where. git push origin main is shorthand for main:main. The source is resolved locally, which is why this error is always about your own repository rather than the remote. Writing the source and destination separately is useful when they differ, as in git push origin HEAD:main, and an empty source as in git push origin :feature/old means delete the remote branch, which is why a typo in that form can be surprising.

How do I delete a remote branch?

git push origin --delete feature/old. The older equivalent, git push origin :feature/old, uses an empty refspec source to mean deletion and still works, but it is easy to mistype into something that pushes instead. The explicit --delete form says what it does. Deleting the remote branch does not remove your local copy, which you delete separately with git branch -d feature/old.

Reference and practice

Learn the underlying concept

Other Git errors