alibaba/open-code-review · error

resolve merge-base between %q and %q

Error message

resolve merge-base between %q and %q

What it means

resolveInputBeforeDiff throws this when, in From/To range mode, the merge-base of the two resolved commits comes back empty from diff.Provider.ResolveInput. An empty ResolvedBase means git merge-base found no common ancestor, so no reviewable range exists between From and To. This happens before diffs are loaded, during resume/admission identity resolution.

Source

Thrown at internal/agent/identity.go:87

	switch {
	case args.Commit != "":
		head, err := resolveCommitHead(ctx, args, args.Commit)
		if err != nil {
			return nil, err
		}
		return &diff.InputResolution{ResolvedHead: head}, nil
	case args.From != "" && args.To != "":
		from, err := resolveCommitHead(ctx, args, args.From)
		if err != nil {
			return nil, err
		}
		head, err := resolveCommitHead(ctx, args, args.To)
		if err != nil {
			return nil, err
		}
		resolved := diff.NewProvider(args.RepoDir, from, head, args.GitRunner).ResolveInput(ctx)
		if resolved.ResolvedBase == "" {
			return nil, fmt.Errorf("resolve merge-base between %q and %q", args.From, args.To)
		}
		return &resolved, nil
	default:
		return nil, nil
	}
}

func resolveCommitHead(ctx context.Context, args Args, ref string) (string, error) {
	head := diff.NewCommitProvider(args.RepoDir, ref, args.GitRunner).ResolveInput(ctx).ResolvedHead
	if head == "" {
		return "", fmt.Errorf("resolve commit %q", ref)
	}
	return head, nil
}

// runIdentity reads the identity off the agent's current selection.
//
// It is only meaningful once the selection is final: sourceArtifactSHA256 hashes

View on GitHub (pinned to 5cf97d0d15)

Solutions

  1. Verify a common ancestor exists: 'git merge-base <from> <to>' must succeed in RepoDir
  2. Choose From/To that share history (e.g. merge-base with main, or use main as From)
  3. If histories are intentionally unrelated, run the review in commit mode (args.Commit) instead of range mode
  4. Fetch all relevant branches so the merge-base commit is not missing locally

Example fix

// before
resolved, err := agent.ResolveIdentity(ctx, agent.Args{From: "orphan-root", To: "main"})
// after: use the real merge point as From
resolved, err := agent.ResolveIdentity(ctx, agent.Args{From: "main~1", To: "main"})
Defensive patterns

Strategy: validation

Validate before calling

func hasCommonAncestor(repoDir, from, to string) bool {
    return execGit(repoDir, "merge-base", "--is-ancestor", from, to) == nil ||
           execGit(repoDir, "merge-base", from, to) == nil
}

Try / catch

sealed, err := agent.ResolveIdentity(ctx, args)
if err != nil && strings.HasPrefix(err.Error(), "resolve merge-base") {
    log.Warnf("unrelated histories for %q..%q; falling back to commit mode", args.From, args.To)
    args.Commit = args.To
    sealed, err = agent.ResolveIdentity(ctx, args)
}

Prevention

When it happens

Trigger: args.From and args.To resolve to commits on unrelated histories (no common ancestor) — e.g. comparing a commit from an orphan branch or two unrelated roots; also possible if the provider silently failed to run merge-base.

Common situations: Reviewing a PR between a squashed-rebase orphan and main; repos created by subtree merge with unrelated roots; --from/--to pointing at tags on diverged root commits after history rewrites.

Related errors


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