alibaba/open-code-review · error

%s is a git repository without a work tree (bare repo?); can

Error message

%s is a git repository without a work tree (bare repo?); cannot resolve its top level for review

What it means

When the path IS a git repository but `git rev-parse --show-toplevel` fails or returns empty, resolveWorkingDir concludes there is no work tree (a bare repo) and refuses to review. Bare repos have an object database but no checkout, so the #287 root-relative-path anchoring cannot resolve and diffs have no files on disk to read.

Source

Thrown at cmd/opencodereview/shared.go:168

	if !isGit && requireGit {
		return "", false, fmt.Errorf("%s is not a git repository", absPath)
	}
	// #287: git reports diff and `git show HEAD:<path>` paths relative to the
	// repository root, not the current directory. When `ocr review` runs from a
	// subdirectory of a monorepo, anchor RepoDir at the git top-level so those
	// root-relative paths resolve for both disk reads and git-show reads.
	// requireGit is true only for the review path; scan (requireGit=false) keeps
	// the CWD so its `git ls-files` walk stays scoped to the subdirectory.
	if isGit && requireGit {
		// runGitCmdStdout captures stdout only so git stderr notices can't
		// pollute the resolved path. --show-toplevel fails (or is empty) when
		// there is no work tree — e.g. a bare repo, where --git-dir succeeds so
		// isGit is true. Fail loudly there instead of silently reusing the
		// subdir, which would reproduce the #287 root-relative-path bug.
		top, topErr := runGitCmdStdout(absPath, "rev-parse", "--show-toplevel")
		t := strings.TrimSpace(string(top))
		if topErr != nil || t == "" {
			return "", false, fmt.Errorf("%s is a git repository without a work tree (bare repo?); cannot resolve its top level for review", absPath)
		}
		absPath = t
	}
	return absPath, isGit, nil
}

// llmRuntime bundles the LLM-side state both subcommands need once they've
// decided to actually run a session: tool definitions, an app-language
// adjusted template (mutated in place via ApplyLanguage), the LLM client,
// the resolved model name, and a fresh comment collector.
type llmRuntime struct {
	Client       llm.LLMClient
	Model        string
	Provider     string // resolved provider name (non-secret label; empty for non-provider endpoints)
	PlanToolDefs []llm.ToolDef
	MainToolDefs []llm.ToolDef
	Collector    *tool.CommentCollector
	// RetryCollector observes every LLM HTTP attempt this run makes. It is

View on GitHub (pinned to 5cf97d0d15)

Solutions

  1. Run ocr review against a normal (non-bare) clone: `git clone /srv/git/project.git` and point --dir at the clone
  2. If you must review a bare repo's content, create a temporary worktree: `git -C <bare> worktree add /tmp/wt` and review /tmp/wt
  3. Verify with `git -C <path> rev-parse --show-toplevel` before invoking

Example fix

// before
ocr review --dir /srv/git/project.git   # bare
// after
git clone /srv/git/project.git /tmp/project && ocr review --dir /tmp/project
Defensive patterns

Strategy: validation

Validate before calling

top, err := exec.Command("git", "-C", dir, "rev-parse", "--show-toplevel").Output()
if err != nil || len(bytes.TrimSpace(top)) == 0 {
	return fmt.Errorf("%s has no work tree (bare repo); use a normal clone", dir)
}

Try / catch

if err != nil {
	// fall back: create a temp worktree from the bare repo
	// git -C <bare> worktree add /tmp/wt && review /tmp/wt
	return err
}

Prevention

When it happens

Trigger: Running `ocr review` against a bare clone (`git clone --bare`, server-side repos like /srv/git/project.git) with requireGit=true.

Common situations: Pointing ocr at a gitolite/Gitea server-side repo directory; using a --bare clone as CI workspace; shared bare mirror used for backups.

Related errors


AI-assisted analysis of alibaba/open-code-review@5cf97d0d15 (2026-09-02). Data as JSON: /api/errors/1576063fc09a246b. Report an issue: GitHub.