Repository navigation
Open
Labels
Description
Summary
After one git repository's history is imported into another (monorepo migration with preserved ancestry), OpenCode V2 associates the new repo's directory with the old repo's project, and the native worktree tool then creates worktrees inside the old repository — even though the session is running in the new one.
Environment
- opencode version: 2.1.3
- OS: Darwin 25.6.0 (darwin arm64)
- Terminal: TERM_PROGRAM=ghostty, TERM=xterm-256color, COLORTERM=truecolor
- Shell: /bin/zsh
- Install/channel: latest
- Active plugins: opencode-wakelock, superpowers@git+https://github.com/obra/superpowers.git
Reproduction
- Create git repo
A(at least one commit) and open it once in OpenCode V2. A project is created; its ID equals a commit hash ofA(in my caseA's root commit — 40-hex exact match in theprojecttable). - Create git repo
Bin a different directory. ImportA's history intoBwhile preserving ancestry (e.g.git fetch /path/to/A <commit>+ merge).Bnow has multiple root commits, one of which isA's root commit — i.e. it matchesA's project ID. - Open
Bin OpenCode. The new directory gets linked toA's existing project: aproject_directoryrow forB's path appears underA'sproject_id, and new sessions created inBare assignedA's project. - With
worktree: { "directory": ".worktrees" }in the project config, invoke the native worktree-creation tool (worktree_create) from a session whose directory isB. - The worktree is created at
<A>/.worktrees/<name>— inside repoA. The server boots a location inA's directory for the tool call.
Expected Behavior
The worktree is created under the session's directory: <B>/.worktrees/<name>.
Actual Behavior
The worktree is created under the session's project's canonical directory (the worktree column of the project row), which is <A> — a different repository. Log evidence from ~/.local/share/opencode/log/opencode.log:
message="location services booted" directory=<A>
message="spawning process" command=git args=["worktree","add","--detach","--","<A>/.worktrees/<name>","HEAD"] cwd=<A>
while every shell command of the same session ran with cwd=<B>.
Additional Context
- Observed in
~/.local/share/opencode/opencode.db:projectstores a canonical directory;project_directorymappedB's path toA's project; essentially all new sessions inB(247/252 in my case) were assignedA's project after the association formed. - The project ID appears to be derived from a git commit (exact match with the repo's root/initial commit for two separate repos). After a history import, the new repo contains the old project's ID among its root commits, so directory→project resolution matches the old project. The exact tie-break when multiple roots match existing projects is unknown.
- Consistently reproducible once the directory→project association exists (re-verified live: a probe
worktree_createfrom a session inBlanded in<A>/.worktrees/, then was removed). - Workaround: create worktrees manually via shell (
git worktree add .worktrees/<name>), which is CWD-anchored and lands correctly. - Suggested directions: (1) native worktree placement should follow the session's directory rather than the project's canonical directory, and/or (2) directory→project resolution should prefer the project whose canonical directory equals the resolved directory over a project matched only via an imported-history commit.
Activity
opencode-agent commentedon Oct 22, 2026
Thanks for the detailed report. I can confirm this on 2.1.3, and it still happens on the latest
dev(074f2fe).What I did:
~/repo-b:main).worktree_createwithworktree.directory: ".worktrees".The worktree was created at
<A>/.worktrees/probeand shows up ingit worktree listfor A; B got none. The recording and script below show the whole run.The cause looks like this: the tool passes only the session's project ID, and worktree creation then uses that project's canonical directory as both the git source and the base for
worktree.directory. The session's own directory isn't used. Your manualgit worktree addworkaround avoids this for now.Related: #12103 (v1, the same root-commit project ID collision after a subtree merge, there affecting shared session history) and #51992 (canonical directory used instead of the selected worktree when creating sessions in the desktop app).
recording.mp4
Reproduction script (drive.ts)
Run it with opencode-drive:
opencode-drive run ./drive.ts. It drivesopencodefrom yourPATH; setOC_DEVto the path of an OpenCode checkout to run that from source instead.Dante-dan commentedon Oct 22, 2026
I've prepared a focused patch:
worktree_createpasses the current repository as its source and uses the calling location's registered worktree strategy and destination configuration. Calls without an explicit source retain their project-level defaults.The core worktree and native tool suites pass (37 tests on Bun 1.4.4), both adjusted regression cases pass 10 repetitions each on Bun 1.4.2, and
bun run checkpasses. The clone regression checks the new worktree's destination and source HEAD while the stored project canonical directory stays unchanged. I haven't rerun the interactive history-import recording.This addresses native worktree creation only; project identity and session grouping are unchanged. I can adjust the patch based on feedback.