jdx/mise · error

git merge-file failed: {}

Error message

git merge-file failed: {}

What it means

`git merge-file` exit status encodes the number of conflicts as a positive code, and success is 0. A negative code (or None) means the process itself failed — it was killed by a signal or never ran — rather than reporting merge conflicts. The tool treats conflicts (positive codes) as a normal 'no clean merge' result, but a negative code is an infrastructure failure, so it bails with git's stderr.

Source

Thrown at src/system/history/shadow.rs:1370

        std::fs::write(&t, theirs)?;
        let output = self.git.output_unchecked(PlumbingCall::new([
            "merge-file",
            "-p",
            "-L",
            "local",
            "-L",
            "base",
            "-L",
            "remote",
            &o.to_string_lossy(),
            &b.to_string_lossy(),
            &t.to_string_lossy(),
        ]))?;
        // exit status is the number of conflicts; negative on error
        match output.status.code() {
            Some(0) => Ok(Some(output.stdout)),
            Some(code) if code > 0 => Ok(None),
            _ => bail!(
                "git merge-file failed: {}",
                String::from_utf8_lossy(&output.stderr).trim()
            ),
        }
    }

    /// Runs a network command with the user's git configuration.
    pub(crate) fn network<'a>(
        &self,
        args: impl IntoIterator<Item = &'a str>,
    ) -> Result<std::process::Output> {
        self.git.network_output(PlumbingCall::new(args))
    }

    const ANNOTATION_TRAILER: &'static str = "Mise-Annotation: ";

    /// An annotation is an empty ordinary child commit, so labels and
    /// descriptions travel with the same ancestry without rewriting it.

View on GitHub (pinned to afd2eddd3a)

Solutions

  1. Run `git merge-file <ours> <base> <theirs>` manually on the reported files and observe the failure.
  2. Verify `git --version` works and that the temp directory is writable.
  3. Check for signal kills (OOM killer, AV interference) in system logs around the failure time.
  4. Re-run the dotfile sync; if persistent, reinstall or repair the system git.
Defensive patterns

Strategy: try-catch

Validate before calling

for f in [ours, base, theirs] {
    assert!(Path::new(f).exists(), "merge-file input {f} missing");
}

Try / catch

match history.three_way_merge(ours, base, theirs) {
    Ok(Some(out)) => write_clean(out),
    Ok(None) => prompt_manual_conflict_resolution(),
    Err(e) if e.to_string().contains("git merge-file failed") => {
        eprintln!("merge-file process failed (signal/IO): {e}");
        fallback_to_manual_merge()?;
    }
    Err(e) => return Err(e),
}

Prevention

When it happens

Trigger: Three-way merging a dotfile when `git merge-file` cannot execute: the temp file paths are missing/unwritable, git is broken, or the child process is killed by a signal (negative exit code from a signal death).

Common situations: Antivirus or system cleanup deletes temp files mid-operation; a sandboxed/limited environment prevents git from writing temp files; the system git installation is damaged.

Understand the failure class

Background: "git command failed": what it means when a tool shells out to git and git exits non-zero — this error's family across 21 libraries.

Related errors


AI-assisted analysis of jdx/mise@afd2eddd3a (2026-09-09). Data as JSON: /api/errors/0c0468adb51da116. Report an issue: GitHub.