Introduction

Git fatal shallow unable to resolve errors occur when a shallow clone (created with --depth flag) attempts to access commits or objects that are not present in the truncated history. Shallow clones are commonly used in CI/CD pipelines to reduce clone time and disk space, but they create fragility when operations require full commit history. The error manifests when fetching deeper history, merging branches, running git describe, calculating version tags, or performing operations that traverse beyond the shallow boundary. The fix requires understanding shallow clone limitations, fetch depth configuration, commit graph traversal, and recovery strategies for corrupted or incomplete repositories. This guide provides production-proven troubleshooting for Git shallow errors across CI/CD platforms (GitHub Actions, GitLab CI, Jenkins), monorepos, and large repositories.

Symptoms

  • fatal: shallow file has changed size, please re-clone
  • fatal: bad shallow line: <commit-hash>
  • fatal: unable to resolve commit '<commit-hash>'
  • error: Server does not allow shallow requests
  • fatal: git upload-pack: not our ref during fetch
  • CI/CD pipeline fails at checkout step with shallow clone errors
  • git describe --tags returns fatal error about commit depth
  • git log shows truncated history then errors
  • Branch merge fails with "ref not found" on shallow clones
  • Submodule checkout fails on shallow repositories

Common Causes

  • Shallow clone depth too shallow for required operations
  • Fetch depth=1 but operation needs parent commits
  • CI/CD pipeline runs git operations requiring full history
  • Repository server disables shallow clones for security
  • Shallow clone boundary crossed during incremental fetch
  • Git LFS objects not fetched with shallow clone
  • Submodule references commits not in shallow history
  • git filter-branch or git filter-repo modifies shallow boundary
  • Corrupted .git/shallow file
  • Remote repository garbage collected commits referenced locally

Step-by-Step Fix

### 1. Confirm shallow clone diagnosis

Check current clone state:

```bash # Check if repository is shallow git rev-parse --is-shallow-repository # Returns: true (shallow) or false (full clone)

# Check shallow file contents cat .git/shallow # Shows commit hashes at shallow boundary

# Check fetch depth git config --get remote.origin.fetch # Returns: +refs/heads/*:refs/remotes/origin/* (full) # Or: +refs/heads/main:refs/remotes/origin/main (partial)

# Check actual depth git log --oneline | wc -l # Very low count suggests shallow clone

# Try to fetch deeper git fetch --depth=10 # If this fails, server may block shallow requests ```

CI/CD specific checks:

```yaml # GitHub Actions - check checkout configuration - uses: actions/checkout@v4 with: fetch-depth: 1 # Shallow clone (may cause issues) # fetch-depth: 0 # Full clone (recommended) # fetch-depth: 50 # Fetch last 50 commits

# GitLab CI - check GIT_DEPTH variable # Default: GIT_DEPTH=50 echo $GIT_DEPTH

# Jenkins - check checkout configuration checkout([$class: 'GitSCM', extensions: [[$class: 'CloneOption', depth: 1, # Shallow noTags: true ]], userRemoteConfigs: [[url: 'https://github.com/org/repo.git']] ]) ```

### 2. Fix by fetching full history

Convert shallow clone to full clone:

```bash # Unshallow current repository git fetch --unshallow

# Or fetch with specific depth (larger number) git fetch --depth=100

# Or fetch all history explicitly git fetch origin --depth=1000000

# For CI/CD, update checkout configuration # GitHub Actions: - uses: actions/checkout@v4 with: fetch-depth: 0 # Full clone

# GitLab CI: variables: GIT_DEPTH: 0 # Full clone

# Jenkins: checkout([$class: 'GitSCM', extensions: [[$class: 'CloneOption', depth: 0]], ]) ```

Re-clone without shallow option:

```bash # Remove existing shallow clone rm -rf repo git clone https://github.com/org/repo.git

# Or clone with explicit full depth git clone --depth=1000000 https://github.com/org/repo.git

# For large repos, use partial clone (Git 2.19+) git clone --filter=blob:none https://github.com/org/repo.git # Fetches all commits but lazy-loads file contents ```

### 3. Fix corrupted shallow file

When .git/shallow is corrupted:

```bash # Backup and remove shallow file cp .git/shallow .git/shallow.bak rm .git/shallow

# Attempt to repair by fetching git fetch origin main

# If that fails, re-clone cd .. rm -rf repo git clone https://github.com/org/repo.git

# For CI/CD, add cleanup step before checkout - name: Clean git repository run: | rm -rf .git/shallow git config --unset remote.origin.shallow

  • name: Checkout code
  • uses: actions/checkout@v4
  • with:
  • fetch-depth: 0
  • `

Fix shallow file format errors:

