gitbutlerapp/gitbutler · error · anyhow::Error
line {line_number}: pick requires exactly one commit
Error message
line {line_number}: pick requires exactly one commit What it means
Raised by `parse_integration_steps_script` when a `pick` line does not have exactly one argument. Tokens are whitespace-split from the command part (before any `|`), so pick must be `pick <commit-spec>` with exactly one spec.
Source
Thrown at crates/but-workspace/src/branch/integrate_branch_upstream/parsing.rs:48
if trimmed.is_empty() || trimmed.starts_with('#') {
continue;
}
let (command_part, message_part) = split_message_clause(trimmed)
.with_context(|| format!("line {line_number}: invalid message clause"))?;
let tokens = command_part.split_whitespace().collect::<Vec<_>>();
let Some(command) = tokens.first().copied() else {
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");
}View on GitHub (pinned to caf1f223d3)
Solutions
- Use exactly one commit spec: `pick 4f2a9c1`.
- If pasting from `git rebase -i`, strip trailing subject text from each line first.
- Use a `squash` line if you actually wanted multiple commits combined.
Example fix
# before pick 4f2a9c1 add login handler # after pick 4f2a9c1
Defensive patterns
Strategy: validation
Validate before calling
// Strip git-rebase-style subjects before parsing a pasted todo:
let cleaned: Vec<String> = script.lines().map(|l| {
let mut it = l.split_whitespace();
match it.next() {
Some(cmd @ ("pick" | "merge")) => format!("{} {}", cmd, it.next().unwrap_or_default()),
_ => l.to_string(),
}
}).collect(); Try / catch
if let Err(err) = parse_integration_steps_script(&script, &divergence) {
// err contains 'line {n}: pick requires exactly one commit'; map line n back to the editor
} Prevention
- Validate the script with parse_integration_steps_script before applying.
- When pre-filling the editor, always emit bare `pick <sha>` lines (no commit subjects).
When it happens
Trigger: Lines like `pick` (no commit), `pick 4f2a 991b` (two commits), or `pick <full-sha> extra-text`. Note the legacy git-rebase habit `pick <sha> <commit-subject>` fails here because the subject words count as extra arguments.
Common situations: Pasting a git-rebase todo (which appends commit subjects after the SHA) into the integration editor; scripts edited by hand or generated by another tool that emit subjects.
Related errors
- line {line_number}: merge requires exactly one commit
- line {line_number}: pick does not accept a message clause
- line {line_number}: merge does not accept a message clause
- line {line_number}: squash requires at least two commits
- line {line_number}: unknown command '{other}'
AI-assisted analysis of gitbutlerapp/gitbutler@caf1f223d3 (2026-08-20).
Data as JSON: /api/errors/df0fa0d89af974cf.
Report an issue: GitHub.