skip to content

questions

5

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

open as a page

How does a Git partial clone with --filter=blob:none differ from a shallow clone?

level: middleimportance: should knowfreq 42%

basics

~20 s

A shallow clone truncates history to a few commits. A partial clone with --filter=blob:none keeps the entire commit and tree graph but omits file contents, downloading each blob lazily from the remote the first time something actually needs it.

open as a page

Which Git operations break in a shallow clone, and how do you restore the full history?

level: middleimportance: should knowfreq 52%

basics

~20 s

Anything needing ancestry degrades in a shallow clone: log, blame, describe, bisect and merge-base against a long-diverged branch. Run git fetch --unshallow to download the missing history, or git fetch --deepen=N to extend it gradually.

open as a page

What does Git's sparse-checkout cone mode do, and how does it pair with a partial clone?

level: seniorimportance: should knowfreq 28%

basics

~20 s

git sparse-checkout limits which directories are materialized in the working tree, marking the rest skip-worktree in the index. Cone mode restricts patterns to whole directory prefixes so matching stays fast. It shrinks the checkout, not the download; a partial clone shrinks the download.

open as a page

For CI on a multi-gigabyte Git repository, how do you choose between shallow, partial, and full clones?

level: principalimportance: should knowfreq 34%

basics

~20 s

Start from what each job needs from history, not from clone speed. Build-only jobs take a shallow single-branch clone; jobs needing tags, blame or merge-base take a partial clone; jobs needing both take a full clone warmed from a local mirror or cache.

open as a page