Skip to content

fix(agent-management): open a worktree for a repository with no commits - #45

Merged
lihaokun merged 1 commit into
devfrom
fix/agent-workdir-unborn-head
Sep 25, 2026
Merged

lihaokun merged 1 commit into
devfrom
fix/agent-workdir-unborn-head

Conversation

@lihaokun

Copy link
Copy Markdown
Owner

Issue for this PR

Closes #44

Type of change

  • Bug fix
  • New feature
  • Refactor / code improvement
  • Documentation

What does this PR do?

Creating a subagent in a repository that had been git init-ed and never committed to failed outright. prepareWorkdir read the base commit with a plain rev-parse HEAD and treated any failure as fatal, so an unborn HEAD — a branch that exists in name only — took the whole creation down.

The judgement behind it was that being a git repository implies having a commit to branch from. It does not, and git has a shape for exactly this case: worktree add --orphan starts a branch with no history and needs no base. The resulting worktree is empty, which is correct — nothing is committed to check out — and the user's repository is left untouched: HEAD stays unborn, the commit count stays at zero.

rev-parse --verify -q separates the three outcomes. 0 resolves to a commit. 1 is the unborn branch, and says so with an empty stderr. Anything else keeps the hard error it always had, so a broken repository is not quietly downgraded into an empty workspace.

--orphan arrived in git 2.42, while Ubuntu 22.04 and Debian 12 are both still supported with older ones. Rather than parse git --version, whose release suffixes and 2.42.0.windows.1 forms are their own trap, the call is attempted and an empty workspace serves where it fails — that is what a project without git already gets, and a repository with nothing committed is in the same position. The reason travels back in a new optional AgentWorkdir.note and reaches the tool's output, so a git project producing no worktree is explained rather than silently downgraded.

note is a field rather than another WorkdirSource. That value decides which opening instruction the subagent receives, and a fallback workspace needs exactly the instruction an empty one already gets — a new value would have to be collapsed back into the old one at its only reader.

Two alternatives were considered and rejected, both recorded in the fix document: creating an empty commit so HEAD resolves writes to history the caller never asked to change, and telling the model to commit is an instruction to mutate the user's repository that it may well carry out as git add -A.

How did you verify your code works?

Two tests, both against real git, and the first checked to fail without the fix:

  • a repository whose branch ref is dropped — putting HEAD back where git init leaves it — now yields a worktree, and the repository still reports zero commits afterwards, so the fix is not buying success by writing to history
  • a repository with commits still branches from HEAD and carries its tracked files, guarding the other direction: an orphan worktree for an ordinary repository would hand the subagent an empty directory and none of the project

agent-management 101/101 and the worktree suites 22/22 pass; typecheck 30/30.

One case is deliberately not automated, with the reason recorded: "old git without --orphan" cannot be simulated under the real Git layer without faking a binary on PATH. The fallback path itself is covered by failing createForAgent directly, which is where that branch can actually go wrong.

Checklist

  • I have tested my changes locally
  • I have not included unrelated changes in this PR

Creating a subagent in a repository that had been initialised and never
committed to failed outright. prepareWorkdir read the base commit with a
plain rev-parse HEAD and treated any failure as fatal, so an unborn HEAD --
a branch that exists in name only -- took down the whole creation.

The judgement behind it was that being a git repository implies having a
commit to branch from. It does not, and git has a shape for exactly this
case: worktree add --orphan starts a branch with no history and needs no
base. The result is empty, which is correct, since nothing is committed to
check out. The user's repository is left untouched -- HEAD stays unborn and
the commit count stays at zero.

rev-parse --verify -q separates the three outcomes: 0 resolves, 1 is the
unborn branch and says so with an empty stderr, and anything else stays the
hard error it was, so a broken repository is not quietly downgraded.

--orphan arrived in git 2.42 while Ubuntu 22.04 and Debian 12 are both
supported with older ones. Rather than parse git --version, whose release
suffixes are their own trap, the call is attempted and an empty workspace
serves where it fails -- what a project without git already gets, and a
repository with nothing committed is in the same position. The reason
travels back in a new optional AgentWorkdir.note and reaches the tool's
output, so a git project producing no worktree is explained rather than
silently downgraded.

note is a field rather than another WorkdirSource: that value decides which
opening instruction the subagent receives, and a fallback workspace needs
exactly the instruction an empty one already gets, so a new value would have
to be collapsed back into the old one at its only reader.
@github-actions

Copy link
Copy Markdown

The following comment was made by an LLM, it may be inaccurate:

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

agent 在未提交的 git 仓库里无法创建工作目录

1 participant