gitbutlerapp/gitbutler · error

" " does not refer to a commit or a branch

Error message

"{target}" does not refer to a commit or a branch

What it means

Thrown by parse_commit_or_branch when the IdMap matched exactly one CliId, but that id is neither a Commit nor a Branch (e.g. a file/htag/hunk id). The target resolves to something in the workspace, just not an entity that can carry conflicts.

Solutions

  1. Run `but status` and use a commit or branch identifier instead.
  2. If the goal is to resolve a file, pass the path in the path/hunk argument position, not as the commit target.

Example fix

// before
but resolve src/main.rs
// after
but resolve abc123 src/main.rs
Defensive patterns

Strategy: type-guard

Validate before calling

const matched = idMap.parse(target);
if (matched.length === 1 && matched[0].kind !== 'commit' && matched[0].kind !== 'branch') {
  throw new Error('target must be a commit or branch, not ' + matched[0].kind);
}

Type guard

const isCommit = (id: CliId): id is CommitCliId => id.kind === 'commit';
const isBranch = (id: CliId): id is BranchCliId => id.kind === 'branch';

Try / catch

try { await butResolve(target) } catch (e) { if (String(e).includes('does not refer to a commit or a branch')) { hint('pass a commit or branch id; the path goes as a separate argument'); } }

Prevention

When it happens

Trigger: Passing a filename, hunk marker, or other non-commit/non-branch CliId as the conflict target to `but resolve`.

Common situations: Users paste a file path or hunk reference (like in `but resolve file.rs`) when the command in this position expects a commit or branch identifier.

Understand the failure class

Background: Type mismatch errors: IllegalArgumentException, TypeError and type guards across 150 open-source libraries — this error's family across 150 libraries.

Related errors


AI-assisted analysis of gitbutlerapp/gitbutler@58e5313667 (2026-09-18). Data as JSON: /api/errors/b1537bdb2bb9a6a1. Report an issue: GitHub.

Appendix: source

Thrown at crates/but/src/command/legacy/resolve.rs:713

    }))
}

enum CommitOrBranch {
    Commit(gix::ObjectId),
    Branch(String),
}

/// Resolve a user-provided identifier to a commit or a branch.
fn parse_commit_or_branch(ctx: &mut Context, target: &str) -> Result<CommitOrBranch> {
    let id_map = IdMap::legacy_new_from_context(ctx)?;
    let matches = id_map.parse_using_context(target, ctx)?;
    match matches.as_slice() {
        [] => bail!(
            "\"{target}\" is neither a commit nor a branch. Try running 'but status' to see what is available."
        ),
        [CliId::Commit { commit, .. }] => Ok(CommitOrBranch::Commit(commit.commit_id)),
        [CliId::Branch(branch)] => Ok(CommitOrBranch::Branch(branch.name.clone())),
        [_] => bail!("\"{target}\" does not refer to a commit or a branch"),
        _ => bail!(
            "\"{target}\" is ambiguous. Please provide more characters to uniquely identify it."
        ),
    }
}

/// List the conflicts of a conflicted commit without entering resolution mode.
fn list_conflicts(ctx: &mut Context, out: &mut OutputChannel, commit: Option<&str>) -> Result<()> {
    let t = theme::get();
    let Some(target) = target_conflicted_commit(ctx, commit)? else {
        if let Some(human_out) = out.for_human() {
            writeln!(
                human_out,
                "{}",
                t.success.paint("No conflicted commits found.")
            )?;
        }
        if let Some(json_out) = out.for_json() {

View on GitHub (pinned to 58e5313667)