{"record":{"id":"b735b2a8c6a8be25","repo":"gitbutlerapp/gitbutler","slug":"bug-gix-disables-this-as-it-knows-we-always-ne","errorCode":null,"errorMessage":"BUG: `gix` disables this, as it knows we always need to be able to run our own diff machinery","messagePattern":"BUG: `gix` disables this, as it knows we always need to be able to run our own diff machinery","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/but-core/src/unified_diff.rs","lineNumber":228,"sourceCode":"                let diff = gix::diff::blob::diff_with_slider_heuristics(algorithm, &input);\n                let (lines_added, lines_removed) = compute_line_changes(&diff);\n                let hunks = gix::diff::blob::UnifiedDiff::new(\n                    &diff,\n                    &input,\n                    ConsumeBinaryHunk::new(ProduceDiffHunk::default(), \"\\n\"),\n                    ContextSize::symmetrical(context_lines),\n                )\n                .consume()?\n                .hunks;\n                UnifiedPatch::Patch {\n                    is_result_of_binary_to_text_conversion: prep.old_or_new_is_derived,\n                    hunks,\n                    lines_added,\n                    lines_removed,\n                }\n            }\n            Operation::ExternalCommand { .. } => {\n                unreachable!(\n                    \"BUG: `gix` disables this, as it knows we always need to be able to run our own diff machinery\"\n                )\n            }\n            Operation::SourceOrDestinationIsBinary => {\n                use gix::diff::blob::platform::resource::Data;\n                fn size_for_data(data: Data<'_>) -> Option<u64> {\n                    match data {\n                        Data::Missing | Data::Buffer { .. } => None,\n                        Data::Binary { size } => Some(size),\n                    }\n                }\n                let (old, new) = diff_filter\n                    .resources()\n                    .expect(\"prepare would have failed if a resource is missing\");\n                let size = size_for_data(old.data)\n                    .or(size_for_data(new.data))\n                    .expect(\"BUG: one of the resources must have been binary/too big\");\n                let big_file_size = repo.big_file_threshold()?;","sourceCodeStart":210,"sourceCodeEnd":246,"githubUrl":"https://github.com/gitbutlerapp/gitbutler/blob/caf1f223d3cfb94488c9198ad34487c6006c648f/crates/but-core/src/unified_diff.rs#L210-L246","documentation":"`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.","triggerScenarios":"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.","commonSituations":"User repositories with `diff.external` configured or `.gitattributes` diff drivers; corporate environments setting `diff.external` globally; code reuse of a generic platform builder.","solutions":["Build the diff platform with external drivers disabled (pass no driver lookup), as the unified-diff code intends.","Unset `diff.external` in the affected repository or global config if you control the environment.","After gix upgrades, re-run unified-diff tests against a repo with gitattributes diff drivers to catch plumbing changes."],"exampleFix":"# environment-level workaround\n# before\ngit config --global diff.external 'my-diff-tool'\n\n# after (let GitButler run its own diff machinery)\ngit config --global --unset diff.external","handlingStrategy":"validation","validationCode":"// refuse to run when an external diff driver would hijack blob diffs\nlet ext = repo.config().string(\"diff.external\")?;\nif ext.is_some() {\n    anyhow::bail!(\"diff.external is set ({:?}); unset it or diff with drivers disabled\", ext.as_ref().map(|s| s.to_string()));\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Construct the gix blob-diff platform with external drivers disabled, as but-core's unified_diff does.","Unset diff.external in repos where GitButler panics on diffing.","Test against repositories with gitattributes diff drivers after gix upgrades."],"tags":["rust","but-core","gix","diff-drivers","gitattributes","internal-invariant"],"backgroundTag":"external-git-diff-driver","analyzedSha":"caf1f223d3cfb94488c9198ad34487c6006c648f","analyzedAt":"2026-08-20T07:55:40.983Z","schemaVersion":2},"datasetVersion":"2026-08-31T22:30:34.772Z"}