How to fix fatal: git fetch-pack: expected shallow list. Shallow clone may not have all commits in Git
The 'fatal: git fetch-pack: expected shallow list' error occurs when Git's shallow clone protocol encounters an unexpected response during fetch operations. This typically happens in CI/CD pipelines where shallow clones lack required commit history for operations like merges, rebases, or version detection.
Quick fix
Fixes fatal: git fetch-pack: expected shallow list. Shallow clone may not have all commits
# Fetch all remaining history
git fetch --unshallow
# Verify the repository is no longer shallow
git rev-parse --is-shallow-repository
# Should output: false- Unshallow the repository to fetch full history
- Increase clone depth in CI/CD configuration
- Fetch specific branches and tags needed for the operation
- Fix corrupted shallow file
# Fetch all remaining historygit fetch --unshallow# Verify the repository is no longer shallowgit rev-parse --is-shallow-repository# Should output: falsefatal: git fetch-pack: expected shallow list. Shallow clone may not have all commits
What this error means
The "fatal: git fetch-pack: expected shallow list" error indicates a protocol-level failure during Git's fetch operation. This error occurs when Git expects to receive shallow clone metadata but the server or local repository state doesn't match expectations. Shallow clones are partial clones created with `git clone --depth=N` that only contain the most recent N commits. While they significantly reduce clone time and disk usage, they can cause problems when Git operations need access to commits beyond the shallow boundary. CI/CD systems commonly use shallow clones to speed up builds, but this optimization creates issues when: - A merge or rebase requires commits from before the shallow depth - Build tools try to count commits or determine versions from Git history - Git needs to find the merge-base between branches - The shallow clone's commit graph becomes inconsistent with the remote The error message "Shallow clone may not have all commits" explicitly warns that the requested operation cannot complete because the necessary commit history is unavailable in the shallow repository.
Typical symptoms
- CI/CD pipeline fails during git fetch or git pull operations
- Error message: 'fatal: git fetch-pack: expected shallow list'
- Warning: 'Shallow clone may not have all commits'
- Git merge operations fail with 'fatal: refusing to merge unrelated histories'
- Git rebase fails to find merge base
- Version detection tools report incorrect or missing version information
- Git describe fails with 'fatal: No names found, cannot describe anything'
- Submodule updates fail in shallow-cloned repositories
- GitHub Actions or GitLab CI workflows fail on pull request merges
- Error occurs after repository force-push or history rewrite
Common causes
- Shallow clone depth is insufficient for the required operation
- CI/CD pipeline uses shallow clone but needs full history for merge/rebase
- Remote repository history was force-pushed or rewritten after shallow clone
- Shallow clone created from a branch that has since diverged significantly
- Git protocol version mismatch between client and server
- Corrupted shallow file (.git/shallow) in the repository
- Submodules or nested Git operations expecting full history
- Build scripts running git log, git describe, or commit counting
- Pull request merge requiring commits from before shallow depth
- Network interruption during shallow clone creation
How to fix "fatal: git fetch-pack: expected shallow list. Shallow clone may not have all commits"
The most reliable fix is to convert the shallow clone to a full clone:
# Fetch all remaining history
git fetch --unshallow
# Verify the repository is no longer shallow
git rev-parse --is-shallow-repository
# Should output: falseIf --unshallow fails, try fetching with increased depth:
# Fetch more history incrementally
git fetch --depth=100
git fetch --depth=1000
git fetch --unshallowConfigure your CI/CD pipeline to clone with sufficient depth:
GitHub Actions:
- uses: actions/checkout@v4
with:
fetch-depth: 0 # Full history
# Or use a specific depth:
# fetch-depth: 100GitLab CI:
variables:
GIT_DEPTH: 0 # Full clone
# Or specific depth:
# GIT_DEPTH: 100
# Or per-job:
job_name:
variables:
GIT_DEPTH: 0Jenkins:
checkout([
$class: 'GitSCM',
extensions: [[$class: 'CloneOption', depth: 0, shallow: false]]
])CircleCI:
- checkout:
# CircleCI doesn't shallow clone by default
# But if using custom clone:
- run:
command: git clone --depth=0 $CIRCLE_REPOSITORY_URL .If full history is too expensive, fetch only what's needed:
# Fetch the target branch for merging
git fetch origin main:refs/remotes/origin/main
# Fetch with enough depth for merge base
git fetch --deepen=50 origin main
# Fetch all tags (often needed for version detection)
git fetch --tags
# Fetch specific commit if known
git fetch origin <commit-sha>For pull request workflows, fetch both branches:
# Fetch PR branch and target branch
git fetch origin pull/$PR_NUMBER/head:pr-branch
git fetch origin $TARGET_BRANCH:$TARGET_BRANCH --depth=100If the shallow clone metadata is corrupted, repair it:
# Check if shallow file exists and its contents
cat .git/shallow
# If corrupted or inconsistent, remove and re-fetch
rm .git/shallow
git fetch --unshallow
# Or recreate the repository
cd ..
rm -rf repo-name
git clone https://github.com/user/repo-name.gitIf you can't remove the repository (e.g., has local changes):
# Backup local changes
git stash
# Repair shallow information
git fetch origin --unshallow
# Restore changes
git stash popIf the remote was force-pushed, your shallow clone may reference commits that no longer exist:
# Reset to match remote state
git fetch origin
git reset --hard origin/main
# If that fails, start fresh
git fetch --refetch --unshallow
# Or clone again
cd ..
rm -rf repo-name
git clone https://github.com/user/repo-name.gitTo prevent this in CI, always use fresh clones:
# GitHub Actions - always clean
- uses: actions/checkout@v4
with:
clean: true
fetch-depth: 0Protocol version mismatches can cause shallow clone errors. Try switching versions:
# Use protocol version 2 (recommended)
git config --global protocol.version 2
# Or fall back to version 1 if v2 causes issues
git config --global protocol.version 1
# Then retry the operation
git fetch --unshallowIn CI/CD, set this before checkout:
- run: git config --global protocol.version 2
- uses: actions/checkout@v4Git 2.22+ supports partial clones, which are more flexible than shallow clones:
# Treeless clone - omits tree and blob objects
git clone --filter=tree:0 https://github.com/user/repo.git
# Blobless clone - omits blob objects
git clone --filter=blob:none https://github.com/user/repo.gitPartial clones include full commit history but lazily fetch file contents, avoiding the shallow clone limitations:
# GitHub Actions with partial clone
- uses: actions/checkout@v4
with:
filter: tree:0This approach maintains full history for merge operations while still reducing initial clone size.
If your build uses git describe for versioning, ensure tags are fetched:
# Fetch all tags
git fetch --tags --force
# If shallow, deepen to include tagged commits
git fetch --shallow-since="2023-01-01"
# Or deepen by count
git fetch --deepen=100
# Verify git describe works
git describe --tags --alwaysFor CI/CD:
# GitHub Actions
- uses: actions/checkout@v4
with:
fetch-depth: 0
fetch-tags: true
# GitLab CI
variables:
GIT_DEPTH: 0
GIT_STRATEGY: fetch
before_script:
- git fetch --tagsIf you only need the latest tag:
# Fetch annotated tags reachable from HEAD
git fetch --tags --shallow-exclude=$(git describe --tags --abbrev=0 2>/dev/null || echo HEAD~100)For very large repositories where full clones are impractical:
# Clone single branch with reasonable depth
git clone --depth=100 --single-branch --branch main https://github.com/user/repo.git
# For PRs, fetch only what's needed
git fetch --depth=100 origin main
git fetch --depth=100 origin pull/$PR_NUMBER/head:pr-branchUse sparse checkout to further reduce size:
git clone --filter=blob:none --sparse https://github.com/user/repo.git
cd repo
git sparse-checkout set path/to/needed/dirConfigure clone timeout to prevent hanging:
# GitLab CI
variables:
GIT_CLONE_TIMEOUT: 600 # secondsAdvanced notes
### Understanding Shallow Clone Internals
Shallow clones store their boundary commits in .git/shallow. This file lists the commits where history is truncated:
# View shallow boundaries
cat .git/shallow
# Output: one commit SHA per line
# Check if repository is shallow
git rev-parse --is-shallow-repositoryThe "expected shallow list" error occurs during the fetch-pack protocol negotiation when Git expects shallow information but receives something unexpected. This can happen when:
1. The .git/shallow file references commits that don't exist on the remote
2. Protocol negotiation fails due to version mismatch
3. The server doesn't support the shallow protocol correctly
### Shallow Clone vs Partial Clone
| Feature | Shallow Clone | Partial Clone |
|---------|--------------|---------------|
| Command | --depth=N | --filter=blob:none |
| History | Truncated | Complete |
| Merges | May fail | Work correctly |
| git log | Limited | Full |
| Lazy fetching | No | Yes |
| Git version | Any | 2.22+ |
### CI/CD Best Practices
For most CI/CD workflows, prefer these strategies in order:
1. For small/medium repos: Full clone (fetch-depth: 0)
2. For large repos with PR workflows: Partial clone (filter: blob:none)
3. For read-only builds: Shallow clone with sufficient depth (fetch-depth: 100)
Avoid shallow clones when:
- Build needs git describe for versioning
- PR workflows require merge/rebase
- Scripts traverse commit history
- Submodules need recursive fetch
### Debugging Protocol Issues
To diagnose fetch-pack errors:
# Verbose fetch
GIT_TRACE=1 GIT_TRACE_PACKET=1 git fetch --unshallow 2>&1 | head -100
# Check protocol version
git config --get protocol.version
# Test server capabilities
GIT_TRACE_PACKET=1 git ls-remote origin### GitHub Actions Specific Notes
GitHub's checkout action behavior:
- Default: fetch-depth: 1 (shallow)
- PR merges: fetches only PR head, not merge base
- Tags: not fetched by default
Recommended configuration for most projects:
- uses: actions/checkout@v4
with:
fetch-depth: 0
persist-credentials: falseFor monorepos or very large repositories:
- uses: actions/checkout@v4
with:
filter: tree:0
fetch-depth: 0 # Still need full commit historyFrequently asked questions
- What does "fatal: git fetch-pack: expected shallow list. Shallow clone may not ha" mean?
- The "fatal: git fetch-pack: expected shallow list" error indicates a protocol-level failure during Git's fetch operation. This error occurs when Git expects to receive shallow clone metadata but the server or local repository state doesn't match expectations. Shallow clones are partial clones created with git clone --depth=N that only contain the most recent N commits.
- How do I fix "fatal: git fetch-pack: expected shallow list. Shallow clone may not ha"?
- The 'fatal: git fetch-pack: expected shallow list' error occurs when Git's shallow clone protocol encounters an unexpected response during fetch operations. This typically happens in CI/CD pipelines where shallow clones lack required commit history for operations like merges, rebases, or version detection.
- What causes "fatal: git fetch-pack: expected shallow list. Shallow clone may not ha"?
- Shallow clone depth is insufficient for the required operation CI/CD pipeline uses shallow clone but needs full history for merge/rebase Remote repository history was force-pushed or rewritten after shallow clone
- Is the "fatal: git fetch-pack: expected shallow list. Shallow clone may not ha" error serious?
- It is a medium-severity error — more of a blocker than a risk. The steps above resolve it.
Official resources & further reading
- 📚Git Official Documentation
- 📖Git Shallow Clone Documentation(Official Docs)
- 📖git-fetch Documentation - Git SCM(Official Docs)
- 📖Git Partial Clone Documentation(Official Docs)
- 🐙GitHub Actions Checkout Action(GitHub)
- 📖GitLab CI - Handling Large Repositories(Official Docs)
- 💬Shallow clone of a single branch - Stack Overflow(Stack Overflow)