GitShallow & Partial Clones

Shallow Clone

A shallow clone is a repository clone that contains only a limited portion of the commit history rather than the full graph going back to the very first commit. Git truncates the history at a specified depth and marks those boundary commits as grafts. The result is a fully functional working repository — you can build, test, and commit — using a fraction of the disk space and download time of a full clone. For CI/CD pipelines that run hundreds of times per day, shallow clones are an enormous practical improvement.

Clone with Depth 1 (Most Common)

Depth 1 means download only the most recent commit on the requested branch. This is the absolute fastest way to get code onto a machine and is the default in most CI systems.

Clone with only the latest commit

Bash
git clone --depth=1 https://github.com/org/large-repo.git
cd large-repo

# Only one commit in history
git log --oneline
# a3f1c2d (HEAD -> main, origin/main) Add authentication module

# Confirm it is shallow
git rev-parse --is-shallow-repository
# true

Size comparison (a real web app repository)

Text
Full clone:              500 MB    30 seconds
Shallow --depth=1:        12 MB     2 seconds

GitHub Actions pipeline improvement:
  Without shallow clone:  45s checkout
  With --depth=1:          4s checkout  (~89% faster)
Clone with N Commits of History

A depth greater than 1 is useful when you need git log to show recent changes, generate changelogs, detect which packages changed between commits, or run release tools like semantic-release that inspect commit messages.

Clone with the last 10 commits

Bash
git clone --depth=10 https://github.com/org/repo.git
cd repo

git log --oneline
# Shows 10 commits
Shallow Clone Since a Date

Clone only commits after a specific date

Bash
# All commits since January 1, 2023
git clone --shallow-since="2023-01-01" https://github.com/org/repo.git

# Using a relative time expression
git clone --shallow-since="6 months ago" https://github.com/org/repo.git
Exclude Commits Reachable from a Tag

Shallow clone excluding commits before v1.0

Bash
git clone --shallow-exclude=v1.0 https://github.com/org/repo.git
# Downloads all commits after v1.0 was tagged
Single-Branch Shallow Clone (Fastest CI Setup)

Combine shallow with single-branch for maximum speed

Bash
git clone   --depth=1   --branch=main   --single-branch   https://github.com/org/repo.git

# --single-branch: do not fetch any other branches
# --branch=main:   fetch only this branch
# --depth=1:       only the most recent commit
What the Shallow Boundary Looks Like

ASCII diagram: full history vs shallow clone

Text
Full history:
  A --- B --- C --- D --- E --- F --- G  (HEAD)

Shallow clone with --depth=3:
                      E --- F --- G  (HEAD)
                      ^
               shallow graft point
               (Git pretends E has no parents)

.git/shallow file:
  <hash of E>   ← marks the truncation boundary

Inspect the shallow boundary file

Bash
cat .git/shallow
# e9f0a1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6e7f8

# Check if the repo is shallow
git rev-parse --is-shallow-repository
# true
Inspecting History in a Shallow Clone

git log in a shallow clone

Bash
git log --oneline
# a3f1c2d (HEAD -> main, origin/main) Add auth module   ← depth=1, only this

git log --oneline --graph
# * a3f1c2d (HEAD -> main, origin/main) Add auth module

# Trying to go deeper shows nothing
git log --oneline main~5
# fatal: ambiguous argument 'main~5': unknown revision
Deepening an Existing Shallow Clone

After cloning with a small depth, you can fetch more history without re-cloning from scratch. This is more efficient when you realise mid-pipeline that you need a few more commits.

Fetch more history into a shallow clone

Bash
# Add 20 more commits to the history
git fetch --deepen=20

# Now you have 21 commits visible (original 1 + 20 more)
git log --oneline | wc -l
# 21

# Deepen until you reach a specific commit
git fetch --shallow-exclude=abc1234
Unshallowing a Clone

To convert a shallow clone into a full clone with complete history, fetch --unshallow downloads all the missing history from the remote.

Convert shallow clone to full clone

Bash
git fetch --unshallow

# Equivalent using pull
git pull --unshallow
Warning
git fetch --unshallow on a large repository with years of history can take 30+ minutes and download gigabytes of data. Only do this if you genuinely need the full history. Consider whether a targeted git fetch --deepen=N is sufficient for your use case instead.
Limitations of Shallow Clones
  • git log shows incomplete history — commits before the graft point are invisible

  • git blame may be cut off — cannot trace lines beyond the shallow boundary

  • git bisect is limited — binary search only works within the visible commit range

  • git describe may give wrong results — the nearest tag might be hidden by the shallow cut

  • Some merge strategies fail — merge-base calculations can break if the common ancestor is beyond the boundary

  • Submodule operations may fail — if submodule commits fall below the shallow boundary

Shallow Clone in CI/CD Systems

GitHub Actions: controlling fetch depth

YAML
# .github/workflows/ci.yml
- uses: actions/checkout@v4
  with:
    fetch-depth: 1   # default: shallow clone, fastest

# For semantic-release, changelogs, or affected-packages detection:
- uses: actions/checkout@v4
  with:
    fetch-depth: 0   # full history (0 = unshallow)

GitLab CI: controlling clone depth

YAML
# .gitlab-ci.yml
variables:
  GIT_DEPTH: 1        # shallow — last commit only
  # GIT_DEPTH: 0      # full history
  # GIT_DEPTH: 20     # last 20 commits
Partial Clone: A More Advanced Alternative

Git 2.22+ supports partial clones, which are related to but different from shallow clones. A partial clone downloads full commit history but defers downloading large file contents (blobs) until they are actually checked out. This is ideal when you need full history for git operations but want to avoid downloading large binary assets upfront.

Partial clone variants

Bash
# Blobless: full history, fetch blobs on demand
git clone --filter=blob:none https://github.com/org/repo.git

# Treeless: full history, fetch trees and blobs on demand
git clone --filter=tree:0 https://github.com/org/repo.git
Comparison Table

Feature

Full Clone

Shallow Clone (--depth=1)

Partial Clone (--filter=blob:none)

Download size

Largest

Smallest

Medium

Full commit history

Yes

No — truncated

Yes

git blame (full)

Yes

Limited

Yes

git bisect (full)

Yes

Limited

Yes

git describe accuracy

Yes

May be wrong

Yes

Blobs downloaded upfront

All

Only for shallow commits

No — on demand

Best for

Development, code review

CI builds, read-only runs

CI needing git ops

Server requirement

Any Git server

Any Git server

Git 2.22+ server

Tip
For most CI pipelines, --depth=1 --single-branch is the optimal choice. For monorepos where you need to detect which packages changed across commits, --depth=20 or --shallow-since='1 week ago' gives enough history for change detection without downloading the full project history.