Script 'mail_helper' called by obssrc
Hello community,

here is the log from the commit of package mergiraf for openSUSE:Factory 
checked in at 2026-09-01 15:51:58
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/mergiraf (Old)
 and      /work/SRC/openSUSE:Factory/.mergiraf.new.1265 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Package is "mergiraf"

Tue Sep  1 15:51:58 2026 rev:13 rq:1375086 version:0.19.1

Changes:
--------
--- /work/SRC/openSUSE:Factory/mergiraf/mergiraf.changes        2026-08-21 
22:17:17.310870205 +0200
+++ /work/SRC/openSUSE:Factory/.mergiraf.new.1265/mergiraf.changes      
2026-09-01 15:52:36.757665291 +0200
@@ -1,0 +2,10 @@
+Tue Sep 01 10:38:15 UTC 2026 - Andrei Dziahel <[email protected]>
+
+- Update to version 0.19.1:
+  * Set version to 0.19.1
+  * fix: don't abort the overall merge when merging binary files (#817)
+  * fix(kotlin): add missing signature for visibility modifiers (#820)
+  * refactor: simplify code using the `in_data_dir` helper (#814)
+  * cargo-update-20260817 (#811)
+
+-------------------------------------------------------------------

Old:
----
  mergiraf-0.19.0.obscpio

New:
----
  mergiraf-0.19.1.obscpio

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Other differences:
------------------
++++++ mergiraf.spec ++++++
--- /var/tmp/diff_new_pack.anfPkC/_old  2026-09-01 15:52:37.865703948 +0200
+++ /var/tmp/diff_new_pack.anfPkC/_new  2026-09-01 15:52:37.868704052 +0200
@@ -18,7 +18,7 @@
 
 
 Name:           mergiraf
-Version:        0.19.0
+Version:        0.19.1
 Release:        0
 Summary:        A syntax-aware git merge driver
 License:        GPL-3.0-or-later

++++++ _service ++++++
--- /var/tmp/diff_new_pack.anfPkC/_old  2026-09-01 15:52:37.916705727 +0200
+++ /var/tmp/diff_new_pack.anfPkC/_new  2026-09-01 15:52:37.919705832 +0200
@@ -3,7 +3,7 @@
     <param name="url">https://codeberg.org/mergiraf/mergiraf.git</param>
     <param name="versionformat">@PARENT_TAG@</param>
     <param name="scm">git</param>
-    <param name="revision">v0.19.0</param>
+    <param name="revision">v0.19.1</param>
     <param name="versionrewrite-pattern">v(\d+\.\d+\.\d+)</param>
     <param name="changesgenerate">enable</param>
   </service>

++++++ _servicedata ++++++
--- /var/tmp/diff_new_pack.anfPkC/_old  2026-09-01 15:52:37.943706669 +0200
+++ /var/tmp/diff_new_pack.anfPkC/_new  2026-09-01 15:52:37.947706808 +0200
@@ -1,6 +1,6 @@
 <servicedata>
 <service name="tar_scm">
                 <param 
name="url">https://codeberg.org/mergiraf/mergiraf.git</param>
-              <param 
name="changesrevision">7246b03c08c02248035bc20668fde1edf94a09e0</param></service></servicedata>
+              <param 
name="changesrevision">e1c6514fb364faca51132be2b336aa739cdfadb9</param></service></servicedata>
 (No newline at EOF)
 

++++++ mergiraf-0.19.0.obscpio -> mergiraf-0.19.1.obscpio ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/mergiraf-0.19.0/Cargo.lock 
new/mergiraf-0.19.1/Cargo.lock
--- old/mergiraf-0.19.0/Cargo.lock      2026-08-16 17:58:44.000000000 +0200
+++ new/mergiraf-0.19.1/Cargo.lock      2026-09-01 10:50:21.000000000 +0200
@@ -146,9 +146,9 @@
 
 [[package]]
 name = "cc"
-version = "1.4.0"
+version = "1.4.3"
 source = "registry+https://github.com/rust-lang/crates.io-index";
-checksum = "5add81bb678e6cb321aff7fa0dc7689ad82b112dbc032cea19f91d6b8e3582b9"
+checksum = "509591b7bcd67f4ef775afad7662703b4935daaa6ec0e5605cfb1090b32a2b6d"
 dependencies = [
  "find-msvc-tools",
  "shlex",
@@ -175,9 +175,9 @@
 
 [[package]]
 name = "clap"
-version = "4.6.5"
+version = "4.6.6"
 source = "registry+https://github.com/rust-lang/crates.io-index";
-checksum = "301b56658598e48f3648647ac6fc887be7e7108eddfa4e9b63fcf3ec58c0cadf"
+checksum = "473c7e07f409a8d772161724aa8db6a765a2532a70f9667eeb7b49d3d02fbdca"
 dependencies = [
  "clap_builder",
  "clap_derive",
@@ -185,9 +185,9 @@
 
 [[package]]
 name = "clap_builder"
-version = "4.6.5"
+version = "4.6.6"
 source = "registry+https://github.com/rust-lang/crates.io-index";
-checksum = "94a65403d1a1bd28f7dc68eb8506e8874808ee5eecb59298de588e2e1407a078"
+checksum = "7b48fea5a88e9ae728a2dcbedbfc0e730f7d60da42e1cb049a83c9fb8b789889"
 dependencies = [
  "anstream",
  "anstyle",
@@ -345,9 +345,9 @@
 
 [[package]]
 name = "find-msvc-tools"
-version = "0.1.9"
+version = "0.1.11"
 source = "registry+https://github.com/rust-lang/crates.io-index";
-checksum = "5baebc0774151f905a1a2cc41989300b1e6fbb29aff0ceffa1064fdd3088d582"
+checksum = "d45db016d36b838f563236e9193d0ee6ce38f3f68b6c94e914b4929c96bbb890"
 
 [[package]]
 name = "fixedbitset"
@@ -366,6 +366,15 @@
 ]
 
 [[package]]
+name = "float-cmp"
+version = "0.10.0"
+source = "registry+https://github.com/rust-lang/crates.io-index";
+checksum = "b09cf3155332e944990140d967ff5eceb70df778b34f77d8075db46e4704e6d8"
+dependencies = [
+ "num-traits",
+]
+
+[[package]]
 name = "foldhash"
 version = "0.1.5"
 source = "registry+https://github.com/rust-lang/crates.io-index";
@@ -615,7 +624,7 @@
 
 [[package]]
 name = "mergiraf"
-version = "0.19.0"
+version = "0.19.1"
 dependencies = [
  "assert_cmd",
  "caplog",
@@ -631,6 +640,7 @@
  "nonempty-collections",
  "nu-ansi-term",
  "oneshot",
+ "predicates",
  "pretty_assertions",
  "rand",
  "regex",
@@ -638,7 +648,7 @@
  "rustc-hash 2.1.3",
  "stderrlog",
  "tempfile",
- "thiserror 2.0.19",
+ "thiserror 2.0.20",
  "tree-edit-distance",
  "tree-sitter",
  "tree-sitter-bash",
@@ -719,6 +729,12 @@
 checksum = "988fb92b275335f315a9bddf7a8881a02c79c6084e9a626f656f12c50776a045"
 
 [[package]]
+name = "normalize-line-endings"
+version = "0.3.0"
+source = "registry+https://github.com/rust-lang/crates.io-index";
+checksum = "61807f77802ff30975e01f4f071c8ba10c022052f98b3294119f3e615d13e5be"
+
+[[package]]
 name = "nu-ansi-term"
 version = "0.50.3"
 source = "registry+https://github.com/rust-lang/crates.io-index";
@@ -792,7 +808,10 @@
 dependencies = [
  "anstyle",
  "difflib",
+ "float-cmp",
+ "normalize-line-endings",
  "predicates-core",
+ "regex",
 ]
 
 [[package]]
@@ -1140,11 +1159,11 @@
 
 [[package]]
 name = "thiserror"
-version = "2.0.19"
+version = "2.0.20"
 source = "registry+https://github.com/rust-lang/crates.io-index";
-checksum = "09a43598840e33d5b0331f38c5e30d13bb11c11210a4b58f0d9b18a5a5eefcd9"
+checksum = "ec86235f5fcc2a73650310756d2ac5b138a5780bbbdfae3eeccec992c435ba4f"
 dependencies = [
- "thiserror-impl 2.0.19",
+ "thiserror-impl 2.0.20",
 ]
 
 [[package]]
@@ -1160,9 +1179,9 @@
 
 [[package]]
 name = "thiserror-impl"
-version = "2.0.19"
+version = "2.0.20"
 source = "registry+https://github.com/rust-lang/crates.io-index";
-checksum = "43cbfe0cf76104d42a574802844187e84a305e531ed54455f11fbde0f10541cd"
+checksum = "bc04cd3e1236dd4a98afca4569f2deb3f120e5422a4023be2cb683f8486292af"
 dependencies = [
  "proc-macro2",
  "quote",
@@ -1192,9 +1211,9 @@
 
 [[package]]
 name = "tree-sitter"
-version = "0.26.11"
+version = "0.26.12"
 source = "registry+https://github.com/rust-lang/crates.io-index";
-checksum = "af1c71c1c4cc0920b20d6b0f6572e7682cd07a6a2faec71067a31fa394c586df"
+checksum = "83c567a8e18ae93f20982c90370b16fd24023aeaf52f6052b96957ab253a0fec"
 dependencies = [
  "cc",
  "regex",
@@ -1256,9 +1275,9 @@
 
 [[package]]
 name = "tree-sitter-dart-orchard"
-version = "0.5.0"
+version = "0.6.0"
 source = "registry+https://github.com/rust-lang/crates.io-index";
-checksum = "26a7282fbb2427b043d84368ff62d54e098e93f47a0bede90c75db7c08f315b4"
+checksum = "5e9e47f28354ae26b1ecfe2b2baa157e5145665d78838fe189008e921c0971eb"
 dependencies = [
  "cc",
  "tree-sitter-language",
@@ -1386,9 +1405,9 @@
 
 [[package]]
 name = "tree-sitter-java-orchard"
-version = "0.5.10"
+version = "0.5.15"
 source = "registry+https://github.com/rust-lang/crates.io-index";
-checksum = "4cc3d047c3a4ebc4f59ef396031db2b82552aa4d1016c5697c5d611b7bd2e6b6"
+checksum = "d653f4d9f16496ec19de6bcb7b7688d3f6b203c9c0af979bd5294fc058a3e16f"
 dependencies = [
  "cc",
  "tree-sitter-language",
@@ -1562,9 +1581,9 @@
 
 [[package]]
 name = "tree-sitter-scala"
-version = "0.26.0"
+version = "0.26.2"
 source = "registry+https://github.com/rust-lang/crates.io-index";
-checksum = "de5a4a7ff23a55474ce6a741d52aaeca7a82fe9421bb982b86e98c6ac8629397"
+checksum = "24e0ab4505990bfe30051761d40a7bf4033ce5a81c9eda9e20e987a5cdc84826"
 dependencies = [
  "cc",
  "tree-sitter-language",
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/mergiraf-0.19.0/Cargo.toml 
new/mergiraf-0.19.1/Cargo.toml
--- old/mergiraf-0.19.0/Cargo.toml      2026-08-16 17:58:44.000000000 +0200
+++ new/mergiraf-0.19.1/Cargo.toml      2026-09-01 10:50:21.000000000 +0200
@@ -11,7 +11,7 @@
 
 [package]
 name = "mergiraf"
-version = "0.19.0"
+version = "0.19.1"
 edition = "2024"
 license = "GPL-3.0-only"
 repository = "https://codeberg.org/mergiraf/mergiraf";
@@ -44,7 +44,7 @@
 tree-sitter-go = "0.25"
 tree-sitter-gomod-orchard = "0.5"
 tree-sitter-gosum-orchard = "0.3"
-tree-sitter-dart-orchard = "0.5"
+tree-sitter-dart-orchard = "0.6"
 tree-sitter-typescript = "0.23"
 tree-sitter-python-orchard = "0.4"
 tree-sitter-php = "0.24"
@@ -103,6 +103,7 @@
 insta = { version = "1.43", default-features = false, features = ["colors"] }
 pretty_assertions = "1.4.1"
 assert_cmd = { version = "2.2.0", features = ["color"] }
+predicates = "3.1.4"
 
 [features]
 dev = ["dep:tempfile"]
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/mergiraf-0.19.0/src/attempts.rs 
new/mergiraf-0.19.1/src/attempts.rs
--- old/mergiraf-0.19.0/src/attempts.rs 2026-08-16 17:58:44.000000000 +0200
+++ new/mergiraf-0.19.1/src/attempts.rs 2026-09-01 10:50:21.000000000 +0200
@@ -91,7 +91,7 @@
                     app_name: "Mergiraf".to_owned(),
                 })
                 .ok();
-                strategy.map(|project_dir| 
project_dir.data_dir().clone().join(ATTEMPTS_DIRECTORY))
+                strategy.map(|project_dir| 
project_dir.in_data_dir(ATTEMPTS_DIRECTORY))
             })
             .ok_or_else(|| {
                 "Could not determine a suitable application data directory to 
store merge attempts"
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/mergiraf-0.19.0/src/lib.rs 
new/mergiraf-0.19.1/src/lib.rs
--- old/mergiraf-0.19.0/src/lib.rs      2026-08-16 17:58:44.000000000 +0200
+++ new/mergiraf-0.19.1/src/lib.rs      2026-09-01 10:50:21.000000000 +0200
@@ -68,14 +68,14 @@
 /// ```
 pub const ENABLING_ENV_VAR: &str = "mergiraf";
 
-pub const EXIT_SUCCESS: i32 = 0;
+pub const EXIT_SUCCESS: u8 = 0;
 
 // Exit code for merge sub command
-pub const EXIT_MERGE_HAS_CONFLICTS: i32 = 1;
+pub const EXIT_MERGE_HAS_CONFLICTS: u8 = 1;
 
 //Exit code for solve sub command
-pub const EXIT_SOLVE_FAILED: i32 = 1;
-pub const EXIT_SOLVE_HAS_CONFLICTS: i32 = 2;
+pub const EXIT_SOLVE_FAILED: u8 = 1;
+pub const EXIT_SOLVE_HAS_CONFLICTS: u8 = 2;
 
 pub use merge::line_merge_and_structured_resolution;
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/mergiraf-0.19.0/src/main.rs 
new/mergiraf-0.19.1/src/main.rs
--- old/mergiraf-0.19.0/src/main.rs     2026-08-16 17:58:44.000000000 +0200
+++ new/mergiraf-0.19.1/src/main.rs     2026-09-01 10:50:21.000000000 +0200
@@ -1,13 +1,13 @@
 use std::{
     borrow::Cow,
-    env, fs, io,
+    env, fs,
     path::{Path, PathBuf},
-    process::{Command, exit},
+    process::{Command, ExitCode},
     time::Duration,
 };
 
 use clap::{ArgAction, Args, Parser, Subcommand};
-use log::warn;
+use log::{error, warn};
 use mergiraf::{
     ENABLING_ENV_VAR, EXIT_MERGE_HAS_CONFLICTS, EXIT_SOLVE_FAILED, 
EXIT_SOLVE_HAS_CONFLICTS,
     EXIT_SUCCESS,
@@ -17,7 +17,7 @@
     newline::{imitate_newline_style, infer_newline_style, normalize_to_lf},
     settings::{ConflictRegexes, DisplaySettings},
     solve,
-    utils::{read_file_to_string, write_string_to_file},
+    utils::{buffer_is_binary, read_file, read_file_to_string, 
write_string_to_file},
 };
 
 /// Syntax-aware merge driver for Git.
@@ -140,7 +140,17 @@
     },
 }
 
-fn main() {
+#[derive(thiserror::Error, Debug)]
+pub enum CliError {
+    #[error("`git merge-file` returned exit code {exit_code}")]
+    GitMergeFile { exit_code: i32 },
+    #[error("IO error: {0}")]
+    Io(#[from] std::io::Error),
+    #[error("{0}")]
+    Other(String),
+}
+
+fn main() -> ExitCode {
     let args = CliArgs::parse();
 
     stderrlog::new()
@@ -150,15 +160,19 @@
         .unwrap();
 
     match real_main(args) {
-        Ok(exit_code) => exit(exit_code),
+        Ok(exit_code) => exit_code,
+        // If we got an internal error from `git merge-file`, we translate that
+        // to a conflicted merge, so that we don't abort the overall merge.
+        // See https://codeberg.org/mergiraf/mergiraf/issues/812.
+        Err(CliError::GitMergeFile { .. }) => 
ExitCode::from(EXIT_MERGE_HAS_CONFLICTS),
         Err(error) => {
             eprintln!("Mergiraf: {error}");
-            exit(-1)
+            ExitCode::from(255)
         }
     }
 }
 
-fn real_main(args: CliArgs) -> Result<i32, String> {
+fn real_main(args: CliArgs) -> Result<ExitCode, CliError> {
     let return_code = match args.command {
         CliCommand::Merge {
             base,
@@ -215,38 +229,51 @@
                 let mergiraf_disabled = env::var(ENABLING_ENV_VAR).as_deref() 
== Ok("0");
 
                 if mergiraf_disabled {
-                    return fallback_to_git_merge_file(base, left, right, git, 
&output, &settings)
-                        .map_err(|e| format!("error when calling 
git-merge-file: {e}"));
+                    return fallback_to_git_merge_file(base, left, right, git, 
&output, &settings);
                 }
             }
 
             if let Some(debug_dir) = debug_dir {
-                fs::create_dir_all(debug_dir)
-                    .map_err(|err| format!("could not create the debug 
directory: {err}"))?;
+                fs::create_dir_all(debug_dir).map_err(|err| {
+                    CliError::Other(format!("could not create the debug 
directory: {err}"))
+                })?;
             }
 
             let fname_base = &*base;
             let fname_left = &*left;
             let fname_right = &*right;
 
+            let original_contents_base = 
read_file(fname_base).map_err(CliError::Other)?;
+            let original_contents_left = 
read_file(fname_left).map_err(CliError::Other)?;
+            let original_contents_right = 
read_file(fname_right).map_err(CliError::Other)?;
+
+            if [
+                &*original_contents_base,
+                &*original_contents_left,
+                &*original_contents_base,
+            ]
+            .into_iter()
+            .any(buffer_is_binary)
+            {
+                // Don't `return Err` here, as that would make `main` exit 
with 255, which would
+                // abort the overall merge. See 
https://codeberg.org/mergiraf/mergiraf/pulls/81
+                error!("cannot merge binary files");
+                return Ok(ExitCode::from(EXIT_MERGE_HAS_CONFLICTS));
+            }
+
             let (
                 Ok(original_contents_base),
                 Ok(original_contents_left),
                 Ok(original_contents_right),
             ) = (
-                read_file_to_string(fname_base),
-                read_file_to_string(fname_left),
-                read_file_to_string(fname_right),
+                String::from_utf8(original_contents_base),
+                String::from_utf8(original_contents_left),
+                String::from_utf8(original_contents_right),
             )
             else {
-                // The case we're actually catching here is an input file 
being non-UTF-8.
-                //
-                // The way this is currently implemented, this will also catch 
IO errors
-                // like a file not being present etc. -- but that's okay, 
since in that case
-                // the output of `git merge-file` is comparable to what we 
would've emitted
-                // (debug representation of `io::Error`)
-                return fallback_to_git_merge_file(base, left, right, git, 
&output, &settings)
-                    .map_err(|e| format!("error when calling git-merge-file: 
{e}"));
+                // if you change this warning message, update 
`misc::test_git_merge_file_fallback_on_files`
+                warn!("input files are not UTF-8, falling back to Git");
+                return fallback_to_git_merge_file(base, left, right, git, 
&output, &settings);
             };
 
             {
@@ -268,8 +295,7 @@
                         warn!("{side} side contains conflict markers, falling 
back to Git");
                         return fallback_to_git_merge_file(
                             base, left, right, git, &output, &settings,
-                        )
-                        .map_err(|e| format!("error when calling 
git-merge-file: {e}"));
+                        );
                     }
                 }
             }
@@ -305,9 +331,11 @@
             merge_result.contents =
                 imitate_newline_style(&merge_result.contents, 
original_newline_style);
             if let Some(fname_out) = output {
-                write_string_to_file(&fname_out, &merge_result.contents)?;
+                write_string_to_file(&fname_out, &merge_result.contents)
+                    .map_err(CliError::Other)?;
             } else if git {
-                write_string_to_file(fname_left, &merge_result.contents)?;
+                write_string_to_file(fname_left, &merge_result.contents)
+                    .map_err(CliError::Other)?;
             } else {
                 print!("{}", merge_result.contents);
             }
@@ -337,13 +365,15 @@
             keep_backup,
         } => {
             if let Some(debug_dir) = &debug_dir {
-                fs::create_dir_all(debug_dir)
-                    .map_err(|err| format!("could not create the debug 
directory: {err}"))?;
+                fs::create_dir_all(debug_dir).map_err(|err| {
+                    CliError::Other(format!("could not create the debug 
directory: {err}"))
+                })?;
             }
 
             // Unlike `mergiraf merge`, there is no `git merge-file` we can 
fall back on in case of
             // non-UTF-8 input, so just bail out.
-            let original_conflict_contents = 
read_file_to_string(&fname_conflicts)?;
+            let original_conflict_contents =
+                
read_file_to_string(&fname_conflicts).map_err(CliError::Other)?;
 
             if file_seems_to_have_a_jj_conflict(&fname_conflicts, 
&original_conflict_contents) {
                 // Our current logger doesn't handle multiline messages well, 
so we split them manually.
@@ -385,12 +415,14 @@
                     if stdout {
                         print!("{}", merged.contents);
                     } else {
-                        write_string_to_file(&fname_conflicts, 
&merged.contents)?;
+                        write_string_to_file(&fname_conflicts, 
&merged.contents)
+                            .map_err(CliError::Other)?;
                         if keep_backup {
                             write_string_to_file(
                                 fname_conflicts.with_added_extension("orig"),
                                 &original_conflict_contents,
-                            )?;
+                            )
+                            .map_err(CliError::Other)?;
                         }
                     };
                     if merged.conflict_count > 0 {
@@ -406,8 +438,10 @@
             }
         }
         CliCommand::Review { merge_id } => {
-            let attempts_cache = AttemptsCache::new(None, None)?;
-            attempts_cache.review_merge(&merge_id)?;
+            let attempts_cache = AttemptsCache::new(None, 
None).map_err(CliError::Other)?;
+            attempts_cache
+                .review_merge(&merge_id)
+                .map_err(CliError::Other)?;
             EXIT_SUCCESS
         }
         CliCommand::Languages { gitattributes } => {
@@ -416,11 +450,11 @@
             EXIT_SUCCESS
         }
         CliCommand::Report { merge_id_or_file } => {
-            report_bug(&merge_id_or_file)?;
+            report_bug(&merge_id_or_file).map_err(CliError::Other)?;
             EXIT_SUCCESS
         }
     };
-    Ok(return_code)
+    Ok(ExitCode::from(return_code))
 }
 
 fn fallback_to_git_merge_file(
@@ -430,7 +464,7 @@
     git: bool,
     output: &Option<PathBuf>,
     settings: &DisplaySettings,
-) -> io::Result<i32> {
+) -> Result<ExitCode, CliError> {
     let mut command = Command::new("git");
     command.arg("merge-file").arg("--diff-algorithm=histogram");
     if !git {
@@ -460,7 +494,19 @@
     } else {
         command.spawn()?.wait()?
     };
-    Ok(code.code().unwrap_or(0))
+    let code = code.code().unwrap_or(0);
+    if code >= 128 {
+        Err(CliError::GitMergeFile { exit_code: code })
+    } else {
+        // we cannot return the exact same exit code as Git returned to us,
+        // because Rust exposes that to us as an i32 and we need to return an
+        // ExitCode (u8), so we map all other errors to 1 (signalling a 
conflict state)
+        Ok(ExitCode::from(if code == 0 {
+            EXIT_SUCCESS
+        } else {
+            EXIT_MERGE_HAS_CONFLICTS
+        }))
+    }
 }
 
 /// Check if user is using Jujutsu instead of Git, which can lead to issues 
when running
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/mergiraf-0.19.0/src/snapshots/mergiraf__supported_langs__test__children_of_commutative_parents_have_sigs.snap
 
new/mergiraf-0.19.1/src/snapshots/mergiraf__supported_langs__test__children_of_commutative_parents_have_sigs.snap
--- 
old/mergiraf-0.19.0/src/snapshots/mergiraf__supported_langs__test__children_of_commutative_parents_have_sigs.snap
   2026-08-16 17:58:44.000000000 +0200
+++ 
new/mergiraf-0.19.1/src/snapshots/mergiraf__supported_langs__test__children_of_commutative_parents_have_sigs.snap
   2026-09-01 10:50:21.000000000 +0200
@@ -11,9 +11,6 @@
     "C#: child `property_declaration` of commutative parent 'declaration_list' 
doesn't have a signature defined",
     "Go: child `literal_element` of commutative parent 'literal_value' doesn't 
have a signature defined",
     "Java: child `type_identifier` of commutative parent 'throws' doesn't have 
a signature defined",
-    "Kotlin: child `inheritance_modifier` of commutative parent 'modifiers' 
doesn't have a signature defined",
-    "Kotlin: child `member_modifier` of commutative parent 'modifiers' doesn't 
have a signature defined",
-    "Kotlin: child `visibility_modifier` of commutative parent 'modifiers' 
doesn't have a signature defined",
     "Markdown: child `link_reference_definition` of commutative parent 
'section' doesn't have a signature defined",
     "PHP: child `use_declaration` of commutative parent 'declaration_list' 
doesn't have a signature defined",
     "Python: child `import_statement` of commutative parent 'module' doesn't 
have a signature defined",
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/mergiraf-0.19.0/src/supported_langs.rs 
new/mergiraf-0.19.1/src/supported_langs.rs
--- old/mergiraf-0.19.0/src/supported_langs.rs  2026-08-16 17:58:44.000000000 
+0200
+++ new/mergiraf-0.19.1/src/supported_langs.rs  2026-09-01 10:50:21.000000000 
+0200
@@ -262,14 +262,9 @@
                 signature("delegation_specifier", vec![vec![]]),
                 // modifiers
                 signature("annotation", vec![vec![]]), // annotations can be 
repeatable, so we can't use the name as key
-                signature("public", vec![vec![]]),
-                signature("protected", vec![vec![]]),
-                signature("private", vec![vec![]]),
-                signature("internal", vec![vec![]]),
-                signature("final", vec![vec![]]),
-                signature("open", vec![vec![]]),
-                signature("abstract", vec![vec![]]),
-                signature("override", vec![vec![]]),
+                signature("visibility_modifier", vec![]), // a single 
visibility modifier is allowed on any given item
+                signature("inheritance_modifier", vec![]), // a single 
visibility modifier is allowed on any given item
+                signature("member_modifier", vec![vec![]]), // potentially 
multiple member modifiers on the same element, but all distinct
             ],
             injections: None,
             flattened_nodes: &[],
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/mergiraf-0.19.0/src/utils.rs 
new/mergiraf-0.19.1/src/utils.rs
--- old/mergiraf-0.19.0/src/utils.rs    2026-08-16 17:58:44.000000000 +0200
+++ new/mergiraf-0.19.1/src/utils.rs    2026-09-01 10:50:21.000000000 +0200
@@ -1,6 +1,12 @@
+use std::cmp::min;
 use std::error::Error;
 use std::{fs, path::Path};
 
+pub fn read_file(path: impl AsRef<Path>) -> Result<Vec<u8>, String> {
+    let path = path.as_ref();
+    fs::read(path).map_err(|err| format!("Could not read '{}': {err}", 
path.display()))
+}
+
 pub fn read_file_to_string(path: impl AsRef<Path>) -> Result<String, String> {
     let path = path.as_ref();
     fs::read_to_string(path).map_err(|err| format!("Could not read '{}': 
{err}", path.display()))
@@ -44,3 +50,22 @@
         }
     }
 }
+
+// Stolen from 
https://git.kernel.org/pub/scm/git/git.git/tree/xdiff-interface.c?commit=db6938689f0a9ef5a9d630e8614d7f807758ff39#n197
+pub fn buffer_is_binary(buf: &[u8]) -> bool {
+    const FIRST_FEW_BYTES: usize = 8000;
+    buf[..min(buf.len(), FIRST_FEW_BYTES)].contains(&0)
+}
+
+#[cfg(test)]
+mod tests {
+    #[test]
+    #[allow(
+        clippy::bool_assert_comparison,
+        reason = "the suggestion makes it easy to miss the `!`"
+    )]
+    fn buffer_is_binary() {
+        assert_eq!(super::buffer_is_binary(b"\0\xff\0"), true);
+        assert_eq!(super::buffer_is_binary(b"I'm non-binary"), false);
+    }
+}
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/mergiraf-0.19.0/tests/common/mod.rs 
new/mergiraf-0.19.1/tests/common/mod.rs
--- old/mergiraf-0.19.0/tests/common/mod.rs     2026-08-16 17:58:44.000000000 
+0200
+++ new/mergiraf-0.19.1/tests/common/mod.rs     2026-09-01 10:50:21.000000000 
+0200
@@ -3,7 +3,7 @@
 use core::str;
 use std::fs::{self, read_to_string};
 use std::path::{Path, PathBuf};
-use std::process::Command;
+use std::process::{Command, Output};
 
 use assert_cmd::{pkg_name, prelude::*};
 use itertools::Itertools;
@@ -12,15 +12,9 @@
 pub const DEFAULT_FILE_FOR_SOLVE: &str =
     "<<<<<<< LEFT\n[1, 2, 3, 4]\n||||||| BASE\n[1, 2, 3]\n=======\n[0, 1, 2, 
3]\n>>>>>>> RIGHT\n";
 
-pub(crate) fn run_git(args: &[&str], repo_dir: &Path) {
+pub(crate) fn run_git(args: &[&str], repo_dir: &Path) -> Output {
     let command_str = format!("git {}", args.iter().format(" "));
-    let mut command = Command::new("git");
-    command.current_dir(repo_dir);
-    command.args(args);
-    // Run using a minimal environment to isolate the test better.
-    command
-        .env_clear()
-        .envs(std::env::vars().filter(|(var, _)| var == "PATH"));
+    let mut command = git_command(args, repo_dir);
     let output = command.output().expect("Failed to execute git command");
     if !output.status.success() {
         panic!(
@@ -28,6 +22,39 @@
             str::from_utf8(&output.stdout).unwrap()
         );
     }
+    output
+}
+
+pub(crate) fn git_command(args: &[&str], repo_dir: &Path) -> Command {
+    let mut command = Command::new("git");
+    command.current_dir(repo_dir);
+    command.args(args);
+    // Run using a minimal environment to isolate the test better.
+    command
+        .env_clear()
+        .envs(std::env::vars().filter(|(var, _)| var == "PATH"));
+    command
+}
+
+/// Given a path to a repo, set up mergiraf as merge driver
+pub(crate) fn setup_mergiraf(repo_path: &Path) {
+    let mergiraf_command = Command::cargo_bin(pkg_name!()).unwrap();
+    let mergiraf_binary = mergiraf_command.get_program().to_string_lossy();
+
+    run_git(&["config", "user.email", "[email protected]"], repo_path);
+    run_git(&["config", "user.name", "Test User"], repo_path);
+    run_git(&["config", "merge.mergiraf.name", "mergiraf"], repo_path);
+    run_git(
+        &[
+            "config",
+            "merge.mergiraf.driver",
+            &format!("{mergiraf_binary} merge --git %O %A %B -s %S -x %X -y %Y 
-p %P -l %L"),
+        ],
+        repo_path,
+    );
+
+    fs::write(repo_path.join(".git/info/attributes"), "* merge=mergiraf\n")
+        .expect("failed to write .gitattributes");
 }
 
 pub(crate) fn write_file_from_rev(
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/mergiraf-0.19.0/tests/data/kotlin/failing/function_modifiers/Base.kt 
new/mergiraf-0.19.1/tests/data/kotlin/failing/function_modifiers/Base.kt
--- old/mergiraf-0.19.0/tests/data/kotlin/failing/function_modifiers/Base.kt    
1970-01-01 01:00:00.000000000 +0100
+++ new/mergiraf-0.19.1/tests/data/kotlin/failing/function_modifiers/Base.kt    
2026-09-01 10:50:21.000000000 +0200
@@ -0,0 +1,5 @@
+object Recipe {
+    override fun demonstrate() {
+        LOGGER.info { "Demo time!" }
+    }
+}
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/mergiraf-0.19.0/tests/data/kotlin/failing/function_modifiers/ExpectedCurrently.kt
 
new/mergiraf-0.19.1/tests/data/kotlin/failing/function_modifiers/ExpectedCurrently.kt
--- 
old/mergiraf-0.19.0/tests/data/kotlin/failing/function_modifiers/ExpectedCurrently.kt
       1970-01-01 01:00:00.000000000 +0100
+++ 
new/mergiraf-0.19.1/tests/data/kotlin/failing/function_modifiers/ExpectedCurrently.kt
       2026-09-01 10:50:21.000000000 +0200
@@ -0,0 +1,11 @@
+object Recipe {
+<<<<<<< LEFT
+    override final fun demonstrate() {
+||||||| BASE
+    override  fun demonstrate() {
+=======
+    override protected fun demonstrate() {
+>>>>>>> RIGHT
+        LOGGER.info { "Demo time!" }
+    }
+}
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/mergiraf-0.19.0/tests/data/kotlin/failing/function_modifiers/ExpectedIdeally.kt
 
new/mergiraf-0.19.1/tests/data/kotlin/failing/function_modifiers/ExpectedIdeally.kt
--- 
old/mergiraf-0.19.0/tests/data/kotlin/failing/function_modifiers/ExpectedIdeally.kt
 1970-01-01 01:00:00.000000000 +0100
+++ 
new/mergiraf-0.19.1/tests/data/kotlin/failing/function_modifiers/ExpectedIdeally.kt
 2026-09-01 10:50:21.000000000 +0200
@@ -0,0 +1,11 @@
+object Recipe {
+<<<<<<< LEFT
+    override final fun demonstrate() {
+||||||| BASE
+    override fun demonstrate() {
+=======
+    override protected fun demonstrate() {
+>>>>>>> RIGHT
+        LOGGER.info { "Demo time!" }
+    }
+}
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/mergiraf-0.19.0/tests/data/kotlin/failing/function_modifiers/Left.kt 
new/mergiraf-0.19.1/tests/data/kotlin/failing/function_modifiers/Left.kt
--- old/mergiraf-0.19.0/tests/data/kotlin/failing/function_modifiers/Left.kt    
1970-01-01 01:00:00.000000000 +0100
+++ new/mergiraf-0.19.1/tests/data/kotlin/failing/function_modifiers/Left.kt    
2026-09-01 10:50:21.000000000 +0200
@@ -0,0 +1,5 @@
+object Recipe {
+    override final fun demonstrate() {
+        LOGGER.info { "Demo time!" }
+    }
+}
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/mergiraf-0.19.0/tests/data/kotlin/failing/function_modifiers/Right.kt 
new/mergiraf-0.19.1/tests/data/kotlin/failing/function_modifiers/Right.kt
--- old/mergiraf-0.19.0/tests/data/kotlin/failing/function_modifiers/Right.kt   
1970-01-01 01:00:00.000000000 +0100
+++ new/mergiraf-0.19.1/tests/data/kotlin/failing/function_modifiers/Right.kt   
2026-09-01 10:50:21.000000000 +0200
@@ -0,0 +1,5 @@
+object Recipe {
+    override protected fun demonstrate() {
+        LOGGER.info { "Demo time!" }
+    }
+}
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/mergiraf-0.19.0/tests/data/kotlin/working/conflicting_inheritance_modifiers/Base.kt
 
new/mergiraf-0.19.1/tests/data/kotlin/working/conflicting_inheritance_modifiers/Base.kt
--- 
old/mergiraf-0.19.0/tests/data/kotlin/working/conflicting_inheritance_modifiers/Base.kt
     1970-01-01 01:00:00.000000000 +0100
+++ 
new/mergiraf-0.19.1/tests/data/kotlin/working/conflicting_inheritance_modifiers/Base.kt
     2026-09-01 10:50:21.000000000 +0200
@@ -0,0 +1,2 @@
+class Recipe {
+}
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/mergiraf-0.19.0/tests/data/kotlin/working/conflicting_inheritance_modifiers/Expected.kt
 
new/mergiraf-0.19.1/tests/data/kotlin/working/conflicting_inheritance_modifiers/Expected.kt
--- 
old/mergiraf-0.19.0/tests/data/kotlin/working/conflicting_inheritance_modifiers/Expected.kt
 1970-01-01 01:00:00.000000000 +0100
+++ 
new/mergiraf-0.19.1/tests/data/kotlin/working/conflicting_inheritance_modifiers/Expected.kt
 2026-09-01 10:50:21.000000000 +0200
@@ -0,0 +1,8 @@
+<<<<<<< LEFT
+open class Recipe {
+||||||| BASE
+class Recipe {
+=======
+final class Recipe {
+>>>>>>> RIGHT
+}
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/mergiraf-0.19.0/tests/data/kotlin/working/conflicting_inheritance_modifiers/Left.kt
 
new/mergiraf-0.19.1/tests/data/kotlin/working/conflicting_inheritance_modifiers/Left.kt
--- 
old/mergiraf-0.19.0/tests/data/kotlin/working/conflicting_inheritance_modifiers/Left.kt
     1970-01-01 01:00:00.000000000 +0100
+++ 
new/mergiraf-0.19.1/tests/data/kotlin/working/conflicting_inheritance_modifiers/Left.kt
     2026-09-01 10:50:21.000000000 +0200
@@ -0,0 +1,2 @@
+open class Recipe {
+}
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/mergiraf-0.19.0/tests/data/kotlin/working/conflicting_inheritance_modifiers/Right.kt
 
new/mergiraf-0.19.1/tests/data/kotlin/working/conflicting_inheritance_modifiers/Right.kt
--- 
old/mergiraf-0.19.0/tests/data/kotlin/working/conflicting_inheritance_modifiers/Right.kt
    1970-01-01 01:00:00.000000000 +0100
+++ 
new/mergiraf-0.19.1/tests/data/kotlin/working/conflicting_inheritance_modifiers/Right.kt
    2026-09-01 10:50:21.000000000 +0200
@@ -0,0 +1,2 @@
+final class Recipe {
+}
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/mergiraf-0.19.0/tests/data/kotlin/working/conflicting_visibility_modifier/Base.kt
 
new/mergiraf-0.19.1/tests/data/kotlin/working/conflicting_visibility_modifier/Base.kt
--- 
old/mergiraf-0.19.0/tests/data/kotlin/working/conflicting_visibility_modifier/Base.kt
       1970-01-01 01:00:00.000000000 +0100
+++ 
new/mergiraf-0.19.1/tests/data/kotlin/working/conflicting_visibility_modifier/Base.kt
       2026-09-01 10:50:21.000000000 +0200
@@ -0,0 +1,5 @@
+object DungeonFinderFeatures {
+
+    fun onInventoryOpen() {
+    }
+}
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/mergiraf-0.19.0/tests/data/kotlin/working/conflicting_visibility_modifier/Expected.kt
 
new/mergiraf-0.19.1/tests/data/kotlin/working/conflicting_visibility_modifier/Expected.kt
--- 
old/mergiraf-0.19.0/tests/data/kotlin/working/conflicting_visibility_modifier/Expected.kt
   1970-01-01 01:00:00.000000000 +0100
+++ 
new/mergiraf-0.19.1/tests/data/kotlin/working/conflicting_visibility_modifier/Expected.kt
   2026-09-01 10:50:21.000000000 +0200
@@ -0,0 +1,11 @@
+object DungeonFinderFeatures {
+
+<<<<<<< LEFT
+    public fun onInventoryOpen() {
+||||||| BASE
+    fun onInventoryOpen() {
+=======
+    private fun onInventoryOpen() {
+>>>>>>> RIGHT
+    }
+}
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/mergiraf-0.19.0/tests/data/kotlin/working/conflicting_visibility_modifier/Left.kt
 
new/mergiraf-0.19.1/tests/data/kotlin/working/conflicting_visibility_modifier/Left.kt
--- 
old/mergiraf-0.19.0/tests/data/kotlin/working/conflicting_visibility_modifier/Left.kt
       1970-01-01 01:00:00.000000000 +0100
+++ 
new/mergiraf-0.19.1/tests/data/kotlin/working/conflicting_visibility_modifier/Left.kt
       2026-09-01 10:50:21.000000000 +0200
@@ -0,0 +1,5 @@
+object DungeonFinderFeatures {
+
+    public fun onInventoryOpen() {
+    }
+}
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/mergiraf-0.19.0/tests/data/kotlin/working/conflicting_visibility_modifier/Right.kt
 
new/mergiraf-0.19.1/tests/data/kotlin/working/conflicting_visibility_modifier/Right.kt
--- 
old/mergiraf-0.19.0/tests/data/kotlin/working/conflicting_visibility_modifier/Right.kt
      1970-01-01 01:00:00.000000000 +0100
+++ 
new/mergiraf-0.19.1/tests/data/kotlin/working/conflicting_visibility_modifier/Right.kt
      2026-09-01 10:50:21.000000000 +0200
@@ -0,0 +1,5 @@
+object DungeonFinderFeatures {
+
+    private fun onInventoryOpen() {
+    }
+}
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/mergiraf-0.19.0/tests/data/kotlin/working/duplicate_visibility_modifier/Base.kt
 
new/mergiraf-0.19.1/tests/data/kotlin/working/duplicate_visibility_modifier/Base.kt
--- 
old/mergiraf-0.19.0/tests/data/kotlin/working/duplicate_visibility_modifier/Base.kt
 1970-01-01 01:00:00.000000000 +0100
+++ 
new/mergiraf-0.19.1/tests/data/kotlin/working/duplicate_visibility_modifier/Base.kt
 2026-09-01 10:50:21.000000000 +0200
@@ -0,0 +1,8 @@
+object DungeonFinderFeatures {
+
+    @HandleEvent(onlyOnSkyblock = true) fun onInventoryOpen() {
+        floorStackSize = stackTip(event)
+        highlightParty = highlightingHandler(event)
+        toolTipMap = toolTipHandler(event)
+    }
+}
\ No newline at end of file
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/mergiraf-0.19.0/tests/data/kotlin/working/duplicate_visibility_modifier/Expected.kt
 
new/mergiraf-0.19.1/tests/data/kotlin/working/duplicate_visibility_modifier/Expected.kt
--- 
old/mergiraf-0.19.0/tests/data/kotlin/working/duplicate_visibility_modifier/Expected.kt
     1970-01-01 01:00:00.000000000 +0100
+++ 
new/mergiraf-0.19.1/tests/data/kotlin/working/duplicate_visibility_modifier/Expected.kt
     2026-09-01 10:50:21.000000000 +0200
@@ -0,0 +1,11 @@
+object DungeonFinderFeatures {
+
+    @HandleEvent(onlyOnSkyblock = true)
+    private fun onInventoryOpen() {
+        val inventoryName = event.inventoryName
+        val inventoryItems = event.inventoryItems
+        floorStackSize = stackTip(inventoryName, inventoryItems)
+        highlightParty = highlightingHandler(inventoryName, inventoryItems)
+        toolTipMap = toolTipHandler(inventoryName, inventoryItems)
+    }
+}
\ No newline at end of file
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/mergiraf-0.19.0/tests/data/kotlin/working/duplicate_visibility_modifier/Left.kt
 
new/mergiraf-0.19.1/tests/data/kotlin/working/duplicate_visibility_modifier/Left.kt
--- 
old/mergiraf-0.19.0/tests/data/kotlin/working/duplicate_visibility_modifier/Left.kt
 1970-01-01 01:00:00.000000000 +0100
+++ 
new/mergiraf-0.19.1/tests/data/kotlin/working/duplicate_visibility_modifier/Left.kt
 2026-09-01 10:50:21.000000000 +0200
@@ -0,0 +1,11 @@
+object DungeonFinderFeatures {
+
+    @HandleEvent(onlyOnSkyblock = true)
+    private fun onInventoryOpen() {
+        val inventoryName = event.inventoryName
+        val inventoryItems = event.inventoryItems
+        floorStackSize = stackTip(inventoryName, inventoryItems)
+        highlightParty = highlightingHandler(inventoryName, inventoryItems)
+        toolTipMap = toolTipHandler(inventoryName, inventoryItems)
+    }
+}
\ No newline at end of file
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/mergiraf-0.19.0/tests/data/kotlin/working/duplicate_visibility_modifier/Right.kt
 
new/mergiraf-0.19.1/tests/data/kotlin/working/duplicate_visibility_modifier/Right.kt
--- 
old/mergiraf-0.19.0/tests/data/kotlin/working/duplicate_visibility_modifier/Right.kt
        1970-01-01 01:00:00.000000000 +0100
+++ 
new/mergiraf-0.19.1/tests/data/kotlin/working/duplicate_visibility_modifier/Right.kt
        2026-09-01 10:50:21.000000000 +0200
@@ -0,0 +1,9 @@
+object DungeonFinderFeatures {
+
+    @HandleEvent(onlyOnSkyblock = true)
+    private fun onInventoryOpen() {
+        floorStackSize = stackTip(event)
+        highlightParty = highlightingHandler(event)
+        toolTipMap = toolTipHandler(event)
+    }
+}
\ No newline at end of file
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/mergiraf-0.19.0/tests/data/kotlin/working/function_modifiers/Base.kt 
new/mergiraf-0.19.1/tests/data/kotlin/working/function_modifiers/Base.kt
--- old/mergiraf-0.19.0/tests/data/kotlin/working/function_modifiers/Base.kt    
2026-08-16 17:58:44.000000000 +0200
+++ new/mergiraf-0.19.1/tests/data/kotlin/working/function_modifiers/Base.kt    
1970-01-01 01:00:00.000000000 +0100
@@ -1,5 +0,0 @@
-object Recipe {
-    override fun demonstrate() {
-        LOGGER.info { "Demo time!" }
-    }
-}
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/mergiraf-0.19.0/tests/data/kotlin/working/function_modifiers/Expected.kt 
new/mergiraf-0.19.1/tests/data/kotlin/working/function_modifiers/Expected.kt
--- 
old/mergiraf-0.19.0/tests/data/kotlin/working/function_modifiers/Expected.kt    
    2026-08-16 17:58:44.000000000 +0200
+++ 
new/mergiraf-0.19.1/tests/data/kotlin/working/function_modifiers/Expected.kt    
    1970-01-01 01:00:00.000000000 +0100
@@ -1,5 +0,0 @@
-object Recipe {
-    override final protected fun demonstrate() {
-        LOGGER.info { "Demo time!" }
-    }
-}
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/mergiraf-0.19.0/tests/data/kotlin/working/function_modifiers/Left.kt 
new/mergiraf-0.19.1/tests/data/kotlin/working/function_modifiers/Left.kt
--- old/mergiraf-0.19.0/tests/data/kotlin/working/function_modifiers/Left.kt    
2026-08-16 17:58:44.000000000 +0200
+++ new/mergiraf-0.19.1/tests/data/kotlin/working/function_modifiers/Left.kt    
1970-01-01 01:00:00.000000000 +0100
@@ -1,5 +0,0 @@
-object Recipe {
-    override final fun demonstrate() {
-        LOGGER.info { "Demo time!" }
-    }
-}
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/mergiraf-0.19.0/tests/data/kotlin/working/function_modifiers/Right.kt 
new/mergiraf-0.19.1/tests/data/kotlin/working/function_modifiers/Right.kt
--- old/mergiraf-0.19.0/tests/data/kotlin/working/function_modifiers/Right.kt   
2026-08-16 17:58:44.000000000 +0200
+++ new/mergiraf-0.19.1/tests/data/kotlin/working/function_modifiers/Right.kt   
1970-01-01 01:00:00.000000000 +0100
@@ -1,5 +0,0 @@
-object Recipe {
-    override protected fun demonstrate() {
-        LOGGER.info { "Demo time!" }
-    }
-}
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/mergiraf-0.19.0/tests/misc.rs 
new/mergiraf-0.19.1/tests/misc.rs
--- old/mergiraf-0.19.0/tests/misc.rs   2026-08-16 17:58:44.000000000 +0200
+++ new/mergiraf-0.19.1/tests/misc.rs   2026-09-01 10:50:21.000000000 +0200
@@ -1,10 +1,15 @@
 use assert_cmd::prelude::*;
 use mergiraf::{EXIT_SOLVE_HAS_CONFLICTS, git, utils::write_string_to_file};
+use predicates::prelude::PredicateBooleanExt as _;
+use predicates::str::contains;
 use std::fs;
 use std::path::{Path, PathBuf};
 
 mod common;
-use common::{DEFAULT_FILE_FOR_SOLVE, create_file_for_solve, 
create_files_for_merge, merge, solve};
+use common::{
+    DEFAULT_FILE_FOR_SOLVE, create_file_for_solve, create_files_for_merge, 
git_command, merge,
+    run_git, setup_mergiraf, solve,
+};
 
 #[test]
 fn keep_backup_keeps_backup() {
@@ -360,7 +365,7 @@
         .arg("--language=html")
         .arg("--stdout")
         .assert()
-        .code(EXIT_SOLVE_HAS_CONFLICTS)
+        .code(EXIT_SOLVE_HAS_CONFLICTS as i32)
         .stdout(content);
 }
 
@@ -422,6 +427,55 @@
 }
 
 #[test]
+fn merging_files_with_binary_files_doesnt_abort_whole_merge() {
+    test_git_merge_file_fallback_on_files(false);
+}
+
+#[test]
+fn merging_files_with_disabled_mergiraf_doesnt_abort_whole_merge() {
+    test_git_merge_file_fallback_on_files(true);
+}
+
+fn test_git_merge_file_fallback_on_files(disabled_mergiraf: bool) {
+    let repo_dir = tempfile::tempdir().expect("failed to create the temp dir");
+    let repo_path = repo_dir.path();
+
+    git::init(repo_path);
+    setup_mergiraf(repo_path);
+
+    let contents_base = b"\0\xff\0";
+    let contents_left = b"\0\0\x4a2\xff";
+    let contents_right = b"\x003\0\0";
+
+    fs::write(repo_path.join("tracked_file"), contents_base).unwrap();
+    run_git(&["add", "tracked_file"], repo_path);
+    run_git(&["commit", "-m", "initial"], repo_path);
+    run_git(&["checkout", "-b", "first_branch"], repo_path);
+    fs::write(repo_path.join("tracked_file"), contents_left).unwrap();
+    run_git(&["commit", "-am", "second"], repo_path);
+    run_git(&["checkout", "HEAD~"], repo_path);
+    run_git(&["checkout", "-b", "second_branch"], repo_path);
+    fs::write(repo_path.join("tracked_file"), contents_right).unwrap();
+    run_git(&["commit", "-am", "third"], repo_path);
+    let mut command = git_command(&["merge", "first_branch"], repo_path);
+    if disabled_mergiraf {
+        command.env("mergiraf", "0");
+    }
+    command
+        .assert()
+        .append_context("main", "should fail on binary file conflict")
+        .failure()
+        // we don't assert the full output as it may not be stable between Git 
versions
+        .stderr(contains("WARN input files are not UTF-8, falling back to 
Git").not());
+
+    let output = run_git(&["status", "--porcelain"], repo_path);
+    let stdout = String::from_utf8(output.stdout).unwrap();
+
+    // the tracked file is marked as conflicted in git (meaning that the whole 
merge wasn't aborted)
+    assert!(stdout.contains("UU tracked_file\n"), "stdout={stdout}",);
+}
+
+#[test]
 fn jj() {
     let repo_dir = tempfile::tempdir().expect("failed to create the temp dir");
     let repo_path = repo_dir.path();

++++++ mergiraf.obsinfo ++++++
--- /var/tmp/diff_new_pack.anfPkC/_old  2026-09-01 15:52:38.763735278 +0200
+++ /var/tmp/diff_new_pack.anfPkC/_new  2026-09-01 15:52:38.770735522 +0200
@@ -1,5 +1,5 @@
 name: mergiraf
-version: 0.19.0
-mtime: 1786895924
-commit: 7246b03c08c02248035bc20668fde1edf94a09e0
+version: 0.19.1
+mtime: 1788252621
+commit: e1c6514fb364faca51132be2b336aa739cdfadb9
 

++++++ vendor.tar.zst ++++++
/work/SRC/openSUSE:Factory/mergiraf/vendor.tar.zst 
/work/SRC/openSUSE:Factory/.mergiraf.new.1265/vendor.tar.zst differ: char 7, 
line 1

Reply via email to