-
Notifications
You must be signed in to change notification settings - Fork 4k
Description
Repos cloned from the same source share the same root commit hash, causing them to share sessions unexpectedly. Opening opencode in either repo shows sessions from both.
Affected workflows
- Cloned templates (e.g.,
create-react-app, Next.js starters) - Forks
- Any "clone and change origin" workflow
Reproduction
#!/bin/bash
set -e
WORKDIR=$(mktemp -d)
cd "$WORKDIR"
# Create template repo and clone it twice
mkdir template && cd template
git init -q && echo "template" > README.md && git add . && git commit -qm "init"
cd "$WORKDIR"
git clone -q template clone-a
git clone -q template clone-b
# Run opencode in each
(cd "$WORKDIR/clone-a" && opencode run "respond with only: session from clone-a")
(cd "$WORKDIR/clone-b" && opencode run "respond with only: session from clone-b")
# Verify collision
echo "clone-a project ID: $(cat "$WORKDIR/clone-a/.git/opencode")"
echo "clone-b project ID: $(cat "$WORKDIR/clone-b/.git/opencode")"
# Both are identical - opening opencode in either shows sessions from bothRoot cause
Project ID is derived from the first root commit hash:
opencode/packages/opencode/src/project/project.ts
Lines 57 to 72 in 038cff4
| if (!id) { | |
| const roots = await $`git rev-list --max-parents=0 --all` | |
| .quiet() | |
| .nothrow() | |
| .cwd(worktree) | |
| .text() | |
| .then((x) => | |
| x | |
| .split("\n") | |
| .filter(Boolean) | |
| .map((x) => x.trim()) | |
| .toSorted(), | |
| ) | |
| id = roots[0] | |
| if (id) Bun.file(path.join(git, "opencode")).write(id) | |
| } |
Related
- Desktop app: opening multiple git worktrees from the same repo replaces existing project #5638 - Same root cause but for git worktrees. PR fix: desktop app worktree collision - use separate ID per worktree #5647 fixes worktrees by adding worktree hash, but cloned repos aren't worktrees so they still collide.
Notes on solution
The fix probably needs to be conditional:
- Worktree → Share project ID with main repo (current behavior is correct for this case)
- Git repo (not worktree) → Need deterministic unique ID that doesn't collide across clones. Root commit alone isn't sufficient. Options: include absolute path in hash, or remote origin URL, or generate UUID on first run.
- Not a git repo → Could use absolute path
Key insight: PR #5647 correctly handles worktrees. This issue is specifically about the non-worktree clone scenario.
Side note: worktree caching
In git worktrees, .git is a file (not directory) pointing to .git/worktrees/<name>/. The current cache write to .git/opencode fails silently. Depending on the solution chosen here, this silent failure may cause issues if the fix relies on persisting something to that file.
opencode/packages/opencode/src/project/project.ts
Lines 53 to 56 in 038cff4
| let id = await Bun.file(path.join(git, "opencode")) | |
| .text() | |
| .then((x) => x.trim()) | |
| .catch(() => {}) |