- Ensure local and SSH worktree creation fetches the exact remote base ref before `git worktree add`, so new worktrees do not start from stale refs. - Fail creation before mutating git state when the required base refresh fails or remains missing. - Replace post-create repair/reconcile behavior with read-only drift reporting and add coverage for refresh ordering, cache bypassing, and SSH failures.
4.3 KiB
Worktree Pre-Create Base Refresh
Problem
When creating a local worktree from a remote-tracking base such as origin/main,
Orca previously allowed one stale-on-create path:
baseBranchresolved to a remote-tracking ref.- The remote-tracking ref already existed locally.
- The cached ref was stale.
That path started git fetch in the background and then continued to
git worktree add, so the new worktree could be created from the old local
refs/remotes/<remote>/<branch> value.
Issue #2307 asks for the next worktree after a merge to be based on the latest remote base. A post-create repair is not safe enough because the renderer may activate the worktree, launch setup, or start an agent immediately after create returns.
Decision
For remote-tracking bases, refresh before git worktree add.
Local and SSH create paths now follow the same rule:
- Resolve whether
baseBranchnames a configured remote-tracking ref. - If it does, refresh only that remote-tracking ref before creating the worktree:
git fetch --no-tags <remote> +refs/heads/<branch>:refs/remotes/<remote>/<branch>. - Do not update local branches such as
main; the refreshed ref isrefs/remotes/<remote>/<branch>. - Bypass the runtime's completed-fetch freshness cache for this create-time refresh. Sharing an already in-flight exact-base refresh is still allowed.
- If the refresh fails, fail the create before any worktree is created.
- If the base ref did not exist before refresh and still does not exist after a successful refresh, fail the create with a clear missing-base error.
- Only after the refresh succeeds, run
git worktree add.
Non-Goals
- Do not mutate a worktree after it has been returned to the renderer.
- Do not run
git reset --hardas part of stale-base repair. - Do not pull, merge, rebase, or fast-forward local
main. - Do not change explicit local-base semantics. Local bases such as
mainkeep the legacy best-effort fetch behavior. - Do not change
refreshLocalBaseRefOnWorktreeCreate; that setting may still fast-forward a local branch pointer, but it is separate from refreshing the remote-tracking base before create.
Why Pre-Create Beats Post-Create
The tempting alternative was:
create from stale ref -> wait for fetch -> if fast-forward, reset new worktree
That is unsafe because there is no atomic boundary between "the worktree is
untouched" and git reset --hard. Setup scripts, agents, or user edits can
start as soon as create returns. A clean-status check before reset still has a
race window.
The chosen design is slower on cold network paths, but it has the property we need: when create succeeds from a remote-tracking base, setup and agents start from the refreshed base immediately.
Failure Behavior
- Exact base-ref fetch fails/offline: create fails before
git worktree add. - Base ref missing after successful fetch: create fails before
git worktree add. - Remote-tracking base already exists: still refresh that one ref before create.
- Recent successful full-remote fetch exists in the 30s cache: still refresh the selected base ref before create, because a merge can land immediately after the cached fetch.
- Local/non-remote base: preserve best-effort fetch and create from the requested local base.
- SSH remote-tracking base: fail closed on fetch failure before asking the relay to create the worktree.
Data Flow
[Create request]
|
v
[Resolve baseBranch]
|
+-- remote-tracking? -- yes --> [fetch exact remote-tracking base ref]
| |
| +-- fail --> [no worktree created]
| |
| v
| [git worktree add]
|
+-- no ---------------------> [legacy best-effort fetch]
|
v
[git worktree add]
Tests
- Existing remote-tracking ref: create waits for refresh before
git worktree add. - Refresh failure: create fails and does not call
git worktree add. - Recent fetch cache: create still refreshes the exact base ref.
- SSH remote-tracking ref: fetch failure prevents relay worktree creation.
- Read-only reconcile remains non-mutating when a fetched base has moved.