```bash # Check shallow file format cat .git/shallow | while read line; do if ! echo "$line" | grep -qE '^[0-9a-f]{40}$'; then echo "Invalid line: $line" fi done

# Remove invalid entries grep -E '^[0-9a-f]{40}$' .git/shallow > .git/shallow.fixed mv .git/shallow.fixed .git/shallow

# Try to fetch and repair git fetch --depth=10 ```

### 4. Handle server blocking shallow requests

Some servers disable shallow clones:

```bash # Error: fatal: The remote end hung up unexpectedly # Or: fatal: git upload-pack: not our ref

# Check server configuration ssh git@github.com info # Look for shallow clone support

# If server blocks shallow, must use full clone git clone --depth=1000000 https://github.com/org/repo.git

# Or use mirror clone (faster for repeated use) git clone --mirror https://github.com/org/repo.git cd repo.git git config core.bare false git checkout main

# For CI/CD, cache the full clone # GitHub Actions with cache: - uses: actions/cache@v3 with: path: .git key: git-cache-${{ runner.os }}-${{ github.sha }}

  • uses: actions/checkout@v4
  • with:
  • fetch-depth: 0
  • `

GitLab server configuration:

```ruby # GitLab server admin can enable shallow clones # In /etc/gitlab/gitlab.rb gitlab_rails['git_enabled'] = true # Shallow clones enabled by default

# If disabled, users see: # fatal: GitLab: shallow clones are disabled

# Contact server admin or use full clone ```

### 5. Fix git describe on shallow clones

git describe requires tag history:

```bash # Error: fatal: No names found, cannot describe anything.

# Fetch tags with history git fetch --tags --depth=100

# Or unshallow first git fetch --unshallow git fetch --tags

# For CI/CD: - uses: actions/checkout@v4 with: fetch-depth: 0 # Required for git describe fetch-tags: true

# Alternative: Use commit hash for versioning VERSION=$(git rev-parse --short HEAD) echo "Version: $VERSION" ```

Semantic versioning without tags:

```bash # When tags aren't available, use alternative versioning # Option 1: Commit count + hash VERSION=$(git rev-list --count HEAD)-$(git rev-parse --short HEAD) echo "Version: $VERSION" # e.g., 1523-a1b2c3d

# Option 2: Date-based VERSION=$(date +%Y%m%d)-$(git rev-parse --short HEAD) echo "Version: $VERSION" # e.g., 20260401-a1b2c3d

# Option 3: Build number from CI VERSION=${{ github.run_number }} # GitHub Actions VERSION=$CI_PIPELINE_ID # GitLab CI ```

### 6. Handle submodule shallow clone issues

Submodules with shallow clones:

```bash # Error: fatal: reference is not a tree: <commit-hash>

# Submodules need their own fetch depth git submodule update --init --recursive --depth=1

# If submodule refs are not in shallow history: git fetch --unshallow git submodule update --init --recursive

# Or clone with full history for submodules git clone --recurse-submodules https://github.com/org/repo.git

# For CI/CD: - uses: actions/checkout@v4 with: fetch-depth: 0 submodules: recursive # fetch-depth: 1 with submodules often fails ```

Fix submodule reference issues:

```bash # Check submodule status git submodule status

# If shows - or + prefix, submodule needs update # - : Not initialized # + : Different commit than recorded

# Update to correct commit git submodule update --init

# If still fails, the referenced commit may not exist # Check submodule remote cd path/to/submodule git fetch origin git checkout <expected-commit>

# If commit doesn't exist, update submodule reference cd ../.. git submodule set-branch --branch main path/to/submodule git submodule update --remote git add path/to/submodule git commit -m "Update submodule reference" ```

### 7. Fix Git LFS with shallow clones

Git LFS objects may be missing:

```bash # Error: Git LFS: object not found

# LFS requires special handling with shallow clones git lfs fetch --all git lfs checkout

# Or disable LFS temporarily GIT_LFS_SKIP_SMUDGE=1 git clone https://github.com/org/repo.git cd repo git lfs fetch git lfs checkout

# For CI/CD: - uses: actions/checkout@v4 with: fetch-depth: 0 lfs: true # Enable LFS

# Or manually: - run: git lfs install - run: git lfs fetch --all - run: git lfs checkout ```

LFS troubleshooting:

```bash # Check LFS status git lfs status

# List LFS objects git lfs ls-files

# Verify LFS objects git lfs fsck

# If objects are corrupted git lfs fetch --all git lfs checkout --force ```

### 8. Handle monorepo shallow clone issues

Large monorepos need sparse checkout:

