Git Worktrees

Overview

A git worktree lets you check out more than one branch of the same repository at once, each in its own directory, while sharing a single .git history. You create one with:

git worktree add ../myproj-feature feature-branch

This is ideal for working on a feature branch without disturbing your main checkout – no stashing, no second clone, no duplicated git history.

IVPM makes worktrees even better: when you run ivpm update inside a linked worktree, it automatically reuses the already-materialized packages from your main worktree instead of re-cloning and re-downloading everything. Packages that your branch hasn’t changed resolve from local disk; only the packages your branch actually bumped are fetched.

Why Worktrees Need a Hand

IVPM’s deps-dir (packages/ by default) is almost always git-ignored – it holds fetched dependencies, not source you commit. So a freshly created worktree starts with no packages/ directory at all, even though ivpm.yaml is present (it is tracked).

A naive ivpm update in the new worktree would therefore re-resolve every dependency from scratch: cloning git repos, downloading archives, and rebuilding the Python virtual environment – often minutes of work – even though a complete packages/ for nearly the same dependency set already exists in the sibling main worktree.

IVPM closes this gap automatically.

Quickstart

cd ~/proj/myws                 # main workspace, already `ivpm update`-d
git worktree add ../myws-feature feature-branch
cd ../myws-feature
ivpm update

When ivpm update runs in the worktree, it prints:

git worktree detected: sourcing unchanged packages from main worktree (/home/you/proj/myws/packages)

Unchanged packages are linked from the main worktree’s packages/ instantly; anything your branch changed is fetched normally. No flags required.

How It Works

Detection

IVPM identifies a linked worktree using git’s own plumbing: in a linked worktree git rev-parse --git-dir differs from git rev-parse --git-common-dir (in the main worktree they are equal). The main worktree’s path is the first entry of git worktree list. See Git Integration for more on IVPM’s git handling.

Lock-Verified Reuse

Reuse is verified, not blind. For each package, IVPM resolves the identity your branch asks for (e.g. a git commit) and compares it against the main worktree’s package-lock.json:

  • Match – the package is unchanged on your branch, so packages/<pkg> is linked to the main worktree’s copy. No fetch.

  • No match – your branch pins a different version, so IVPM falls through to the shared cache / remote and fetches the correct version.

This is exactly the behavior you want from a worktree: reuse everything you didn’t touch, fetch what you did. See Deps-Source (“How Matching Works”) and Package Lock File for details.

Note

Worktree auto-detection always uses lock-verified matching. It never enables --trust-deps-source (trust-by-name), because that could silently link the main worktree’s version of a package your branch deliberately changed.

What Gets Shared

Lock-verified matching decides this per package, and it does the right thing for the worktree use case:

  • Cacheable packages (cache: true) are read-only mirrors – in either worktree they point into the same shared cache anyway, so linking is free and safe.

  • Editable packages (cache: false or cache omitted) are shared only when your branch resolves to the same version as the main worktree. If your branch pins a different commit/tag, the version won’t match and you get your own independent clone (see Working on Diverging Dependencies below).

Warning

When an editable package is shared, packages/<pkg> in the worktree is a symlink to the same on-disk clone as the main worktree – they share one working copy, one branch, one index. Edits and git operations on that package are visible in both worktrees. This is usually what you want for a dependency you are co-developing (a single source of truth). If you need an independent copy, use --deps-source-mode=copy, or pin the package to a different version on your branch so it falls through to its own clone.

Working on Diverging Dependencies

The headline benefit: create a worktree to try a dependency bump, and IVPM fetches only the changed package while reusing everything else.

git worktree add ../myws-bump main
cd ../myws-bump
# edit ivpm.yaml: bump `mylib` to a newer commit/tag
ivpm update
#   mylib        -> fetched fresh (branch pins a new commit)
#   everything else -> linked from the main worktree

Controlling the Behavior

Option

Effect

(default)

Auto-detect the parent worktree and reuse via lock-verified linking.

--no-worktree-deps-source

Disable auto-detection entirely; resolve as if standalone.

--deps-source PATH / IVPM_DEPS_SOURCE

Take precedence over auto-detection (auto only fills the gap).

--deps-source-mode=copy

Copy instead of symlink, for full physical isolation from the main tree.

Inspecting Provenance

ivpm status annotates packages that were reused from the main worktree with (auto: worktree) (versus (deps-source) for a user-supplied --deps-source):

✓  mylib                          (detached @ 9f3a1c2)  9f3a1c2  clean
~  somedata (auto: worktree)      (dir)

ivpm sync treats worktree-sourced packages as read-only mirrors and reports them SKIPPED – their source of truth is the main worktree, not upstream.

Lifecycle and Cleanup

Remove a worktree with git as usual:

git worktree remove ../myws-feature

The worktree’s packages/ entries are symlinks into the main tree (or independent copies under copy mode), so removing the worktree just deletes those links; the main worktree is untouched.

Warning

If you delete or move the main worktree while a linked worktree still references it, that worktree’s symlinks will dangle. Re-run ivpm update in the affected worktree to rematerialize (it will fetch fresh, or pick up a new main worktree if one exists).

Non-Git and CI

Note

This feature is purely opportunistic. In a directory that is not a git repository, or on a system where git is not installed, detection is a silent no-op – ivpm update behaves exactly as it always has, with no errors and no extra output. IVPM never requires git for its own operation; git is only needed to fetch git: packages.

Troubleshooting

Symptom

Likely cause / fix

Worktree re-fetched everything

The main worktree was never updated, has no package-lock.json, or your branch diverged on most packages. Run ivpm update in the main worktree first.

Want to disable reuse for one run

Pass --no-worktree-deps-source.

Need an independent copy of a reused package

Use --deps-source-mode=copy, or pin the package to a different version on your branch so it falls through to its own clone.

Edits to a reused package appeared in the main tree

Expected: a package whose version matched the main worktree is shared by symlink (one working copy for both trees). Use copy mode for isolation, or pin a different version on your branch.

See Also