Fix: git error: src refspec 'main' does not match any
Part of: Docker, DevOps & Infrastructure
Quick Answer
How to fix git error src refspec main does not match any caused by empty repos, wrong branch name, no commits, typos, and default branch mismatch.
The Error
You run git push and get:
error: src refspec 'main' does not match any
error: failed to push some refs to 'https://github.com/user/repo.git'Or variations:
error: src refspec 'master' does not match anyerror: src refspec 'my-feature' does not match anyGit cannot find the branch you are trying to push. The branch name does not exist locally, or there are no commits on it.
Why This Happens
When you run git push origin main, Git resolves main against your local refs. It looks for a branch named exactly main under refs/heads/. If no such ref exists, Git reports “src refspec does not match any” and aborts before contacting the remote. The remote never sees the request.
The confusing part is that this error never tells you what it could not match. It only tells you the name you typed is not a valid local ref. That covers four very different situations: the branch was never created (no commits), it exists under a different name (master vs main), it has a typo, or you are in a detached HEAD state where no branch is current.
Common causes:
- No commits yet. You initialized a repo but never made a first commit. A branch does not exist until it has at least one commit.
git initwritesHEADpointing atrefs/heads/main, butrefs/heads/mainitself does not exist until the first commit. - Wrong branch name. Your local branch is
masterbut you are pushingmain, or vice versa. This is extremely common on older machines wheregit initstill defaults tomaster. - Typo in branch name.
git push origin mianinstead ofmain. Branch names are case-sensitive on most file systems, soMainandmainare different refs. - Detached HEAD. You checked out a tag or a commit SHA directly.
HEADpoints at a commit, not at a branch name, so there is nothing to push. - Empty repository. The repo was just created with
git initand has no history. The branch shown ingit statusis symbolic only. - Branch was deleted. The local branch was deleted before pushing, or you ran
git checkoutinto a different branch and forgot.
Platform and Environment Differences
The “default branch” you end up on depends entirely on which Git binary and which version initialized the repo. This causes most cross-machine confusion.
Git 2.28 and later (July 2020). Git introduced the init.defaultBranch config. When you run git init, Git uses whatever this setting holds. With no setting, Git still uses master and prints a hint suggesting you set the config. Most distros ship a recent enough Git, but a colleague on a stale Ubuntu LTS image can still produce master repos by default.
Git before 2.28. No config, no hint. Every git init produces master. If your CI image is old (Debian Stretch, CentOS 7) you will get master even if your laptop produces main.
GitHub (October 2020). GitHub switched the default branch for new repos from master to main. Older repos kept master unless renamed. So a fresh GitHub repo expects main, but you may have a local repo on master, which is the most common form of this error.
GitLab. Default became main for new projects in GitLab 14.0 (May 2021). Self-hosted instances on older versions still default to master.
Bitbucket Cloud. Switched default to main in 2021. Self-hosted Bitbucket Server / Data Center still produces master unless the admin changed default.branch in the global config.
Gitea / Forgejo. Configurable per instance via [repository] DEFAULT_BRANCH. Many self-hosted instances still ship main as the default.
Fresh git init vs cloned repo. A clone always tracks whatever the remote’s HEAD symref points to (master, main, develop, anything). A fresh git init uses your local init.defaultBranch. Pushing a freshly-initialized local repo to a freshly-created remote is where mismatches surface.
CI checkout actions. actions/checkout@v4 on GitHub Actions clones using the default ref of the triggering event, which is the repo’s default branch. If you create the repo on the command line with git init (producing master) and then push to a GitHub repo whose default is main, your first push fails until you align the names.
WSL2 vs Windows native. Git for Windows and Git inside WSL2 are independent installations with independent configs. Setting init.defaultBranch in one does not propagate to the other. People hit this when they git init in PowerShell but commit from a WSL2 shell or vice versa.
Fix 1: Make an Initial Commit
The most common cause. A new repo has no commits, so no branch exists yet:
git init
git add .
git commit -m "Initial commit"
git push -u origin mainWithout at least one commit, Git has no branch to push. The git init command does not create a main branch — it only sets up the .git directory. The branch is created when you make the first commit.
If you already added files but forgot to commit:
git status
# Shows staged or unstaged files
git add .
git commit -m "Initial commit"
git push -u origin mainPro Tip: After
git init, always make an initial commit immediately, even if it is just a README or.gitignore. This creates the branch and avoids the “src refspec” error entirely.
Fix 2: Check Your Branch Name
Your local branch might have a different name than what you are pushing:
git branch
# Shows all local branches with * next to the current oneIf your branch is master but you are pushing main:
# Option 1: Push the correct branch name
git push -u origin master
# Option 2: Rename your branch to main
git branch -m master main
git push -u origin mainIf your branch is main but the remote expects master:
git push -u origin main:master
# Pushes local "main" to remote "master"Check what the remote expects:
git remote show origin
# Shows the remote's default branch (HEAD branch)Common Mistake: GitHub changed its default branch name from
mastertomainin October 2020. Old tutorials usemaster, new repos usemain. Always check which branch name your remote repository uses.
Fix 3: Fix Detached HEAD State
If you are in detached HEAD state, you are not on any branch:
git status
# HEAD detached at abc1234Create a branch from the current state:
git checkout -b main
git push -u origin mainOr switch back to an existing branch:
git checkout main
# or
git switch mainFor more on detached HEAD, see Fix: Git detached HEAD state.
Fix 4: Fix After git clone of an Empty Repo
When you clone an empty repository:
git clone https://github.com/user/new-repo.git
cd new-repo
# warning: You appear to have cloned an empty repository.There is no branch yet. Create one:
echo "# My Project" > README.md
git add README.md
git commit -m "Initial commit"
git branch -M main
git push -u origin mainThe -M flag forces the branch rename even if the target name already exists.
Fix 5: Fix Branch Name Typos
Check for typos in your push command:
# Wrong
git push origin mian # typo: "mian"
git push origin mainn # typo: extra "n"
git push origin Main # case-sensitive: "Main" ≠ "main"
# Correct
git push origin mainList all local branches to find the right name:
git branch -a
# Local branches:
# * main
# feature/login
# Remote branches:
# remotes/origin/mainUse tab completion to avoid typos. In most shells, typing git push origin m and pressing Tab auto-completes the branch name.
Case sensitivity differs by file system. ext4, APFS (case-sensitive), and Btrfs treat Main and main as separate refs. NTFS and the default APFS on macOS are case-insensitive at the file level, so the ref file may collide, but Git still rejects the name mismatch when matching the literal refspec you typed.
Fix 6: Fix the Default Branch Configuration
Set Git’s default branch name to avoid future mismatches:
# Set default branch name for new repos
git config --global init.defaultBranch mainThis setting only affects future git init calls. Existing repos keep whatever name they were created with. To check the current value, run git config --global init.defaultBranch. If it prints nothing, your Git falls back to master.
For an existing repo, rename the branch:
# Rename current branch to main
git branch -m main
# Update the remote
git push -u origin main
# Set the new default on GitHub (via web UI or API):
# Settings → Branches → Default branch → Change to "main"
# Delete the old branch on the remote
git push origin --delete masterFix 7: Fix Pushing Tags vs Branches
If you are trying to push a tag, not a branch:
# This fails if "v1.0.0" is a tag, not a branch
git push origin v1.0.0
# error: src refspec 'v1.0.0' does not match any
# Push a tag explicitly
git push origin tag v1.0.0
# or
git push origin refs/tags/v1.0.0Push all tags:
git push origin --tagsFix 8: Fix Submodule and Worktree Issues
In rare cases, submodules or worktrees can cause this error:
# Check if you are in a submodule
git rev-parse --show-superproject-working-tree
# Check worktree status
git worktree listIf you are accidentally in a submodule directory:
cd .. # Go back to the main repo
git push origin mainA worktree shares the same object store but has its own HEAD. If two worktrees both think they own main, Git refuses to check out the second one — but the first push still works. The error appears when a third process (a CI build, an IDE indexer) deletes the working ref between the time you typed git push and the time Git resolved the refspec.
Still Not Working?
Verify the remote URL is correct:
git remote -v
# Should show the correct repository URLCheck if the remote repository exists:
git ls-remote origin
# Lists all refs on the remote
# Empty output means the remote is empty or unreachableForce push (use with caution):
git push -u origin main --forceWarning: Force pushing overwrites the remote branch. Only use this on new repositories or when you are certain about what you are doing.
Check for a packed-refs vs loose-refs mismatch. Git stores branch tips either as files under .git/refs/heads/ or packed inside .git/packed-refs. Tools that edit packed-refs by hand (or interrupted git gc runs) can leave the ref unresolvable even though git branch lists it. Run git pack-refs --all to consolidate, then retry the push.
Check for a stale HEAD file. If .git/HEAD contains ref: refs/heads/main but .git/refs/heads/main is missing, git status reports On branch main while every push fails. Make a commit with git commit --allow-empty -m "bootstrap" to materialize the ref.
Check the hook output. A pre-push hook that prints nothing but exits non-zero looks identical to a refspec mismatch in some terminals. Run GIT_TRACE=1 git push origin main 2>&1 | head -40 to see what Git is actually executing.
Check for credential issues. If the remote URL is correct but push still fails, the error might be an authentication issue disguised as a refspec error. See Fix: error: failed to push some refs for push-related errors and Fix: git permission denied publickey for SSH authentication issues.
For other Git branch issues, see Fix: Git cannot lock ref — a related ref-management failure with similar symptoms.
Solo developer based in Japan. Every solution is cross-referenced with official documentation and tested before publishing.
Was this article helpful?
Related Articles
Fix: DVC Not Working — Remote Push Errors, Pipeline DAG Issues, and Git Integration
How to fix DVC errors — dvc push authentication failed, dvc pull file missing, pipeline stage not reproducing, cache out of disk space, dvc add vs dvc stage, conflict with git LFS, and S3/GCS remote setup.
Fix: Git Hooks Not Running — Husky Not Working, pre-commit Skipped, or lint-staged Failing
How to fix Git hooks not executing — Husky v9 setup, hook file permissions, lint-staged configuration, pre-commit Python tool, lefthook, and bypassing hooks in CI.
Fix: Git Keeps Asking for Username and Password
How to fix Git repeatedly prompting for credentials — credential helper not configured, HTTPS vs SSH, expired tokens, macOS keychain issues, and setting up a Personal Access Token.
Fix: Undo git reset --hard and Recover Lost Commits
How to undo git reset --hard and recover lost commits using git reflog — step-by-step recovery for accidentally reset branches, lost work, and dropped stashes.