KhueApps
Home/DevOps/Fix Git errors: "shallow update not allowed" or fetch declined

Fix Git errors: "shallow update not allowed" or fetch declined

Last updated: October 07, 2025

Overview

You’re seeing one of these errors when working with a shallow clone (made with --depth or --shallow-since):

  • fatal: shallow update not allowed
  • fatal: fetch declined (or “server does not allow shallow fetch”)

They occur when either:

  • Your local repository is shallow and Git needs more history to fetch/rebase/merge.
  • The remote (server-side) repository is shallow and refuses updates.

This guide shows quick fixes, safe configurations, and alternatives that keep performance while avoiding breakage.

Quickstart

  • If your local clone is shallow and fetch/pull is declined:

    • Convert to a full clone: git fetch --unshallow
    • Or deepen just enough: git fetch --deepen=1000
    • Re-run your fetch/pull/rebase.
  • If push fails with “shallow update not allowed”:

    • Fix the remote (server) repo; it should not be shallow. On the server:
      • Unshallow: git fetch --unshallow --tags
      • Or rebuild the remote as a non-shallow bare/mirror.
    • Only as a last resort, temporarily allow shallow updates: git config receive.shallowUpdate true
  • In CI, disable shallow checkouts:

    • GitHub Actions: use actions/checkout with fetch-depth: 0
    • GitLab CI: set GIT_DEPTH: 0
    • Jenkins: uncheck “Shallow clone” or set depth to 0

Minimal working example

A. Local shallow clone blocks fetch/rebase

# Start with a shallow clone
git clone --depth=1 https://example.com/repo.git app
cd app

# Later you try to fetch more history (e.g., for rebase) and it’s declined
# Fix: convert to a full clone (or deepen)
git fetch --unshallow    # or: git fetch --deepen=1000

git rebase origin/main   # now succeeds because full history is present

B. Push rejected because the remote repository is shallow

# Simulate a shallow remote locally for demonstration
mkdir /tmp/remote && cd /tmp/remote

# Create a bare remote and make it shallow (do NOT do this in real servers)
git init --bare origin.git
# Populate it by fetching shallowly from some upstream (example: another local repo)
# git -C origin.git fetch --depth=1 /path/to/upstream main:main

# From a client clone, pushing will be rejected with "shallow update not allowed"
# Fix on the server: unshallow the remote
cd /tmp/remote/origin.git
git fetch --unshallow --tags   # bring in full history
# Optionally make sure shallow update is not required anymore

echo "Now client push will succeed without shallow errors"

Step-by-step remedies

  1. Detect whether your repo is shallow
  • Local: git rev-parse --is-shallow-repository (prints true/false)
  • Also check for .git/shallow file
  • Remote (server/bare): run the same command on the repo path on the server
  1. If local is shallow and you need more history
  • Full history: git fetch --unshallow
  • Incremental: git fetch --deepen=N (repeat until the operation succeeds)
  • For a specific branch only: git fetch --depth=1 origin main
  • Then retry: git pull --rebase, git rebase, git merge, etc.
  1. If the remote is shallow (push rejected)
  • Strongly recommended: unshallow the remote
    • SSH to the server and run inside the bare repo:
      • git fetch --unshallow --tags
    • If the remote mirrors another source, rebuild it as a non-shallow mirror:
      • mv repo.git repo.git.bak
      • git clone --mirror <upstream-url> repo.git
  • Only if you fully understand the risks, temporarily allow updates:
    • git -C /path/to/repo.git config receive.shallowUpdate true
    • Revert this after the push: git -C /path/to/repo.git config --unset receive.shallowUpdate
  1. CI systems: disable shallow clones when you need full history
  • GitHub Actions (actions/checkout):
- uses: actions/checkout@v4
  with:
    fetch-depth: 0  # full history; avoids shallow-related failures
  • GitLab CI:
variables:
  GIT_DEPTH: 0  # full history
  • Jenkins (Git plugin): uncheck “Shallow clone” or set depth to 0.
  1. Replace shallow clones with safer performance options
  • Partial clone (full commit history, blobless):
git clone --filter=blob:none https://example.com/repo.git
  • This avoids shallow-repo limitations while keeping network usage low for large repos.

Pitfalls and how to avoid them

  • Central remotes must not be shallow

    • Never create your canonical bare remote via a shallow fetch. Rebuild as a full mirror if it is.
  • Non-fast-forward pushes are separate from shallow issues

    • A rejected push may also be due to non-fast-forward updates. Check: git push --force-with-lease only if policy allows.
  • Tags pointing outside your shallow boundary

    • Fetching tags can fail if they reference commits you don’t have. Run git fetch --deepen=N or --unshallow first.
  • Submodules

    • Shallow submodules can block superproject operations. Update with depth or unshallow: git submodule update --init --recursive --depth=1 or remove depth.
  • Gerrit and similar code review servers

    • Some servers disallow shallow fetch/push. Remove --depth from your clone/fetch or use fetch-depth: 0 in CI.
  • Large monorepos

    • Prefer partial clone (--filter=blob:none) and optionally sparse-checkout over shallow clones to avoid history-related failures.

Performance notes

  • Shallow clone speeds initial checkout but can break rebase, merge, and tag fetching later.
  • Partial clone reduces blob transfer without hiding commit history, avoiding shallow-specific rejections.
  • If bandwidth is the main constraint, use:
    • git clone --filter=blob:none
    • git fetch --filter=blob:none (for subsequent fetches)
  • If you must stay shallow, plan to deepen gradually when operations need more history.

Tiny FAQ

  • Q: Can I push from a shallow clone?

    • A: Sometimes, but servers may reject it. It’s safer to unshallow before pushing.
  • Q: How do I check if a repo is shallow?

    • A: Run git rev-parse --is-shallow-repository; true means shallow.
  • Q: Is enabling receive.shallowUpdate safe?

    • A: It’s discouraged on shared remotes. Prefer unshallowing or rebuilding the remote.
  • Q: What’s the fastest way to avoid these errors without full history?

    • A: Use partial clone: git clone --filter=blob:none, not --depth.
  • Q: My CI uses shallow clones by default. What should I set?

    • A: Set full history (fetch-depth: 0 or GIT_DEPTH: 0) on jobs that need tags, merges, or rebases.

Series: Git

DevOps