{"record":{"id":"0c0468adb51da116","repo":"jdx/mise","slug":"git-merge-file-failed","errorCode":null,"errorMessage":"git merge-file failed: {}","messagePattern":"git merge-file failed: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src/system/history/shadow.rs","lineNumber":1621,"sourceCode":"        std::fs::write(&t, theirs)?;\n        let output = self.git.output_unchecked(PlumbingCall::new([\n            \"merge-file\",\n            \"-p\",\n            \"-L\",\n            \"local\",\n            \"-L\",\n            \"base\",\n            \"-L\",\n            \"remote\",\n            &o.to_string_lossy(),\n            &b.to_string_lossy(),\n            &t.to_string_lossy(),\n        ]))?;\n        // exit status is the number of conflicts; negative on error\n        match output.status.code() {\n            Some(0) => Ok(Some(output.stdout)),\n            Some(code) if code > 0 => Ok(None),\n            _ => bail!(\n                \"git merge-file failed: {}\",\n                String::from_utf8_lossy(&output.stderr).trim()\n            ),\n        }\n    }\n\n    /// Runs a network command with the user's git configuration.\n    pub(crate) fn network<'a>(\n        &self,\n        args: impl IntoIterator<Item = &'a str>,\n    ) -> Result<std::process::Output> {\n        self.git.network_output(PlumbingCall::new(args))\n    }\n\n    const ANNOTATION_TRAILER: &'static str = \"Mise-Annotation: \";\n\n    /// An annotation is an empty ordinary child commit, so labels and\n    /// descriptions travel with the same ancestry without rewriting it.","sourceCodeStart":1603,"sourceCodeEnd":1639,"githubUrl":"https://github.com/jdx/mise/blob/533346cc374382b41ec5ff70536252b2e96e725c/src/system/history/shadow.rs#L1603-L1639","documentation":"`git merge-file` reports conflicts with a positive exit code and success with 0; a negative code (or no code) means git itself errored — e.g. the binary is missing/broken or arguments are invalid. mise surfaces that condition with the captured stderr. A conflict-free or conflicted-but-valid merge is not an error here.","triggerScenarios":"Three-way merging an individual dotfile via `git merge-file` when the git invocation crashes (negative exit status): broken git installation, unreadable temp file for the file content, or invalid merge arguments.","commonSituations":"Corrupt or half-installed git (e.g. partial upgrade); filesystem errors preventing temp-file creation during merge; SELinux/AV blocking git from writing temp merge files.","solutions":["Read the stderr in the message; if empty, verify `git merge-file --help` works at all.","Reinstall or repair your git installation.","Check free disk space and permissions on the temp directory used for merges.","Retry the dotfile sync after the environment issue is fixed."],"exampleFix":null,"handlingStrategy":"fallback","validationCode":"if std::process::Command::new(\"git\").arg(\"merge-file\").arg(\"--help\").status().is_err() {\n  eprintln!(\"git is not usable; repair installation before syncing dotfiles\");\n}","typeGuard":null,"tryCatchPattern":"match result {\n  Err(e) if e.to_string().contains(\"git merge-file failed\") => {\n    // fall back to leaving the file untouched and surface the git install problem\n  }\n  other => other?,\n}","preventionTips":["Keep git fully installed (verify after upgrades).","Ensure the temp directory is writable and has free space.","Watch for AV/SELinux policies blocking git temp-file writes."],"tags":["git","merge-file","dotfiles","environment"],"backgroundTag":"git-command-failed","analyzedSha":"533346cc374382b41ec5ff70536252b2e96e725c","analyzedAt":"2026-09-17T13:35:38.149Z","contentChangedAt":"2026-09-17T13:35:38.149Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}