gitbutlerapp/gitbutler · error · anyhow::Error

line {line_number}: invalid pick commit: {err}

Error message

line {line_number}: invalid pick commit: {err}

What it means

While parsing an edited interactive integration script, a `pick <commit>` line referenced a commit that resolve_commit could not match: the hash/prefix is not in the editable divergence set (not-integrated local-only commits plus all upstream-only commits), or the prefix matched multiple commits and is ambiguous. The inner error states which case.

Source

Thrown at crates/but-workspace/src/branch/integrate_branch_upstream/parsing.rs:56

            continue;
        };
        let arguments = tokens.get(1..).unwrap_or_default();

        let step = match command {
            "pick" => {
                if message_part.is_some() {
                    bail!("line {line_number}: pick does not accept a message clause");
                }
                if arguments.len() != 1 {
                    bail!("line {line_number}: pick requires exactly one commit");
                }
                let commit = arguments
                    .first()
                    .copied()
                    .expect("validated pick arity above");
                InteractiveIntegrationStep::Pick {
                    commit_id: resolve_commit(commit, &allowed_commits).map_err(|err| {
                        anyhow::anyhow!("line {line_number}: invalid pick commit: {err}")
                    })?,
                }
            }
            "merge" => {
                if message_part.is_some() {
                    bail!("line {line_number}: merge does not accept a message clause");
                }
                if arguments.len() != 1 {
                    bail!("line {line_number}: merge requires exactly one commit");
                }
                let commit = arguments
                    .first()
                    .copied()
                    .expect("validated merge arity above");
                InteractiveIntegrationStep::Merge {
                    commit_id: resolve_commit(commit, &allowed_commits).map_err(|err| {
                        anyhow::anyhow!("line {line_number}: invalid merge commit: {err}")
                    })?,

View on GitHub (pinned to caf1f223d3)

Solutions

  1. Use only hashes printed in the generated script (the current divergence candidates)
  2. Lengthen an ambiguous short hash until it matches exactly one candidate
  3. Remove pick lines for commits already integrated upstream
  4. Regenerate the script from the current divergence and re-apply edits

Example fix

# before
pick deadbee          # not part of the editable divergence
# after — copy the exact hash from the generated script
pick 3333333
Defensive patterns

Strategy: validation

Validate before calling

// validate the edited script against the same divergence before executing
let candidates: HashSet<String> = divergence.local_only.iter()
    .filter(|c| matches!(c.target_relation, IntegrationDivergenceTargetRelation::NotIntegrated))
    .map(|c| c.id.to_string()).chain(divergence.upstream_only.iter().map(|c| c.id.to_string())).collect();
for token in extract_commit_tokens(&script) {
    let matches = candidates.iter().filter(|c| c.starts_with(token)).count();
    assert_eq!(matches, 1, "commit {token} unknown or ambiguous");
}

Type guard

fn commit_resolves(candidates: &HashSet<String>, spec: &str) -> bool {
    candidates.iter().filter(|c| c.starts_with(spec)).count() == 1
}

Try / catch

match parse_integration_steps_script(&script, &divergence) {
    Err(e) if e.to_string().contains("invalid pick commit") => { /* highlight the line for the user to fix the hash */ }
    r => r,
}

Prevention

When it happens

Trigger: parse_integration_steps_script receiving a script where a pick line references a commit outside the editable candidates — e.g. an already-integrated local commit, a random hash like deadbee, or a short prefix that matches two candidate hashes (ambiguity).

Common situations: User hand-edits the rebase-plan-style script and introduces/keeps a stale hash from an older divergence; long scripts edited after the divergence changed underneath.

Related errors


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