gitbutlerapp/gitbutler · error

BUG: `gix` disables this, as it knows we always need to be a

Error message

BUG: `gix` disables this, as it knows we always need to be able to run our own diff machinery

What it means

`but_core::unified_diff` drives gix's blob-diff platform and asserts it never sees `Operation::ExternalCommand`: the platform is intentionally created with external diff drivers disabled, because GitButler must run its own diff machinery (context handling, hunks, binary-to-text conversion) rather than shell out to `diff.external`/gitattributes drivers. The `unreachable!` fires when the platform was built honoring external diff commands after all.

Source

Thrown at crates/but-core/src/unified_diff.rs:228

                let diff = gix::diff::blob::diff_with_slider_heuristics(algorithm, &input);
                let (lines_added, lines_removed) = compute_line_changes(&diff);
                let hunks = gix::diff::blob::UnifiedDiff::new(
                    &diff,
                    &input,
                    ConsumeBinaryHunk::new(ProduceDiffHunk::default(), "\n"),
                    ContextSize::symmetrical(context_lines),
                )
                .consume()?
                .hunks;
                UnifiedPatch::Patch {
                    is_result_of_binary_to_text_conversion: prep.old_or_new_is_derived,
                    hunks,
                    lines_added,
                    lines_removed,
                }
            }
            Operation::ExternalCommand { .. } => {
                unreachable!(
                    "BUG: `gix` disables this, as it knows we always need to be able to run our own diff machinery"
                )
            }
            Operation::SourceOrDestinationIsBinary => {
                use gix::diff::blob::platform::resource::Data;
                fn size_for_data(data: Data<'_>) -> Option<u64> {
                    match data {
                        Data::Missing | Data::Buffer { .. } => None,
                        Data::Binary { size } => Some(size),
                    }
                }
                let (old, new) = diff_filter
                    .resources()
                    .expect("prepare would have failed if a resource is missing");
                let size = size_for_data(old.data)
                    .or(size_for_data(new.data))
                    .expect("BUG: one of the resources must have been binary/too big");
                let big_file_size = repo.big_file_threshold()?;

View on GitHub (pinned to caf1f223d3)

Solutions

  1. Build the diff platform with external drivers disabled (pass no driver lookup), as the unified-diff code intends.
  2. Unset `diff.external` in the affected repository or global config if you control the environment.
  3. After gix upgrades, re-run unified-diff tests against a repo with gitattributes diff drivers to catch plumbing changes.

Example fix

# environment-level workaround
# before
git config --global diff.external 'my-diff-tool'

# after (let GitButler run its own diff machinery)
git config --global --unset diff.external
Defensive patterns

Strategy: validation

Validate before calling

// refuse to run when an external diff driver would hijack blob diffs
let ext = repo.config().string("diff.external")?;
if ext.is_some() {
    anyhow::bail!("diff.external is set ({:?}); unset it or diff with drivers disabled", ext.as_ref().map(|s| s.to_string()));
}

Prevention

When it happens

Trigger: Constructing the gix diff platform with drivers looked up from repository config while `diff.external` or a `diff=<driver>` gitattribute is set; a refactor that starts passing `gix::diff::blob::Drivers` from config; a gix upgrade changing driver plumbing defaults.

Common situations: User repositories with `diff.external` configured or `.gitattributes` diff drivers; corporate environments setting `diff.external` globally; code reuse of a generic platform builder.

Related errors


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