你的第一个 worktree
这一章把一个 checkout 从零带到跑起来的服务栈,再干净地停下来。示例是 Hello Worktree:两个 Python 3 进程,不装依赖、不要账号、不要 API key。
开始之前
你需要已在 PATH 上的 oberth(安装 oberth)、Python 3,以及仓库自带的示例目录。
git clone https://github.com/SheathedSharp/option-berth.git
cd option-berth/examples/hello-worktree
除非显式传 --allow-outside-home,这个 checkout 必须位于你的 HOME 之下;默认情况下引擎拒绝管理 HOME 边界之外的服务栈。
声明这套服务
示例已经带着一份 oberth.yaml。先读它,再运行任何命令:它就是全部输入。
name: hello-worktree
services:
- name: api
cmd: python3 -u api.py
port: auto
health: /health
- name: worker
cmd: python3 -u worker.py
depends_on: [api]
env:
API_URL: ${api.url}
两个服务。api 要求自动分配端口并带健康检查;worker 没有端口,在 api 之后启动,并通过 ${api.url} 拿到 API 的真实地址。这里的每一项都不是从运行中的进程猜出来的。
在你自己的项目里,这份文件由 oberth init 写出。agent 可以用 oberth init draft 起草,只有人会运行 oberth init adopt。
启动并等到就绪
oberth up --wait --json
--wait 只在每个服务真的就位后才返回:api 有绑定的监听、/health 通过,无端口的 worker 进程活着。还在启动的进程不算就绪,超时也不算成功。
读现在跑着什么
hello-worktree · main
api running :21730 health 200
worker running no port
2 services · manifest oberth.yaml
这个端口属于本 checkout:同一仓库的另一个 worktree 会拿到不同的端口,因为 port: auto 是按一次运行分配的,不是按项目记住的。no port 是一条事实,不是失败——worker 通过它的运行记录被观察到。
打开 status 打印的地址,就能看到 API 用它实际绑定的端口应答。同一次读取的 JSON 版本是 oberth status --json --brief,也是 agent 的开场读取。
读 worker 的日志
worker: API health=200
worker: API health=200
worker: API health=200
--once 读一次当前运行的日志就返回;不带它时 logs 会持续跟随。服务已经失败时,--first-error 给出当前运行的第一条错误,而不是最后一屏输出。
停下来
oberth down --force --json
down 停掉这个 worktree 启动的服务,并把端口预留交还。它不碰另一个 checkout、不碰普通用户的 daemon,也不碰清单从未声明过的进程。
亲手看一次隔离
给同一个仓库再建一个 Git worktree,在两边分别进入 examples/hello-worktree 并各自 up。两个 API 服务会拿到不同的端口。在其中一个里 down,另一个继续跑。