Hmbown/CodeWhale · error

The pinned PR commits do not have one available merge base

Error message

The pinned PR commits do not have one available merge base

What it means

After the shallow check, diff_with runs `git merge-base --all <base_sha> <head_sha>`. The result must be exactly one full 40-hex commit ID; multiple candidates (criss-cross/ambiguous merge bases) or no candidate mean there is no single well-defined merge base, and the review diff cannot be computed deterministically.

Solutions

  1. Fetch the missing objects: `git fetch origin <base_sha> <head_sha>` (or `git fetch origin '+refs/*:refs/remotes/origin/*' --prune --no-tags`), then retry
  2. If merge-base --all lists multiple commits, inspect `git log --graph` for criss-cross merges and confirm the PR's current base/head on GitHub; re-pin to the latest SHAs by re-running the review
  3. Confirm both SHAs exist locally with `git cat-file -e <sha>^{commit}` before retrying

Example fix

// before: ambiguous result silently used
let base = base.trim();
// after: require exactly one full commit id
let base = base.trim();
if !commit_id(base) {
    bail!("The pinned PR commits do not have one available merge base");
}
Defensive patterns

Strategy: validation

Validate before calling

// confirm exactly one merge base and full objects exist
let out = Command::new("git").args(["merge-base","--all",&base,&head]).output()?;
let bases: Vec<&str> = String::from_utf8_lossy(&out.stdout).trim().lines().collect();
assert_eq!(bases.len(), 1, "expected one merge base, got {}", bases.len());
for sha in [&base, &head, bases[0]] {
    assert!(Command::new("git").args(["cat-file","-e",format!("{sha}^{{commit}}").as_str()]).status()?.success(), "missing object {sha}");
}

Try / catch

let out = Command::new("git").args(["merge-base","--all",&base,&head]).output()?;
let n = String::from_utf8_lossy(&out.stdout).trim().lines().count();
if n != 1 { git_fetch_missing(&base, &head)?; } // then retry the review

Prevention

When it happens

Trigger: `git merge-base --all` for the pinned PR base/head returns empty (unrelated or missing history — objects not fetched) or more than one commit (criss-cross merges), so the trimmed output fails commit_id().

Common situations: Missing remote objects because origin wasn't fully fetched; histories of base and head branches diverged with multiple equally best ancestors; base SHA references a commit absent from the local clone; force-pushed base leaving orphaned pins.

Understand the failure class

Background: "git command failed": what it means when a tool shells out to git and git exits non-zero — this error's family across 21 libraries.

Related errors


AI-assisted analysis of Hmbown/CodeWhale@73e0f67d83 (2026-09-22). Data as JSON: /api/errors/00ae759dec88b178. Report an issue: GitHub.

Appendix: source

Thrown at crates/tui/src/tools/review_pr.rs:287

                let shallow = run(
                    Program::Git,
                    &["rev-parse".into(), "--is-shallow-repository".into()],
                )?;
                if shallow.trim() != "false" {
                    bail!("A full Git history is required to establish the PR merge base");
                }
                let base = run(
                    Program::Git,
                    &[
                        "merge-base".into(),
                        "--all".into(),
                        view.base_sha.clone(),
                        view.head_sha.clone(),
                    ],
                )?;
                let base = base.trim();
                if !commit_id(base) {
                    bail!("The pinned PR commits do not have one available merge base");
                }
                let diff = run(
                    Program::Git,
                    &[
                        "diff".into(),
                        "--no-ext-diff".into(),
                        "--no-textconv".into(),
                        "--no-color".into(),
                        "--no-relative".into(),
                        "--full-index".into(),
                        "--find-renames=50%".into(),
                        "--src-prefix=a/".into(),
                        "--dst-prefix=b/".into(),
                        "--ignore-submodules=none".into(),
                        "--submodule=short".into(),
                        base.into(),
                        view.head_sha.clone(),
                        "--".into(),

View on GitHub (pinned to 73e0f67d83)