skip to content

In Git, what does cloning with --depth 1 actually download, and what is missing?

level: juniorimportance: must knowfreq 72%

answer

  1. Think about how much of the graph arrives
  2. One branch, one commit, nothing older
  3. Git writes down where history stops
  4. A dotfile inside .git names the boundary
  5. --depth also implies --single-branch

basics

~20 s

git clone --depth 1 downloads only the tip commit of a single branch plus the trees and file contents needed to check it out. Older history and other branches are absent, so log and blame reach back one commit.

solid answer

~40 s

`git clone --depth 1 <url>` asks the server for a **shallow** clone: the tip commit of one branch, the trees and blobs needed to check it out, and nothing older. Git records the truncation boundary in `.git/shallow` and treats the commits listed there as if they had no parents, which is why `git log` shows a single entry. `--depth` also implies `--single-branch`, so only one branch is fetched and the `remote.origin.fetch` refspec written into `.git/config` is narrowed to it; `--branch <name>` picks which branch, and `--no-single-branch` asks for every branch's tip at that depth. It is the standard trick for CI jobs that only need to build the current tree, because it turns a multi-minute clone into seconds.

code

bash · 8 lines
bash
git clone --depth 1 https://example.com/big/repo.git
cd repo
git log --oneline
# 9f1c2ab (grafted, HEAD -> main, origin/main) Fix login redirect
cat .git/shallow
# 9f1c2ab3e0d5b7c8f2a1d4e6b9c0a3f5d7e8b1c2
git config --get remote.origin.fetch
# +refs/heads/main:refs/remotes/origin/main

go deeper

for a junior

Be ready to say what --depth 1 gives you: one commit on one branch, enough to build. Know that git log will show a single entry and that this is expected, not a broken clone.

for a middle

Explain the mechanics: the shallow boundary file, commits treated as parentless, and that --depth implies --single-branch and narrows the fetch refspec written into the config.

for a senior

Show judgment about which pipeline steps a shallow checkout breaks — tag-based versioning, merge-base diffs, blame — and how you would detect that failure mode before it reaches a release job.

for a principal

Own the policy: a default clone depth for the whole CI estate, with a documented escape hatch for jobs that legitimately need history, so teams do not each rediscover the breakage.

## What "shallow" means A normal clone copies the complete commit graph: every commit reachable from the remote's refs, plus all the trees (directory listings) and blobs (file contents) those commits reference. For a long-lived project that is often hundreds of megabytes of history nobody on the machine will ever read. `git clone --depth <n> <url>` asks the server to send only the last `<n>` commits of the branch being cloned, plus the objects needed to check that state out. The result is a **shallow repository**: an ordinary Git repository in every other respect, but with a deliberately truncated history. ## How Git records the truncation The file `.git/shallow` holds the commit IDs that sit on the boundary. Git treats each of those commits as if it had no parents, so history simply stops there. Nothing is corrupt and nothing is lying about content — the commits you do have are byte-for-byte the real ones, with their real IDs. Only the ancestry beyond the boundary is unavailable, because those objects were never transferred. This is why `git log --oneline` in a `--depth 1` clone prints exactly one line, and why `git log --graph` shows no ancestry. ## What --depth implies about branches `--depth` turns on `--single-branch` automatically. The practical consequences: - Only one branch is fetched — the one given with `--branch <name>`, or the remote's default branch if you did not say. - The `remote.origin.fetch` line in `.git/config` is narrowed to that single branch instead of the usual `+refs/heads/*:refs/remotes/origin/*`, so later `git fetch` calls keep fetching only that branch until you widen it. - Only tags that point into the history you received come along; `--no-tags` skips even those. If you want the tips of all branches but still no deep history, `git clone --depth 1 --no-single-branch <url>` does that. ## Variants of the depth request `--depth <n>` is a commit count, but Git can also truncate by other criteria: `--shallow-since=<date>` keeps commits newer than a date, and `--shallow-exclude=<ref>` keeps history that is not already reachable from the named ref or tag. All three produce the same kind of shallow repository with a `.git/shallow` boundary. ## What it costs Anything that needs ancestry degrades. `git log` and `git blame` stop at the boundary. `git describe` cannot find a tag if the tag is older than the boundary. `git merge-base` may not find a common ancestor with another branch, so merges, rebases and "diff against the target branch" style commands can fail or produce nonsense. `git bisect` can only search the commits present. A shallow clone is also not a substitute for a **partial clone**. Shallow truncates the *history* (fewer commits); a partial clone (`--filter=blob:none`) keeps the whole commit graph but omits *file contents* until something asks for them. They solve different problems and can be combined. ## When to use it Use `--depth 1` when the job only needs the current source tree: compiling, running a linter over the checkout, building a container image, publishing a static site. Avoid it when the job needs history: tag-derived version numbers, changed-file detection against a base branch, blame-driven ownership checks, or anything that merges or rebases. The shallowness is not permanent — `git fetch --unshallow` refills the history later, at the cost of the download you were trying to avoid.

  • Does --depth 1 also limit which branches you get?
    Yes. `--depth` implies `--single-branch`, so Git fetches only the branch you named with `--branch` (or the remote's default) and narrows `remote.origin.fetch` to it. Later fetches keep that narrow refspec. Pass `--no-single-branch` if you want every branch's tip at the same depth.
  • Can you commit and push from a shallow clone?
    Yes — recent Git allows both fetching and pushing from a shallow repository, and the client tells the server where its history stops. The risk is not the transport but the graph: new commits sit on top of a truncated ancestry, so anything needing a real merge base with an older branch can still misbehave.
  • What exactly is in .git/shallow?
    A list of commit IDs that Git treats as parentless. They form the boundary of the truncated history; `git log` renders them with the marker `grafted`. Deepening or unshallowing rewrites this file as more ancestry arrives.

It is like buying only the latest issue of a magazine instead of the bound archive: the issue is genuine and complete, but you cannot look up what happened three years ago.

saying these in an interview costs you the question

  • Thinks --depth 1 only drops old file versions, keeping commits
  • Says a shallow clone repairs its own history over time
  • Assumes --depth 1 still fetches every branch
  • Believes git log is just faster, not truncated
  • Uses shallow and partial clone as synonyms

context