Compare commits

...

1 Commits

Author SHA1 Message Date
Jiang Bohan
3da7815a78 refactor(repocache): clarify resolveBaseRef comment and cover tag refs
Follow-up nits from PR #1988 review:

- Move the comment that documents getRemoteDefaultBranch's resolution
  walk into the resolveBaseRef call site description, and rephrase the
  "" branch so it's clear that path only fires for the default-branch
  case (the requested-ref path returns an explicit error before
  reaching it).
- Add TestCreateWorktreeWithRequestedTagRef to lock in the
  refs/tags/<ref> candidate. The test tags the initial commit, advances
  the default branch past it, then asserts the worktree HEAD matches
  the tagged commit (so the tag must have been resolved, not the
  default branch).

Co-authored-by: multica-agent <github@multica.ai>
2026-05-03 11:28:57 +08:00
2 changed files with 44 additions and 8 deletions

View File

@@ -399,19 +399,23 @@ func (c *Cache) CreateWorktree(params WorktreeParams) (*WorktreeResult, error) {
}
// Determine the ref to base the worktree on. By default this is the remote's
// default branch. Callers may request a specific branch, tag, or commit so
// review/QA agents can inspect the exact revision without trying to mutate
// the daemon-owned worktree metadata themselves.
// default branch (resolved internally via getRemoteDefaultBranch, which walks
// origin/HEAD → origin/main, origin/master → bare-HEAD hint into origin/<same>
// → single-entry scan of origin/* → bare HEAD when origin/* is empty).
// Callers may request a specific branch, tag, or commit so review/QA agents
// can inspect the exact revision without trying to mutate the daemon-owned
// worktree metadata themselves.
baseRef, err := resolveBaseRef(barePath, params.Ref)
if err != nil {
return nil, err
}
// getRemoteDefaultBranch walks origin/HEAD → origin/main, origin/master →
// bare-HEAD hint into origin/<same> → single-entry scan of origin/* → bare
// HEAD (only if origin/* is empty). Reaching "" here means the cache is in a
// state we refuse to guess from (no origin/HEAD, no main/master, bare HEAD
// doesn't match any origin/* entry, and origin/* has multiple candidates).
// Empty here means params.Ref was unset and getRemoteDefaultBranch couldn't
// resolve a default — the cache is in a state we refuse to guess from (no
// origin/HEAD, no main/master, bare HEAD doesn't match any origin/* entry,
// and origin/* has multiple candidates). The requested-ref path returns an
// explicit error before reaching here, so this branch only fires for the
// default-branch case.
if baseRef == "" {
return nil, fmt.Errorf("cannot resolve default branch for %s: bare cache at %s has no usable refs (origin/* is empty or ambiguous and bare HEAD has no match). The cache may be corrupted; delete it and retry", params.RepoURL, barePath)
}

View File

@@ -591,6 +591,38 @@ func TestCreateWorktreeWithRequestedCommitRef(t *testing.T) {
}
}
func TestCreateWorktreeWithRequestedTagRef(t *testing.T) {
t.Parallel()
sourceRepo := createTestRepo(t)
taggedCommit := gitHead(t, sourceRepo)
runGitAuthored(t, sourceRepo, "tag", "v1")
// Advance the default branch past the tag so worktree HEAD == taggedCommit
// can only be true if the tag was actually resolved (vs falling back to
// the default branch tip).
addEmptyCommit(t, sourceRepo, "post-tag commit")
cache := New(t.TempDir(), testLogger())
if err := cache.Sync("ws-1", []RepoInfo{{URL: sourceRepo}}); err != nil {
t.Fatalf("sync failed: %v", err)
}
result, err := cache.CreateWorktree(WorktreeParams{
WorkspaceID: "ws-1",
RepoURL: sourceRepo,
WorkDir: t.TempDir(),
Ref: "v1",
AgentName: "Reviewer",
TaskID: "tag-task-id",
})
if err != nil {
t.Fatalf("CreateWorktree failed: %v", err)
}
if got := gitHead(t, result.Path); got != taggedCommit {
t.Fatalf("worktree HEAD = %s, want tagged commit %s", got, taggedCommit)
}
}
func TestCreateWorktreeWithUnknownRequestedRef(t *testing.T) {
t.Parallel()
sourceRepo := createTestRepo(t)