By admin , 28 April 2026

Introduction

A shallow clone downloads only the most recent N commits of a branch instead of the full history. The result is much smaller and faster to fetch, at the cost of an incomplete history.

Creating

git clone --depth 1 https://github.com/example/widget.git
git clone --depth 50 https://github.com/example/widget.git
git clone --depth 1 --branch v1.2.3 --single-branch <url>

The .git directory contains a shallow file listing commits whose parents have been omitted.

Why shallow

  • CI builds: only need source for HEAD.
  • Containers and Dockerfiles: smaller images.
  • One-shot tooling that does not need history.

Limitations

  • You cannot push from a shallow clone if your push depends on commits the server does not have (rare, but possible).
  • git log stops at the shallow boundary.
  • Some operations (rebase across the boundary, blame on old lines) cannot work.
  • Until Git 2.11 cloning shallow over HTTP was unsupported; modern Git handles it.

Deepening and unshallowing

git fetch --depth 100              # extend depth
git fetch --deepen 50              # add 50 more commits
git fetch --shallow-since=2024-01-01
git fetch --unshallow              # download full history

After --unshallow the repo behaves like a normal clone.

Single-branch and shallow

--single-branch + --depth 1 is the smallest possible useful clone. To later track other branches:

git remote set-branches --add origin main feature
git fetch origin

Partial clones (a different optimization)

If you need full history but not all blobs, use a partial clone instead:

git clone --filter=blob:none <url>
git clone --filter=tree:0 <url>

Partial clones download history but defer blobs (or trees) until needed. They are usually a better choice than shallow when the server supports them.

Detecting shallow state

git rev-parse --is-shallow-repository
cat .git/shallow

CI patterns

Many CI providers default to shallow clones (depth 1 or 50). If your build runs git describe or needs blame across versions, request a full clone:

# GitHub Actions
- uses: actions/checkout@v4
  with:
    fetch-depth: 0

Shallow files and grafts

The shallow file in .git/ lists commit SHAs whose parents are intentionally missing. Git treats them as roots during graph traversal. The related but deprecated info/grafts mechanism let you fake parent relationships; use git replace --graft instead, which is safer and replicates over fetch:

cat .git/shallow
git replace --graft <commit> <new-parent>
git replace -l
git replace -d <commit>

This is occasionally useful for stitching together imported histories without rewriting commits.

Common mistakes

Running git describe in a depth-1 clone and getting an error because no annotated tag is reachable; either fetch tags (--tags) or use a deeper clone. Trying to rebase a feature branch in a shallow clone where the merge base is beyond the shallow boundary; deepen first. Pushing from a shallow clone and being surprised by "remote rejected"; the server may need missing parent objects. Finally, treating shallow clones as a substitute for partial clones; they solve different problems and partial is usually friendlier.