gitbutlerapp/gitbutler · error · anyhow::Error
commit '{spec}' is not part of the editable divergence
Error message
commit '{spec}' is not part of the editable divergence What it means
Raised by `resolve_commit` inside `parse_integration_steps_script` when a commit spec prefix-matches zero commits in `allowed_commits` — the set built from the divergence's editable commits (local-only commits chained with `upstream_only` commits). Anything outside that divergence (merge-base ancestors, commits on other branches, typos) is rejected so the integration cannot pull in foreign history.
Source
Thrown at crates/but-workspace/src/branch/integrate_branch_upstream/parsing.rs:159
.filter(|commit| {
matches!(
commit.target_relation,
IntegrationDivergenceTargetRelation::NotIntegrated
)
})
.map(|commit| commit.id)
.chain(divergence.upstream_only.iter().map(|commit| commit.id))
.collect()
}
fn resolve_commit(spec: &str, allowed_commits: &HashSet<gix::ObjectId>) -> Result<gix::ObjectId> {
let matches = allowed_commits
.iter()
.copied()
.filter(|commit_id| commit_id.to_string().starts_with(spec))
.collect::<Vec<_>>();
match matches.as_slice() {
[] => bail!("commit '{spec}' is not part of the editable divergence"),
[commit_id] => Ok(*commit_id),
_ => bail!("commit prefix '{spec}' is ambiguous"),
}
}
fn split_message_clause(line: &str) -> Result<(&str, Option<&str>)> {
let Some((command_part, message_part)) = line.split_once('|') else {
return Ok((line, None));
};
Ok((command_part.trim_end(), Some(message_part.trim_start())))
}
fn parse_message_clause(clause: &str) -> Result<String> {
let value = clause
.strip_prefix("message=")
.context("expected `message=` after `|`")?;
parse_quoted_string(value)
}View on GitHub (pinned to caf1f223d3)
Solutions
- Re-open/re-render the integration proposal so the script's commit list matches the current divergence, then re-apply edits.
- Copy commit prefixes only from the script itself or the divergence display shown alongside it.
- If a specific commit must be included, first bring it into the branch (so it appears in the local-only divergence), then restart integration.
Defensive patterns
Strategy: validation
Validate before calling
// Verify every spec in the script resolves against the current divergence before applying:
let allowed: HashSet<gix::ObjectId> = /* local_only + upstream_only commit ids from divergence */;
for (i, line) in script.lines().enumerate() {
for spec in line.split_whitespace().skip(1) {
let spec = spec.trim_start_matches('#');
if !allowed.iter().any(|id| id.to_string().starts_with(spec)) {
return Err(anyhow::anyhow!("line {}: commit {spec} not in divergence (stale script?)", i + 1));
}
}
} Try / catch
if let Err(err) = parse_integration_steps_script(&script, &divergence) {
if err.to_string().contains("not part of the editable divergence") {
// prompt: divergence changed, re-render the proposal and re-apply edits
}
} Prevention
- Bind the editor session to a snapshot of the divergence; if the branch updated since rendering, re-render before applying.
- Only let users reference commits listed in the rendered script/divergence view.
When it happens
Trigger: A script line references a SHA that is not one of the local-only or upstream-only divergence commits — e.g. copied from `git log` of the main branch, a full SHA from another stack, or a typo/hand-typed prefix. Also stale scripts: the divergence changed (branch updated, commits added) between rendering the script and parsing it back.
Common situations: User pastes a commit from elsewhere in the repo into the integration editor; the editor session is stale after the branch moved (script rendered before a fetch/update, parsed after); truncated SHAs that don't correspond to any allowed commit.
Related errors
- commit prefix '{spec}' is ambiguous
- line {line_number}: pick does not accept a message clause
- line {line_number}: pick requires exactly one commit
- line {line_number}: merge does not accept a message clause
- line {line_number}: merge requires exactly one commit
AI-assisted analysis of gitbutlerapp/gitbutler@caf1f223d3 (2026-08-20).
Data as JSON: /api/errors/72b2d380a7eef885.
Report an issue: GitHub.