gitbutlerapp/gitbutler · error

Target must be a commit ID or branch, not {}

Error message

Target must be a commit ID or branch, not {}

What it means

In `but show` (crates/but/src/command/legacy/show.rs:83), when the argument resolves to exactly one IdMap entry, only CliId::Commit and CliId::Branch are showable. Every other CliId variant (uncommitted file/hunk, path prefix, committed file, the uncommitted area, a worktree, a stack) bails, with kind_for_humans() naming the actual kind.

Source

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

        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()
                );
            }
        }
    };

    // Get commit and file details
    let repo = ctx.repo.get()?;
    let raw_commit = repo.find_commit(commit_id)?;
    let decoded = raw_commit.decode()?;

    // Get diff with first parent
    let parent_id = raw_commit.parent_ids().next().map(|id| id.detach());
    let tree_changes = but_core::diff::TreeChanges::from_trees(&repo, parent_id, commit_id)?;

    // Extract change-id if present (try both header names)
    let change_id = decoded

View on GitHub (pinned to caf1f223d3)

Solutions

  1. Pass a commit SHA or a branch CLI ID to `but show`.
  2. Use the command matching the entity kind: stack/branch subcommands for stacks and branches, `but status` for uncommitted items.
  3. Re-run `but status` and read the entity kind shown next to the ID before reusing it.

Example fix

# before
but show s7      # s7 is a stack ID
# Target must be a commit ID or branch, not a stack

# after
but branch list   # inspect stacks/branches
but show 4f2a     # a commit short ID
Defensive patterns

Strategy: type-guard

Validate before calling

let ids = id_map.lookup(arg);
if ids.len() == 1 && !matches!(ids[0], CliId::Commit { .. } | CliId::Branch(_)) {
    // route to the right command for this kind instead of `but show`
}

Type guard

fn is_showable_target(id: &CliId) -> bool {
    matches!(id, CliId::Commit { .. } | CliId::Branch(_))
}

Try / catch

match cli_ids[0] {
    CliId::Commit { .. } | CliId::Branch(_) => { /* proceed */ }
    other => anyhow::bail!("not showable: {} — use the matching subcommand", other.kind_for_humans()),
}

Prevention

When it happens

Trigger: Running `but show <short-id>` where the ID belongs to a stack, worktree, uncommitted area, committed file, or path prefix — e.g. copying a stack or worktree ID from `but status` output and passing it to show.

Common situations: Assuming every short ID printed by status works with every subcommand; scripted use of IDs without checking their kind; stale docs or examples.

Related errors


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