{"record":{"id":"63fba6fd4717072e","repo":"alibaba/open-code-review","slug":"cannot-find-merge-base-between-s-and-s","errorCode":null,"errorMessage":"cannot find merge-base between %s and %s","messagePattern":"cannot find merge-base between (.+?) and (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/diff/git.go","lineNumber":181,"sourceCode":"\n// MergeBase returns the computed merge-base commit hash for range mode.\nfunc (p *Provider) MergeBase(ctx context.Context) string {\n\tif p.mode != ModeRange || p.mergeBase != \"\" {\n\t\treturn p.mergeBase\n\t}\n\tp.mergeBase = p.computeMergeBase(ctx, p.from, p.to)\n\treturn p.mergeBase\n}\n\n// GetDiff returns all changes as parsed model.Diff structs.\nfunc (p *Provider) GetDiff(ctx context.Context) ([]model.Diff, error) {\n\tvar combined strings.Builder\n\n\tswitch p.mode {\n\tcase ModeRange:\n\t\tbase := p.MergeBase(ctx)\n\t\tif base == \"\" {\n\t\t\treturn nil, fmt.Errorf(\"cannot find merge-base between %s and %s\", p.from, p.to)\n\t\t}\n\t\tout, 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, \"--\")\n\t\tif err != nil {\n\t\t\treturn nil, gitFailure(\"git diff\", stderr, err)\n\t\t}\n\t\tcombined.WriteString(out)\n\n\tcase ModeCommit:\n\t\t// --diff-merges=first-parent: for merge commits, plain `git show`\n\t\t// emits a combined diff (\"diff --cc\"), which ParseDiffText cannot\n\t\t// parse — the commit would silently yield zero reviewable diffs.\n\t\t// Diffs against the first parent instead, in regular unified format.\n\t\tout, 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)\n\t\tif err != nil {\n\t\t\treturn nil, gitFailure(\"git show\", stderr, err)\n\t\t}\n\t\tcombined.WriteString(out)\n","sourceCodeStart":163,"sourceCodeEnd":199,"githubUrl":"https://github.com/alibaba/open-code-review/blob/5cf97d0d15cbd41b602513c4be3bfec3cee5bf7f/internal/diff/git.go#L163-L199","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Check both refs exist (git rev-parse <from> <to>) and are spelled correctly","Use refs that share history, or unshallow the clone (git fetch --unshallow)","Switch the diff mode to a workspace or commit diff instead of a range diff","Verify ancestry with git merge-base <from> <to> before invoking"],"exampleFix":"// before\nbase := p.MergeBase(ctx); if base == \"\" { return nil, ... } // unrelated refs\n// after\n// pick a common ancestor\nparams.from = \"main\"; params.to = \"feature\" // both on shared history\nbase := p.MergeBase(ctx); if base == \"\" { return nil, ... }","handlingStrategy":"validation","validationCode":"func haveMergeBase(ctx context.Context, dir, from, to string) bool {\n    out, err := exec.CommandContext(ctx, \"git\", \"-C\", dir, \"merge-base\", from, to).Output()\n    return err == nil && len(bytes.TrimSpace(out)) > 0\n}","typeGuard":null,"tryCatchPattern":"d, err := differ.GetDiff(ctx, p)\nif err != nil && strings.Contains(err.Error(), \"cannot find merge-base\") {\n    // fall back to two-dot compare or workspace diff\n}","preventionTips":["Unshallow CI clones (fetch-depth: 0) so merge-bases resolve","Verify both refs share history before requesting a range diff","Sanitize/refuse user-supplied refs that fail git rev-parse"],"tags":["git","diff","merge-base"],"backgroundTag":"git-no-common-ancestor","analyzedSha":"5cf97d0d15cbd41b602513c4be3bfec3cee5bf7f","analyzedAt":"2026-09-02T02:08:09.116Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}