Environment isolation

Two branches. Two apps.
Zero conflicts.

Not containers — separate ports, databases, Redis namespaces, and env files for every worktree. Declare what your project needs once in .treeline.yml and a git hook installed by gtl install allocates resources on every checkout.

The second worktree is always broken

You run git worktree add and get a second checkout in seconds. Then you try to start it.

~/worktrees/feature-b

$ npm run dev

Error: listen EADDRINUSE :::3000

$ rails db:create

Database 'myapp_development' already exists

$ cat .env.local

PORT=3000

DATABASE_URL=postgres:///myapp_development

# Same as every other worktree.

Port collisions. Database conflicts. Shared env files. The checkout is fresh — everything around it is not.

One command changes everything

gtl new feature-auth

Creating worktree feature-auth

Allocated port 3010

Extra port 3011

Cloned database myapp_dev_feature_auth

Assigned Redis namespace myapp:feature-auth

Wrote .env.local

Copied config/master.key

Running setup commands…

Ready. cd ~/worktrees/feature-auth

The worktree has its own port, its own database (cloned with data), its own env file with interpolated values, and secrets copied from main. Boot immediately.

What this makes possible

Isolation is the contract: ports, databases, env, and cross-repo URLs are deterministic per worktree. Once .treeline.yml describes your app, gtl new and gtl setup apply the same rules everywhere—no manual editing after every branch switch.

Run several branches at full fidelity

Main, a feature branch, and a PR review can run side by side with different ports and databases. You switch browser tabs—or editor windows with distinct title-bar colors—not terminal sessions, and you are not sharing one .env.local between checkouts.

Onboarding tracks the repo, not a wiki

New developers clone the repo and run gtl setup in a worktree. Database clone, env interpolation, commands.setup, and hooks run in a predictable order—no one-off “change these three env vars” instructions that drift from reality.

Agents and automation get a real sandbox

A worktree created for an agent or script gets the same allocation rules as yours: isolated DB, env, and supervisor-controlled start/stop. Teardown via gtl release frees resources when the branch is done—see AI Agents for MCP and JSON surfaces.

Declare it once. Git Treeline handles the rest.

Everything is driven by .treeline.yml at the root of your project. The excerpt below is representative: ports and database, env seeding, commands.setup / commands.start, lifecycle hooks (the same four keys the CLI implements), and editor chrome.

.treeline.yml
project: myapp
port_count: 2

# Database
database:
  adapter: postgresql
  template: myapp_dev

# Environment
env_file: .env.local
copy_files:
  - config/master.key

# Commands + hooks (order matches runtime)
commands:
  setup:
    - bin/setup
  start: bin/dev

hooks:
  pre_setup:
    - bin/check-toolchain
  post_setup:
    - bin/warm-cache
  pre_release:
    - bin/confirm-safe-to-drop
  post_release:
    - bin/notify-teardown

# Editor
editor:
  color: auto

Ports

Every worktree gets a unique port automatically. port_count: 2 reserves sequential ports for multi-process apps (Vite + API, for example). Allocated ports are written to your env file via {port} tokens and available as $PORT in setup/start commands.

Database

database.adapter picks the cloning strategy. PostgreSQL uses createdb --template for instant clones with seed data. SQLite is file-copied. Manage with gtl db reset, gtl db restore, or gtl db reset --from <source>.

Environment

Your env file is interpolated with allocated values — {port}, {database}, {redis_url}. Secrets like master.key are copied from your main worktree via copy_files.

Editor

editor.color: auto gives each worktree a deterministic title bar color so you always know which branch you're looking at. Works in VS Code, Cursor, Zed, and JetBrains. Override with a hex value or set editor.theme for full theme switching.

Setup commands

commands.setup runs after allocation, env write, and database clone. $PORT and interpolated values are available. commands.start is what gtl start and gtl review … --start execute via the supervisor.

Lifecycle hooks

hooks.pre_setup and hooks.post_setup wrap commands.setup; hooks.pre_release and hooks.post_release wrap freeing ports and dropping databases on gtl release. Pre-hooks abort the operation on non-zero exit; post-hooks warn and continue. Full ordering and examples: Hooks guide.

main
feature-auth
pr-42

Each worktree gets a distinct color. Know which branch you're in at a glance.

Multiple repositories, one machine

Your web app and your API are different clones. Hardcoding localhost:3030 in the frontend env file breaks as soon as Git Treeline re-allocates the API. The registry already knows every project’s port—you need a way to reference it by name.

gtl resolve and {resolve:…}

gtl resolve api prints the base URL for project api on the same branch name as your current worktree—no extra config when both repos track feature-auth. In .treeline.yml, API_URL: "{resolve:api}" resolves at setup time. Use {resolve:api/main} to pin a branch explicitly.

If the frontend branch does not match the API branch you need, gtl link api staging stores an override, regenerates the env file, and restarts the server automatically (visible in gtl status and gtl doctor). gtl unlink api clears it. Setup fails with a clear error if the target is not allocated.

web repo

$ gtl resolve api --json

# scripting / agents

env:

API_URL: "{resolve:api}"

Scenario: frontend + API

Add isolation to your project

One file, committed to your repo. Teammates without gtl installed are unaffected—the config file has no effect on builds or deployments.

gtl install

Auto-detects your framework, creates .treeline.yml, allocates ports, and writes env — all in one step.

Full configuration reference →