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
- Fix the remote (server) repo; it should not be shallow. On the server:
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
- 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
- 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.
- 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
- SSH to the server and run inside the bare repo:
- 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
- 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.
- 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.