Worktrees, sparse checkout, shallow and partial clone
Expert Git CLI
Why this matters
Four tools for two annoyances: switching branches constantly to review someone's work, and a repository so large that a full clone or checkout is painful. None is needed on a small project, and each one saves real time on a large one.
Worktrees: two branches at once
A worktree is a second working directory attached to the same repository. Both share one .git, so all the commits, branches and objects are common, and each has its own checked-out branch.
$ git worktree add ../trailguide-review HEAD~1Preparing worktree (detached HEAD b81702c)
HEAD is now at b81702c docs: add getting started guide and FAQ$ git worktree list/Users/you/dev/trailguide d3b92ec [main]
/Users/you/dev/trailguide-review b81702c (detached HEAD)
Now ~/dev/trailguide-review is a full working copy of that commit, and your original directory is untouched. Editors can open both at once.
| Use it for | Instead of |
|---|---|
| Reviewing a colleague's branch while yours stays open | Stashing and switching |
| A long build in one directory while you edit in another | Waiting |
| Comparing two versions side by side in an editor | Two clones |
$ git worktree add ../trailguide-hotfix -b hotfix/23 v1.2.0
$ git worktree remove ../trailguide-reviewTwo rules: one branch can be checked out in only one worktree at a time, and removing the directory by hand leaves a stale entry, cleaned up with git worktree prune.
Worktrees are much lighter than a second clone: no second copy of the history, and no second remote to keep in sync.
Sparse checkout: part of a repository
In a monorepo, you may need docs/ and nothing else (lesson 13.10). Sparse checkout puts only what you name in your working directory, while the repository still contains everything.
$ git sparse-checkout set docs
$ git sparse-checkout listdocsOne thing to expect: the top level is always kept. After set docs the other folders are gone from disk and the project's root files are still there, because that is how the default cone mode works.
$ git sparse-checkout disableCommits still cover the whole project, and a merge still merges everything; only the files on disk are limited. That distinction matters: sparse checkout is a working-directory feature, not a permissions feature, and it hides nothing from anyone.
Combine it with git clone --filter=blob:none for a large repository, and the clone fetches content only for the paths you check out.
Shallow clone
$ git clone --depth 1 <url>Fetches only the most recent commit. The clone is fast and small, and the trade is real:
| Works | Does not |
|---|---|
| Building, running, reading current files | git log beyond the fetched depth |
| Making commits and pushing | git blame for older lines |
| Ordinary branch work, mostly | Merging with a base outside the fetched history |
Shallow clones belong in throwaway environments, mainly CI, where speed matters and history does not. git fetch --unshallow converts one back into a full clone.
Partial clone
$ git clone --filter=blob:none <url>Fetches all the commits and trees but no file contents until something needs them. The history is complete, so git log works everywhere; the first git blame or checkout of an old commit fetches what it needs on demand.
For a large repository this is usually the better of the two: --depth truncates history, --filter merely defers content. It needs a server that supports it, which both platforms do.
| Option | Fetches | Keeps working |
|---|---|---|
--depth 1 |
One commit's history and content | Only recent history |
--filter=blob:none |
All history, content on demand | Everything, with occasional pauses |
--filter=tree:0 |
Even less, for automation | Only with care |
How to do it
$ git worktree add ../review <branch>
$ git worktree list
$ git worktree remove ../review
$ git sparse-checkout set docs src
$ git clone --filter=blob:none <url>
$ git fetch --unshallowA worktree is an ordinary folder, so File → Open Folder on it works and gives you two windows on the same repository. VS Code has no sparse-checkout interface; set it in the terminal and the Explorer follows.
The same: open the worktree as a project. IntelliJ handles multiple roots, and the worktree level of configuration exists for exactly this case (lesson 18.2).
Nothing platform-specific. Large-repository features that do concern the platform are LFS and the repository size limits (lesson 18.9).
The same; GitHub's servers support partial clone filters.
Common mistakes
- Checking out the same branch in two worktrees. Git refuses; use a detached checkout or a different branch.
- Deleting a worktree folder by hand, leaving a stale entry until
git worktree prune. - Using
--depth 1for daily work, then findinggit blameand old history unavailable. - Expecting sparse checkout to hide files from others. It is local, and a merge still merges everything.
- Forgetting a worktree exists, and wondering why a branch is "already checked out".
Try it yourself
Goal: review a branch without disturbing your own work.
- In your practice repository, leave an uncommitted change in place.
- Run
git worktree add ../practice-review HEAD~1and open that folder in your editor. - Confirm your original folder still has the uncommitted change and its own branch.
- Run
git worktree listand read both entries. - Remove the worktree with
git worktree remove ../practice-review, then trygit sparse-checkout set docsandlistbefore disabling it.
Expected result: two working directories on one repository, your unfinished work untouched, and a sparse checkout tried and reversed.
Show solution
Step 3 is the point. Everything a stash-and-switch does to your working directory, a worktree avoids entirely, because the second checkout is somewhere else. Once you have used it for a review, the "stash, switch, look, switch back, pop" routine starts to feel unnecessary.