```bash # Clone specific directories only (Git 2.25+) git clone --filter=blob:none --sparse https://github.com/org/repo.git cd repo git sparse-checkout set path/to/component

# Or with shallow clone git clone --depth=1 --filter=blob:none --sparse https://github.com/org/repo.git cd repo git sparse-checkout set path/to/component

# For CI/CD (GitHub Actions): - uses: actions/checkout@v4 with: fetch-depth: 1 sparse-checkout: | apps/my-app packages/shared filter: blob:none ```

Sparse checkout troubleshooting:

```bash # Check sparse checkout configuration git sparse-checkout list

# Enable if not set git config core.sparseCheckout true

# Set directories git sparse-checkout set dir1 dir2 dir3

# Disable sparse checkout git sparse-checkout disable ```

### 9. CI/CD pipeline fixes

GitHub Actions:

```yaml # Problematic configuration (shallow clone) - uses: actions/checkout@v4 with: fetch-depth: 1 # May cause issues

# Fixed configuration - uses: actions/checkout@v4 with: fetch-depth: 0 # Full history # Or specify adequate depth # fetch-depth: 100

# For git operations that need history: - name: Get version with git describe run: | # Requires full history or adequate depth VERSION=$(git describe --tags --always --dirty) echo "VERSION=$VERSION" >> $GITHUB_ENV ```

GitLab CI:

```yaml # Default has GIT_DEPTH=50 # May need more for some operations

variables: GIT_DEPTH: 100 # Increase depth # Or full clone # GIT_DEPTH: 0

# For jobs needing full history build: variables: GIT_DEPTH: 0 script: - git describe --tags

# For jobs where shallow is fine lint: script: - npm run lint # Doesn't need history ```

Jenkins Pipeline:

```groovy // Shallow clone (may fail) checkout([$class: 'GitSCM', branches: [[name: '*/main']], extensions: [[$class: 'CloneOption', depth: 1]], userRemoteConfigs: [[url: 'https://github.com/org/repo.git']] ])

// Full clone (recommended) checkout([$class: 'GitSCM', branches: [[name: '*/main']], extensions: [[$class: 'CloneOption', depth: 0, noTags: false]], userRemoteConfigs: [[url: 'https://github.com/org/repo.git']] ])

// With WipeOutWorkspace for clean state checkout([$class: 'GitSCM', branches: [[name: '*/main']], doGenerateSubmoduleConfigurations: false, extensions: [ [$class: 'CloneOption', depth: 0, honorRefspec: true], [$class: 'WipeWorkspace'] ], submoduleCfg: [], userRemoteConfigs: [[url: 'https://github.com/org/repo.git']] ]) ```

### 10. Prevent shallow clone issues

Best practices for CI/CD:

```yaml # Use adequate fetch depth for your workflow # Depth requirements by operation:

# No history needed (depth=1 OK): # - npm install / yarn install # - Running tests (without coverage) # - Building artifacts

# Some history needed (depth=50+): # - git blame # - Finding changed files # - Commit-based versioning

# Full history needed (depth=0): # - git describe --tags # - Generating changelog # - Full test coverage with blame # - Semantic release

# Recommended GitHub Actions configuration - uses: actions/checkout@v4 with: fetch-depth: 50 # Good balance for most workflows fetch-tags: true # Always fetch tags ```

Repository server configuration:

```bash # GitLab: Ensure shallow clones allowed # Admin settings -> Network -> Git # Shallow clone: Enabled

# GitHub Enterprise: Check repository settings # Settings -> Actions -> General # Allow shallow clones: Yes

# Self-hosted Git servers (gitolite, gitea): # In config, ensure uploadpack.allowReachableSHA1InWant = true ```

Local development standardization:

```bash # Add to team documentation / README:

Git Clone Recommendations

For local development: ``bash git clone https://github.com/org/repo.git cd repo git submodule update --init --recursive

For CI/CD pipelines: - Use fetch-depth: 0 for release builds - Use fetch-depth: 50 for PR builds - Always fetch tags: fetch-tags: true ```

Prevention

  • Use fetch-depth: 0 for release/deployment pipelines
  • Use fetch-depth: 50+ for PR builds that need history
  • Always fetch tags when using git describe
  • Test shallow clone scenarios in staging CI/CD
  • Document depth requirements for team members
  • Use partial clone (--filter=blob:none) for large repos
  • Cache git directories in CI/CD to speed up full clones
  • Monitor CI/CD for shallow-related failures
  • Set up alerts for git operation failures
  • Standardize checkout configuration across pipelines
  • **fatal: not a git repository**: Directory not initialized
  • **fatal: Couldn't find remote ref**: Branch/tag doesn't exist
  • **fatal: Remote end hung up unexpectedly**: Network/server issue
  • **error: RPC failed; curl**: Large push/pull timeout
  • **fatal: Could not read from remote repository**: Authentication failure