alibaba/open-code-review · error

cannot find merge-base between %s and %s

Error message

cannot find merge-base between %s and %s

What it means

In ModeRange, GetDiff first computes the merge-base of p.from and p.to via MergeBase; if git returns no merge-base (empty string), the range diff is meaningless and this error is returned. It means the two revisions share no common ancestor, so 'from..to' style comparison cannot be performed.

Source

Thrown at internal/diff/git.go:181

// MergeBase returns the computed merge-base commit hash for range mode.
func (p *Provider) MergeBase(ctx context.Context) string {
	if p.mode != ModeRange || p.mergeBase != "" {
		return p.mergeBase
	}
	p.mergeBase = p.computeMergeBase(ctx, p.from, p.to)
	return p.mergeBase
}

// GetDiff returns all changes as parsed model.Diff structs.
func (p *Provider) GetDiff(ctx context.Context) ([]model.Diff, error) {
	var combined strings.Builder

	switch p.mode {
	case ModeRange:
		base := p.MergeBase(ctx)
		if base == "" {
			return nil, fmt.Errorf("cannot find merge-base between %s and %s", p.from, p.to)
		}
		out, stderr, err := p.runGitSplit(ctx, "-c", "core.quotepath=false", "diff", "--no-ext-diff", "--no-textconv", "--find-renames", "--src-prefix=a/", "--dst-prefix=b/", "--no-color", "-U"+fmt.Sprint(DiffContextLines), "--end-of-options", base, p.to, "--")
		if err != nil {
			return nil, gitFailure("git diff", stderr, err)
		}
		combined.WriteString(out)

	case ModeCommit:
		// --diff-merges=first-parent: for merge commits, plain `git show`
		// emits a combined diff ("diff --cc"), which ParseDiffText cannot
		// parse — the commit would silently yield zero reviewable diffs.
		// Diffs against the first parent instead, in regular unified format.
		out, stderr, err := p.runGitSplit(ctx, "-c", "core.quotepath=false", "show", "--no-ext-diff", "--no-textconv", "--find-renames", "--src-prefix=a/", "--dst-prefix=b/", "--no-color", "--diff-merges=first-parent", "-U"+fmt.Sprint(DiffContextLines), "--end-of-options", p.commit)
		if err != nil {
			return nil, gitFailure("git show", stderr, err)
		}
		combined.WriteString(out)

View on GitHub (pinned to 5cf97d0d15)

Solutions

  1. Check both refs exist (git rev-parse <from> <to>) and are spelled correctly
  2. Use refs that share history, or unshallow the clone (git fetch --unshallow)
  3. Switch the diff mode to a workspace or commit diff instead of a range diff
  4. Verify ancestry with git merge-base <from> <to> before invoking

Example fix

// before
base := p.MergeBase(ctx); if base == "" { return nil, ... } // unrelated refs
// after
// pick a common ancestor
params.from = "main"; params.to = "feature" // both on shared history
base := p.MergeBase(ctx); if base == "" { return nil, ... }
Defensive patterns

Strategy: validation

Validate before calling

func haveMergeBase(ctx context.Context, dir, from, to string) bool {
    out, err := exec.CommandContext(ctx, "git", "-C", dir, "merge-base", from, to).Output()
    return err == nil && len(bytes.TrimSpace(out)) > 0
}

Try / catch

d, err := differ.GetDiff(ctx, p)
if err != nil && strings.Contains(err.Error(), "cannot find merge-base") {
    // fall back to two-dot compare or workspace diff
}

Prevention

When it happens

Trigger: Calling GetDiff on a params with mode=ModeRange where from and to are unrelated histories (e.g. two orphan branches), or where a revision name is invalid enough that git merge-base silently returns nothing.

Common situations: Comparing a fresh orphan branch against main; typo'd ref names; comparing across repos or after history rewrites that severed ancestry; CI shallow clones missing shared history.

Related errors


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