gitbutlerapp/gitbutler · error

Commit ID '{}' is ambiguous. Found {} matches

Error message

Commit ID '{}' is ambiguous. Found {} matches

What it means

`but show` (crates/but/src/command/legacy/show.rs:67) resolves its argument through the IdMap of short CLI IDs; when the argument prefix matches more than one entity (cli_ids.len() > 1) it refuses to guess and reports the match count. Short IDs (often 2-character prefixes) are only usable when unique within the current workspace snapshot.

Source

Thrown at crates/but/src/command/legacy/show.rs:67

        }
    }

    // Not a branch, resolve the commit ID through the IdMap
    let cli_ids = id_map.parse_using_context(commit_id_str, ctx)?;

    let commit_id = if cli_ids.is_empty() {
        // If not found in IdMap, try to parse as a git commit ID directly
        let repo = ctx.repo.get()?;
        let obj = repo
            .rev_parse_single(commit_id_str)
            .map_err(|_| anyhow::anyhow!("Commit '{commit_id_str}' not found"))?;
        let commit = obj
            .object()?
            .try_into_commit()
            .map_err(|_| anyhow::anyhow!("'{commit_id_str}' is not a commit"))?;
        commit.id
    } else if cli_ids.len() > 1 {
        bail!(
            "Commit ID '{}' is ambiguous. Found {} matches",
            commit_id_str,
            cli_ids.len()
        );
    } else {
        match &cli_ids[0] {
            CliId::Commit {
                commit: CommitId { commit_id, .. },
                id: _,
            } => *commit_id,
            CliId::Branch(branch) => {
                // This is a branch identified by CLI ID, show the branch
                return show_branch(ctx, out, &branch.name, verbose, &id_map);
            }
            _ => {
                bail!(
                    "Target must be a commit ID or branch, not {}",
                    cli_ids[0].kind_for_humans()

View on GitHub (pinned to caf1f223d3)

Solutions

  1. Lengthen the prefix until unique, or pass the full 40-character object ID.
  2. Re-run `but status` to see the current short-ID assignments and pick an unambiguous one.
  3. Remember the fallback path: any string not in the IdMap is parsed with rev_parse_single, so full SHAs and ref names always bypass ambiguity.

Example fix

# before
but show ab
# Commit ID 'ab' is ambiguous. Found 2 matches

# after
but show ab9f31c04d8e2f7a1b3c5d6e7f8a9b0c1d2e3f4a
Defensive patterns

Strategy: validation

Validate before calling

let matches = id_map.lookup(prefix);
match matches.len() {
    0 => /* fall back to rev_parse_single */,
    1 => /* safe */,
    _ => return Err(anyhow::anyhow!("prefix '{}' matches {} entities; extend it", prefix, matches.len())),
}

Try / catch

if let Err(err) = show_command(&ctx, &out, id) {
    if err.to_string().contains("ambiguous") {
        // retry with the full 40-char SHA captured from the original entity
    }
}

Prevention

When it happens

Trigger: Passing a short ID prefix that collides across entities, e.g. `but show ab` where two commits or branches share that prefix; the workspace changed between displaying the ID and running the command, introducing a new collision.

Common situations: Copy-pasting a truncated ID from stale TUI/status output; small workspaces where 1-2 hex characters collide frequently; scripts that cut SHAs to fixed short lengths.

Related errors


AI-assisted analysis of gitbutlerapp/gitbutler@caf1f223d3 (2026-08-20). Data as JSON: /api/errors/b57ec69c2a24c6c9. Report an issue: GitHub.