Worktree
每个 git worktree 一个环境:拥有自己的域名、端口、.env 和数据库,让多个分支(或多个编程智能体)并行运行。
git worktree 是仓库的第二份工作副本,位于另一个分支、另一个文件夹中。Joppa 把它变成一个 环境:同一个应用,拥有自己的域名、自己的端口、自己的 .env,如果你愿意,还可以有自己的数据库。你可以让 main 保持在线,同时让一个分支(或 Claude Code 这样的智能体)在旁边工作,不会有端口或数据冲突。
项目的 Worktree 标签页(W)列出它的 worktree。项目文件夹是 git 仓库时才会显示该标签页。

worktree 会得到什么
域名
分支名会成为域名中的一级标签:feature/Login UI 变为 feature-login-ui(游离的 worktree 使用其文件夹名)。
| 项目域名 | worktree 域名 |
|---|---|
myproject.test |
feature-login-ui.myproject.test |
app.myproject.test |
app.feature-login-ui.myproject.test |
如果这个名称已被占用(例如分支 api,而项目已有 api.myproject.test),Joppa 会加上编号:api-2。证书会自动覆盖这些域名,无需任何操作。只有指向项目开发服务器的域名才会被沿用。
端口
每个开发服务器都会获得自己的端口:项目的端口 + 100、+ 200……(5173 → 5273),否则使用 41000 到 49999 之间的空闲端口。绝不会使用其他项目的端口,也不会使用已被占用的端口。
Joppa 会以服务器能理解的方式把端口传给它:
- Joppa 本来就会赋值的变量(脚本中的
${PORT:-3000},php artisan serve的SERVER_PORT,Reverb 的REVERB_SERVER_PORT); - 服务器读取的变量(代码中的
API_PORT,.env中的PORT); - 脚本中写明的端口(
vite --port 5173),会被改写; - 对 Vite、Astro、Next.js、Nuxt、Angular、Wrangler、Storybook、Vue CLI、Docusaurus、Gatsby、VitePress 和 Expo 使用
--port(同时设置PORT);对 Create React App 使用PORT。
如果服务器的端口只写死在代码里、没有变量,就无法迁移:Joppa 会把它从「全部启动」中取消勾选,并提示你。
如果服务器从带默认值的变量中读取另一个服务器的地址(process.env.API_URL ?? "http://localhost:47400"),它会收到新的地址:worktree 的前端与 worktree 的 API 通信,而不是项目的 API。
Docker Compose 服务仍属于项目:worktree 直接使用它们,不会启动第二份副本(它们的端口是固定的)。
.env
git 不会复制它忽略的文件。Joppa 会把 worktree 缺少的这些文件复制进去:.env、.env.local、.env.development、.env.development.local、.dev.vars(Wrangler)和 .php.ini,以及未提交的版本固定文件(.php-version、.node-version、.nvmrc、.tool-versions),包括根目录和每个开发服务器的文件夹。其中的地址会被替换:localhost:5173 → localhost:5273,VITE_PORT=5173 → 5273,https://app.myproject.test → https://app.feature-login-ui.myproject.test。
数据库
对于项目在 Joppa 服务 中使用的每个数据库:
| 选项 | Joppa 的操作 |
|---|---|
| 复制项目的数据库(默认) | 以项目的数据库为基础创建 myproject_feature_login_ui:PostgreSQL 使用 TEMPLATE(瞬间完成),否则通过 dump 复制(正被运行中的服务器使用的 PostgreSQL、MySQL、MariaDB) |
| 空数据库 | 创建一个空数据库;对于 Laravel,如果在准备过程中安装了依赖,会运行 php artisan migrate |
| 使用项目的数据库 | worktree 与项目使用同一个数据库 |
worktree 的 .env 会写入其数据库的名称。Redis、Valkey、Mailpit 和搜索引擎与项目共用。
SQLite 数据库(DB_CONNECTION=sqlite 的 Laravel,或 file: 形式的 DATABASE_URL,包括 Prisma 的)遵循同样的选择:复制该文件、创建一个空文件(若依赖已安装,Laravel 随后会运行迁移),或让 worktree 的 .env 指向项目的文件。git 会忽略这些文件:否则 worktree 将没有数据库。
进程
worktree 的 进程 与项目相同,但使用它自己的端口,Laravel worker 也包括在内:Reverb 通过 REVERB_SERVER_PORT 获得端口,复制过来的 .env 中的 REVERB_PORT 也随之更新。当 Laravel 队列经由 Redis 时(Horizon,或 QUEUE_CONNECTION=redis),worktree 的 php artisan 进程会获得自己的 REDIS_PREFIX 和 HORIZON_PREFIX(myproject_database_feature_login_ui_):它的 worker 绝不会取走项目的 job。Xdebug 沿用项目的设置。它们保存在 Joppa 的配置中,而不是 joppa.toml 中。保存项目的进程时,其 worktree 的进程会随之更新(新进程会获得自己的端口);从 myproject 更新 可随时手动执行。
它的开发服务器在 15 分钟没有请求后会进入休眠,并在下一个请求时被唤醒:几十个 worktree 可以同时保持打开,而不必各自把服务器常驻内存。
准备 worktree
在 Worktree 标签页中,对「未准备」的 worktree 点击 准备。选择它的数据库,然后按需勾选:
- 安装依赖:没有
node_modules时运行bun install(或项目的包管理器),没有vendor时运行composer install; - 启动进程:准备就绪后启动。
准备过程的日志会显示出来;打开 进入该环境。
创建 worktree
新建 worktree 会执行 git worktree add,然后准备环境:
- 新分支(基于当前提交或另一个分支),或 已有分支;
- 文件夹创建在仓库旁边:
myproject-worktrees/<分支>。
在别处创建的 worktree
开启 自动准备新的 worktree(默认开启)后,Joppa 每 3 秒检查一次项目的 worktree,并准备 git、Claude Code、Conductor 或其他智能体刚创建的 worktree:域名、端口、.env 和数据库,数据库按 新 worktree 的数据库 的选择处理。不会安装或启动任何东西:通常由创建 worktree 的工具负责。系统通知会告诉你环境已就绪,并附有 打开。这两项设置可以在 joppa.toml 的 [worktrees] 部分与团队共享。
只有开启之后创建的 worktree 才会被自动准备:之前已存在的需要点击 准备。
worktree 的环境
它显示在侧边栏中其项目的下方,标有 ⎇,并以分支命名。它的页面与项目页面相同(域名、进程、.env、运行时、分析),顶部会提示所属分支,并提供:
- 打开 myproject;
- 从 myproject 更新;
- 删除…:它的域名将被移除,进程将停止。按需勾选 删除它的数据库(为它创建的数据库)和 删除 worktree 文件夹(
git worktree remove;如果有未提交的更改会被拒绝,除非勾选 即使有未提交的更改)。
如果你保留文件夹,Joppa 不会再自动准备它(「已忽略」);点击 准备 可重新接管。