KhueApps
Home/DevOps/Fix 'failed to push some refs (pre-receive hook declined)' in Git

Fix 'failed to push some refs (pre-receive hook declined)' in Git

Last updated: October 07, 2025

Topic: How to fix 'error: failed to push some refs (pre-receive hook declined)'

Category: DevOps • Collection: Git

This error means the remote server ran a pre-receive hook and rejected your push. It’s not a network glitch or a local Git bug—policy enforcement on the server blocked the update. Common causes include protected branches, non–fast-forward updates, commit policy checks, file size limits, or permission rules.

Quickstart (TL;DR)

  • Read the server’s rejection message shown after the push; it often states the exact rule violated.
  • If pushing to a protected branch (e.g., main): push to a new branch and open a pull request.
  • If non–fast-forward: fetch, rebase or merge to align with remote, then push with --force-with-lease only if your team allows history rewrites.
  • If large files or LFS required: move large binaries to Git LFS and purge them from history.
  • If commit signing/policy failed: fix the commit(s) and push again.

Minimal working example (common fix)

Scenario: You’re trying to push changes that are behind the remote branch or the branch is protected.

# 1) Sync local refs
git fetch --prune origin

# 2) Update your feature branch with the latest main (adjust names as needed)
# If you were on main and it's protected, switch to a feature branch
BR=feature/fix-pre-receive-decline
git switch -c "$BR"
git rebase origin/main

# 3) Push a new branch to avoid protected-branch policies
git push --set-upstream origin "$BR"

# 4) Open a pull request on your platform to merge into main

If your team allows history rewrites and you must update an existing branch:

# Align your branch, then force-push safely
git fetch origin
git rebase origin/your-branch
# Use --force-with-lease (safer than --force)
git push --force-with-lease origin your-branch

Diagnose the rejection message

  • The lines printed by the remote during push are key. Look for phrases like:
    • "protected branch"
    • "non-fast-forward updates are not allowed"
    • "commit message does not match policy"
    • "large file detected / LFS required"
    • "missing required signature" or "unsigned commits"
    • "secret detected" or "blocked file path"
  • If you control the server, check the repository’s pre-receive hook and logs. On self-hosted Git, hooks live in repo.git/hooks/pre-receive.
  • For deeper client-side tracing when needed:
GIT_TRACE=1 GIT_TRACE_PACKET=1 git push origin HEAD

Common causes and fixes

  • Protected branch rules

    • Symptom: Pushing to main/develop is rejected.
    • Fix: Push to a feature branch and create a pull request; or relax protection if policy allows.
  • Non–fast-forward update (history rewrite blocked)

    • Symptom: "non-fast-forward" in message.
    • Fix: git fetch, then git rebase origin/<branch> or git merge origin/<branch>. If policy allows, git push --force-with-lease.
  • Missing permissions

    • Symptom: You can read but cannot push to the branch.
    • Fix: Request push/maintainer rights or push to a fork/feature branch.
  • Commit message or format policy

    • Symptom: Messages like "must reference a ticket", "no merge commits", or "DCO sign-off required".
    • Fix: Amend commits to meet policy:
git commit --amend -m "feat: JIRA-123 add validation"
# Or add DCO sign-off
git commit --amend -s
# Then push (force-with-lease if history changed)
git push --force-with-lease
  • GPG/SSO signing required
    • Symptom: "unsigned commits" or "invalid signature".
    • Fix: Configure signing and re-create commits:
git config --global user.signingkey <KEYID>
git config --global commit.gpgsign true
# Rebase to re-sign each commit
GIT_COMMITTER_DATE="now" git rebase -i --rebase-merges --exec 'git commit --amend --no-edit --gpg-sign' origin/main
  • Large files or Git LFS requirement
    • Symptom: Errors mentioning file size or LFS.
    • Fix: Track and migrate with LFS, then purge large blobs from history:
git lfs track "*.bin"
echo "*.bin" >> .gitattributes
# Migrate history to move existing large files to LFS
git lfs migrate import --include="*.bin"
# Force-push with lease if policy allows
git push --force-with-lease
  • Secret scanning / forbidden content
    • Symptom: "secret detected" or blocked patterns.
    • Fix: Rotate secrets, remove from history, add secure config:
# Remove secret from latest commit
git reset --soft HEAD~1
# Replace with env var/config, recommit
# To scrub from history (careful):
BLOB=<path>
git filter-repo --path "$BLOB" --invert-paths
  • Shallow clone limitations
    • Symptom: Rebase fails due to missing history.
    • Fix: Unshallow before rebasing:
git fetch --unshallow

Step-by-step resolution checklist

  1. Read the exact server message after the failed push.
  2. Identify the category: protection, non–fast-forward, permissions, policy, size/LFS, secrets.
  3. Synchronize local state: git fetch --prune origin.
  4. Update your branch: git rebase origin/<target> (or git merge if your workflow prefers it).
  5. If branch is protected: push to a new branch: git push -u origin HEAD and open a PR.
  6. If policy failed: amend/rewrite commits to comply (message format, sign-off, GPG signing).
  7. If large files: adopt LFS and purge large blobs, then push.
  8. If history rewrite is intended and allowed: git push --force-with-lease.
  9. If you lack permission: request access or use a fork.

Pitfalls

  • Using --force indiscriminately: prefer --force-with-lease to avoid overwriting collaborators’ work.
  • Rewriting shared branch history without team agreement.
  • Ignoring the server’s error text; it typically names the violation.
  • Mixing binaries into Git history; use LFS early to avoid costly purges.
  • Amending old commits without re-pushing all dependent branches.

Performance notes

  • Large pushes are slow and more likely to trip hooks. Keep histories lean; run git gc periodically.
  • Use Git LFS for big assets; it reduces pack sizes and server-side checks on blobs.
  • Rebasing a long-lived branch frequently keeps diffs small and pushes faster.
  • Prefer --force-with-lease over --force; it reduces accidental retries from conflicts.
  • If CI runs as part of pre-receive on self-hosted setups, expect pushes to wait for checks; push smaller, incremental commits to shorten cycles.

Tiny FAQ

  • What is a pre-receive hook?

    • A server-side script that runs before the remote accepts your updates. It can reject pushes that violate policy.
  • Can I bypass it with --no-verify?

    • No. --no-verify only skips client-side hooks. Server hooks still run.
  • Why did push fail but pull/merge requests work?

    • Pushing to protected branches is blocked; merging via PR runs checks and uses server-side permissions.
  • Is --force safe?

    • Use --force-with-lease. It refuses to overwrite remote changes you haven’t seen.
  • I don’t control the server—what now?

    • Adjust your workflow (feature branches, PRs) or contact the repo admin to review policies and permissions.

Series: Git

DevOps