Git Forest
A VS Code extension for working on several branches of the same repository at
the same time — each in its own VS Code window, running side by side. No
stashing, no switching back and forth, no waiting for one task to finish
before starting another.
It's built on git worktree: a
worktree is a separate folder checked out to its own branch, but all worktrees
share one underlying .git history. Open each folder in its own window and
the windows are fully independent — you can run a dev server on main in one
while rebasing feature-x in another.
Personal/local-use extension. Not published to the Marketplace.
Quick start
- Install the extension (see Installing below).
- Open a git repository in VS Code.
- Click the Git Forest icon in the activity bar.
- Hit + in the Worktrees view to create a worktree, and choose
Open in New Window when it offers.
If you work on Node projects, set these two first — they're what make a new
worktree usable the moment it's created:
"gitForest.copyOnCreate": [".env", ".env.local"],
"gitForest.postCreateCommand": "npm install"
The Worktrees view
Lists every worktree for the repository open in the current window. The one
open in this window is marked with a filled dot. Each entry is annotated
with its current state:
| Badge |
Meaning |
● |
Has uncommitted changes (including untracked files) |
↑2 |
2 commits ahead of its upstream |
↓1 |
1 commit behind its upstream |
(locked) |
Locked via git worktree lock |
(missing) |
The folder no longer exists on disk — prunable |
Ahead/behind only appears when the branch has an upstream configured.
The view auto-refreshes: it watches the repository's shared .git
directory, so it updates when another window — or a plain terminal — adds a
worktree, commits, or switches branch. It also refreshes whenever the window
regains focus. Disable with gitForest.autoRefresh.
Commands
All available from the Command Palette under Git Forest: …, and
from the view's title bar / right-click menus.
| Command |
What it does |
| New Worktree… |
Create a worktree for a branch (see below) |
| Open in New Window |
Open a worktree's folder in a new VS Code window |
| Merge Into… |
Merge one worktree's branch into another's, without switching windows |
| Remove Worktree… |
Delete a worktree's folder and its git registration |
| Lock Worktree / Unlock Worktree |
Protect a worktree from pruning/removal |
| Prune Stale Worktrees |
Clear bookkeeping for worktrees whose folders were deleted outside git |
| Refresh |
Re-read worktree state manually |
| Toggle Pet Animation / Next Pet |
Controls for the pet panel |
New Worktree…
Runs git worktree add for you, then offers to open the result. You can pick:
- an existing local branch;
- a remote branch (e.g.
origin/feature-x) that has no local counterpart
yet — this creates the local branch tracking it, so ahead/behind works
straight away;
- or create a new branch, choosing what to base it on:
HEAD, any local
branch, or any remote branch — rather than always branching from wherever
the current window happens to be sitting.
Branches already checked out in another worktree are flagged, since git won't
allow the same branch in two worktrees at once.
Merge Into…
Merges one worktree's branch into whatever branch another worktree currently
has checked out — e.g. bring feature-x into main, or pull main into
feature-x to catch it up — without switching windows yourself. The merge
runs with the target worktree as its working directory, so it lands there;
if that worktree is open in another window, that window picks up the change
like any other external edit.
It warns first if the target has uncommitted changes, and on a conflict it
tells you exactly which worktree to open to resolve it.
Remove Worktree…
Confirms first, then runs git worktree remove. If the worktree has
uncommitted changes git refuses, and you're offered an explicit force-remove.
Removing the worktree open in the current window is blocked outright.
Automatic setup for new worktrees
A freshly created worktree contains only git-tracked files. Everything
gitignored — .env files, node_modules, build caches — is missing, which is
usually what stops a new worktree from being immediately runnable.
Three opt-in settings close that gap:
copyOnCreate — copies files/folders from your current worktree into
the new one. Best for .env files.
linkOnCreate — links folders instead of copying. Much faster than
reinstalling for node_modules.
postCreateCommand — runs a command in a terminal opened at the new
worktree, e.g. npm install.
Nothing is copied or linked unless you configure it; the defaults are empty.
Tradeoff on linkOnCreate: ["node_modules"]: a link means both
worktrees share the same folder, so two branches with different
dependency versions will overwrite each other's packages. Use it when your
branches have matching dependencies; prefer postCreateCommand with
npm install when they don't.
On Windows, linked directories are created as junctions, which do not
require Developer Mode or an elevated terminal.
Entries are skipped with a notice — not an error — when they don't exist in
the source worktree or already exist in the new one. Existing files are never
overwritten, and any entry that would resolve outside the worktree is refused.
Settings
All under gitForest.* (Settings UI → search "Git Forest").
| Setting |
Default |
What it does |
worktreeLocation |
../{repo}-{branch} |
Default folder for new worktrees. {repo} and {branch} are substituted; relative paths resolve against the repo root. |
copyOnCreate |
[] |
Files/folders copied into each new worktree, e.g. [".env", ".env.local"] |
linkOnCreate |
[] |
Folders linked into each new worktree instead of copied, e.g. ["node_modules"] |
postCreateCommand |
"" |
Command run in a terminal at the new worktree, e.g. npm install |
autoRefresh |
true |
Watch .git and refresh on external changes / window focus |
showDirtyIndicator |
true |
Show ● for worktrees with uncommitted changes |
showAheadBehind |
true |
Show ↑/↓ counts against the upstream |
Keeping worktrees tidy
By default new worktrees land beside the repo, which scatters them through
your projects folder. To group them instead:
"gitForest.worktreeLocation": "../worktrees/{repo}-{branch}"
Absolute paths work too. {branch} has path-illegal characters replaced, so
feature/login becomes feature-login.
Pet panel
A small, purely-for-fun panel below the Worktrees view. It has no connection
to your git data — it's decoration.
It plays a Lottie animation from resources/,
filling the panel with no border around it, anchored to the bottom edge.
Ships with three: Looking Around (cat), Playing with Ball (cat), and
Flying Panda.
- Pet — a checkbox multi-select for which pets are in the rotation. At
least one stays checked.
- Loop (⟲) — when on, each pet advances to the next checked one after
finishing a full animation loop, cycling through your selection. When off,
the current pet just keeps looping in place.
- Speed — Slow / Normal / Fast. Starts on Slow until you change it.
- Play/pause and next pet are icon buttons in the panel's title bar.
- Clicking the pet gives it a brief speed-burst reaction with a speech bubble.
Selection, loop, on/off, speed, and which pet is showing all persist across
windows and restarts.
To add a pet: drop a Lottie .json export into resources/ and add one
{ id, label, file } entry to the PETS array at the top of
src/petsView.ts.
Requirements
- Git 2.5+ on
PATH (when git worktree was introduced).
- A folder open in VS Code that is, or is inside, a git repository.
Installing (as a .vsix)
A pre-built git-forest-0.0.1.vsix sits in this folder:
- Extensions view (
Ctrl+Shift+X)
… menu → Install from VSIX…
- Pick
git-forest-0.0.1.vsix
VS Code does not auto-update an extension installed from a .vsix.
After rebuilding, install the new file again to pick up changes.
Notes and limitations
- One repo at a time. Only the git repository in the first workspace
folder of the window is managed — there's no multi-root repo picker yet.
- Ahead/behind reflects your last fetch. These counts compare against the
branch's configured upstream; the extension never fetches on its own, so
↓0 can just mean nothing new has been fetched.
- Dirty markers for other worktrees aren't live. Auto-refresh watches
worktree bookkeeping, branch tips, and
HEAD — not every file in every
working tree. The ● on another worktree updates on the next refresh
(window focus, any git operation, or the Refresh button) rather than the
instant someone types in it.
- Merge Into… is a plain
git merge — no rebase option, and it only
targets branches currently checked out in one of your worktrees. It won't
touch a branch nobody has open.
- [Inference] Worktree paths with unusual characters, or very long paths on
Windows, haven't been specifically tested; straightforward folder paths are
the safe bet.
- The pet panel vendors lottie-web
(
resources/lottie.min.js, MIT — see resources/lottie-web-LICENSE.md) as
a local file so it works fully offline. It isn't an npm dependency of the
extension itself.