Fix: error: failed to push some refs to remote
Part of: Docker, DevOps & Infrastructure
Quick Answer
How to fix Git error 'failed to push some refs' caused by diverged branches, remote changes, protected branches, authentication failures, and pre-push hooks.
The Error
You run git push and get:
To github.com:user/repo.git
! [rejected] main -> main (fetch first)
error: failed to push some refs to 'github.com:user/repo.git'
hint: Updates were rejected because the remote contains work that you do not
hint: have locally. Integrate the remote changes (e.g., 'git pull ...') before pushing again.Or variations:
error: failed to push some refs to 'origin'
hint: Updates were rejected because the tip of your current branch is behind
hint: its remote counterpart.error: failed to push some refs to 'github.com:user/repo.git'
hint: Updates were rejected because a pushed branch tip is behind its remote counterpart.remote: error: GH006: Protected branch update failed for refs/heads/main.
error: failed to push some refs to 'github.com:user/repo.git'Git refused to push your commits to the remote repository. The remote has changes you do not have locally, or something else is blocking the push.
Why This Happens
When you push, Git checks if your local branch can be fast-forwarded onto the remote branch. If the remote branch has commits that your local branch does not, the push fails because it would overwrite those commits. Git treats this as a safety stop: rather than silently throwing away those remote commits, it refuses the push and asks you to reconcile.
Behind the scenes, every Git push uses a small protocol exchange. Your client tells the server, “I want to update refs/heads/main from commit A to commit B.” The server walks its current ref and confirms that A is the current value. If the server’s main is actually pointing at commit C — because someone else pushed, or because you rewrote history — the precondition fails and the server returns ! [rejected]. The hint text you see is generated by Git’s advice.pushNonFastForward machinery, not the server itself, which is why the wording varies subtly between Git versions.
The “failed to push some refs” line is the umbrella message. The interesting detail is always the inner reason: fetch first, non-fast-forward, GH006, pre-receive hook declined, file size, or permission denied. Read that line carefully before reaching for --force. The wrong fix here can erase a teammate’s work in seconds.
Common causes:
- Someone else pushed first. A teammate pushed commits to the same branch while you were working.
- You pushed from another machine. Your own commits from a different computer are on the remote.
- Branch protection rules. GitHub/GitLab/Bitbucket branch protection blocks direct pushes.
- Rebased or amended history. You rewrote local history that diverges from the remote.
- Authentication failure. Your credentials expired or are wrong.
- Pre-push hook failure. A Git hook script rejected the push.
- Large file rejection. The remote rejects files exceeding size limits.
Version History That Changes the Failure Mode
The exact wording, defaults, and even safety behavior of git push have changed several times. Knowing your client version (git --version) and your server’s Git version tells you which fix actually applies.
- Git 2.0 (May 2014) changed
push.defaultfrommatchingtosimple. Older clients pushed every matching branch; modern clients only push the current branch. Many “why did my fix branch end up on main?” stories come from pre-2.0 defaults. - Git 2.21 (Feb 2019) refined
push.default = simplesemantics to require that the upstream branch share the same name. If your local branch name does not match the upstream, you getsrc refspec ... does not match any, which is a related but separate failure. - Git 2.27 (Jun 2020) started warning when
git pullis run without an explicitpull.rebasesetting. That warning is the hint to pick Fix 2 over Fix 1. - Git 2.28 (Jul 2020) introduced
init.defaultBranch, letting you makemainthe default name. Older clones still createmaster, which is whygit push origin mainsometimes fails with “src refspec main does not match” on legacy local repos. - Git 2.30 (Dec 2020) added
push.useForceIfIncludes, which makes--force-with-leaseeven safer by requiring that the lease ref was actually fetched into your local repo. Use it in any 2.30+ workflow. - Git 2.34 (Nov 2021) flipped the default merge strategy to
ort. This changes how merge commits are produced aftergit pull, which can affect subsequent fast-forward checks. - Git 2.37 (Jun 2022) added
branch.autoSetupMerge = simple, which only sets up upstream tracking when the remote and local branch names match. This eliminates a category of “I pushed and nothing went where I expected” bugs. - Git 2.41 (Jun 2023) rewrote many of the hints you see in error output to be shorter and more actionable. If your error text looks different from what older Stack Overflow answers show, that is why.
- GitHub deprecated password authentication on Aug 13, 2021. Any HTTPS push from a client older than that date may need a Personal Access Token even if the local Git binary is current.
- GitHub raised the warning threshold to 50 MB and the hard limit to 100 MB. Git LFS (initially released Apr 2015) is the supported escape hatch; rewriting history with
git filter-repo(Sep 2019, replacing the slowergit filter-branch) is the cleanup tool.
If you are stuck on Git < 2.30, upgrade before you trust --force-with-lease on a shared branch.
Fix 1: Pull Before Pushing
The most common fix. Integrate the remote changes first:
git pull origin mainIf there are no conflicts, Git merges the remote changes into your branch. Then push:
git push origin mainIf git pull creates a merge commit and you prefer a linear history, use git pull --rebase instead (see Fix 2).
If git pull itself fails because you have uncommitted local changes, see Fix: Your local changes would be overwritten by merge.
Fix 2: Pull with Rebase
For a cleaner history without merge commits:
git pull --rebase origin mainThis replays your local commits on top of the remote commits. The result is a linear history.
If conflicts arise during rebase:
# Edit the conflicting files
git add <resolved-files>
git rebase --continueThen push:
git push origin mainTo make rebase the default behavior for git pull:
git config --global pull.rebase truePro Tip: Use
git pull --rebaseas your default workflow. It prevents unnecessary merge commits and keeps the branch history clean. Most teams prefer this over merge-based pulls.
Fix 3: Fix Diverged Branches After Rebase or Amend
If you amended a commit or rebased after already pushing, your local and remote histories have diverged. A regular push fails because the histories are incompatible.
Check the divergence:
git log --oneline --graph HEAD origin/mainOption 1 — Force push (if you are the only one working on the branch):
git push --force-with-lease origin main--force-with-lease is safer than --force. It fails if someone else pushed to the branch since your last fetch, preventing you from overwriting their work.
Warning: Never force push to shared branches (like main or develop) unless you have coordinated with your team. Force push rewrites remote history and can cause data loss for others. For more on rejected pushes, see Fix: git push rejected non-fast-forward.
Option 2 — Reset to remote and re-apply your changes:
If you are not sure what happened and want to start clean:
git fetch origin
git log --oneline origin/main # See what's on remote
git log --oneline HEAD # See what's localThen decide whether to merge, rebase, or cherry-pick your changes.
Fix 4: Fix Protected Branch Errors
If the error includes GH006: Protected branch update failed or similar:
remote: error: GH006: Protected branch update failed for refs/heads/main.
remote: - Changes must be made through a pull request.The branch has protection rules that block direct pushes. You need to create a pull request instead:
# Create a feature branch
git checkout -b my-feature
# Push the feature branch
git push -u origin my-feature
# Create a PR on GitHub
gh pr create --title "My changes" --body "Description"Check branch protection settings:
In GitHub: Settings → Branches → Branch protection rules.
Common protections:
- Require pull request reviews — direct pushes blocked
- Require status checks — CI must pass before merge
- Require signed commits — unsigned commits rejected
- Restrict who can push — only specific users/teams can push
If you are an admin and need to push directly (not recommended):
git push --force-with-lease origin mainAdmins can bypass some protections, but this is generally a bad practice.
Fix 5: Fix Authentication Failures
If the error is about authentication:
remote: Invalid username or password.
fatal: Authentication failed for 'https://github.com/user/repo.git'
error: failed to push some refs to 'https://github.com/user/repo.git'Fix: Update your credentials:
For HTTPS:
# Check your remote URL
git remote -v
# If using HTTPS, update the credential
git credential reject <<EOF
protocol=https
host=github.com
EOF
# Next push will prompt for new credentials
git push origin mainFor SSH:
# Test SSH connection
ssh -T [email protected]
# If it fails, check your SSH key
ssh-add -lIf SSH authentication fails entirely, see Fix: git permission denied publickey.
GitHub personal access tokens: If you use HTTPS with GitHub, you need a PAT (Personal Access Token) instead of your password. GitHub stopped accepting passwords in August 2021.
Fix 6: Fix Large File Rejections
GitHub rejects files larger than 100 MB:
remote: error: File large-data.csv is 150.00 MB; this exceeds GitHub's file size limit of 100.00 MB
error: failed to push some refs to 'github.com:user/repo.git'Fix: Remove the large file from history:
git rm --cached large-data.csv
echo "large-data.csv" >> .gitignore
git commit -m "Remove large file"If the file was committed in a previous commit, you need to rewrite history:
git filter-branch --force --index-filter \
"git rm --cached --ignore-unmatch large-data.csv" \
--prune-empty -- --allOr use the faster git-filter-repo:
pip install git-filter-repo
git filter-repo --path large-data.csv --invert-pathsFix: Use Git LFS for large files:
git lfs install
git lfs track "*.csv"
git add .gitattributes
git add large-data.csv
git commit -m "Track CSV with LFS"
git push origin mainCommon Mistake: Removing a large file from the working directory and committing the removal does not remove it from Git history. The file still exists in previous commits and the push still fails. You must use
filter-branchorfilter-repoto rewrite history.
Fix 7: Fix Pre-Push Hook Failures
If a pre-push hook rejects the push:
error: failed to push some refs to 'origin'The error output usually includes messages from the hook. Common hook checks:
- Running tests before push
- Checking code formatting
- Validating commit messages
- Scanning for secrets or credentials
Find the hook:
cat .git/hooks/pre-pushOr for shared hooks configured by the project:
git config core.hooksPathFix the underlying issue (failing tests, formatting errors, etc.) rather than bypassing the hook.
Fix 8: Fix Pushing to a New Remote
If the remote does not exist or the URL is wrong:
# Check the remote URL
git remote -v
# Fix the URL
git remote set-url origin [email protected]:user/repo.git
# Or add a remote if none exists
git remote add origin [email protected]:user/repo.gitIf the remote repository itself does not exist, create it first (on GitHub, GitLab, etc.) and then push:
git push -u origin mainThe -u flag sets up tracking between your local and remote branch.
Still Not Working?
If the error persists after trying the fixes above:
Check if the remote branch was deleted. If someone deleted the remote branch and recreated it, your local tracking is stale:
git fetch --prune origin
git push origin mainCheck for required commit signing. Some repositories require GPG-signed commits. Unsigned commits are rejected:
git log --show-signature -1If your commit is not signed and signing is required:
git config user.signingkey YOUR_KEY_ID
git commit --amend -S # Re-sign the last commitCheck for repository transfer or rename. If the repository was moved to a new organization or renamed, update your remote URL.
Check disk space on the remote. Self-hosted Git servers (Gitea, GitLab CE) can reject pushes when disk space is low.
Check the server-side hooks. If the remote runs custom server-side hooks (pre-receive, update, post-receive), they might reject your push for reasons not shown in the client error. Check the server logs or contact the repository administrator.
Try pushing a single commit. If pushing many commits fails, try pushing one at a time to identify which commit is causing the issue:
git push origin HEAD~5:main # Push all but the last 5
git push origin HEAD~4:main # Then the next one
# Continue until you find the problematic commitCheck whether core.autocrlf rewrote line endings. On Windows clients, an autocrlf = true setting can cause a pre-receive hook that validates file hashes to reject every push. Inspect the rejection text for CRLF or mixed line endings, set core.autocrlf = input, and re-commit the affected files.
Check whether the upstream is set to a deleted ref. After a teammate runs git push --delete origin feature-x, your local origin/feature-x still exists until you run git fetch --prune. A subsequent push targets a ref that no longer exists, returning failed to push some refs with a quietly different inner cause. Always run git fetch --prune before debugging.
Check whether your IDE is using a separate Git binary. VS Code, JetBrains IDEs, and SourceTree often bundle their own Git executable. If the bundled version is older than 2.30, --force-with-lease may behave differently than from the terminal. Run git --version inside the IDE’s integrated terminal and compare it with git --version in your shell.
Check the network proxy and HTTP/2 settings. Corporate proxies sometimes terminate the smart HTTP push midway, producing a generic failed to push some refs. Set git config --global http.version HTTP/1.1 and retry. If it works, you have a proxy compatibility issue rather than a Git issue.
If you end up in merge conflict during the pull, see Fix: git merge conflict for resolution steps.
Solo developer based in Japan. Every solution is cross-referenced with official documentation and tested before publishing.
Was this article helpful?
Related Articles
Fix: gh CLI Not Working — Auth Scopes, Multiple Accounts, PR Create Errors, and Enterprise Hosts
How to fix GitHub CLI errors — gh auth login token scopes missing, multiple accounts switching, gh pr create permission denied, GHE host auth, gh repo clone vs git clone, and API rate limits.
Fix: Git remote rejected — file exceeds GitHub's file size limit of 100.00 MB
Resolve the GitHub push error when a file exceeds the 100 MB size limit by removing the large file from history, using Git LFS, or cleaning your repository with BFG Repo Cleaner.
Fix: CONFLICT (content): Merge conflict in file — fix conflicts and then commit the result
How to fix Git merge conflicts during merge, rebase, cherry-pick, and pull — resolve conflict markers, use merge tools, accept theirs or ours, abort, and prevent future conflicts.
Fix: fatal: not a git repository (or any of the parent directories): .git
How to fix the 'fatal: not a git repository' error in Git by checking your working directory, initializing a repo, recovering a deleted .git folder, and resolving submodule, CI/CD, and IDE path issues.