{"record":{"id":"36fb451065e0de2a","repo":"jdx/mise","slug":"cannot-merge-dotfile-git-history","errorCode":null,"errorMessage":"cannot merge dotfile Git history: {}","messagePattern":"cannot merge dotfile Git history: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src/system/history/shadow.rs","lineNumber":1540,"sourceCode":"        }\n        let text = String::from_utf8(output.stdout)?;\n        Ok(text.lines().map(str::to_owned).collect())\n    }\n\n    /// Merge complete ordinary trees using Git's recursive merge-base handling.\n    /// Conflict trees are never adopted or written into live configuration.\n    pub(crate) fn merge_tree(&self, local: &str, remote: &str) -> Result<(String, Vec<String>)> {\n        let output = self.git.output_unchecked(PlumbingCall::new([\n            \"merge-tree\",\n            \"--write-tree\",\n            \"--name-only\",\n            \"--no-messages\",\n            \"-z\",\n            local,\n            remote,\n        ]))?;\n        if !output.status.success() && output.status.code() != Some(1) {\n            bail!(\n                \"cannot merge dotfile Git history: {}\",\n                String::from_utf8_lossy(&output.stderr).trim()\n            );\n        }\n        let text = String::from_utf8(output.stdout)?;\n        let mut fields = text.split('\\0');\n        let tree = fields\n            .next()\n            .filter(|tree| !tree.is_empty())\n            .ok_or_else(|| eyre::eyre!(\"Git did not return a merged tree\"))?\n            .to_owned();\n        let conflicts = fields\n            .filter(|path| !path.is_empty())\n            .map(str::to_owned)\n            .collect();\n        Ok((tree, conflicts))\n    }\n","sourceCodeStart":1522,"sourceCodeEnd":1558,"githubUrl":"https://github.com/jdx/mise/blob/533346cc374382b41ec5ff70536252b2e96e725c/src/system/history/shadow.rs#L1522-L1558","documentation":"mise runs `git merge-tree --no-messages -z` (via plumbing) to compute a merge of the local and remote dotfile histories. Exit code 1 signals conflicts and is tolerated, but any other non-success git exit triggers this error with git's stderr. It means the history-merge operation itself failed rather than producing a conflicted merge.","triggerScenarios":"Calling the dotfile history sync/merge path when `git merge-tree` fails outright: invalid or unknown ref names, corrupt object database, or an object missing from the shadow repo.","commonSituations":"Remote history rewritten/force-pushed so objects referenced locally are gone; the shadow history repo partially pruned; git version too old to support the merge-tree flags used.","solutions":["Check the embedded stderr message for the exact git failure.","Confirm both refs resolve in the history repo (`git rev-parse <local> <remote>`).","Ensure git is recent enough for the merge-tree flags used (`git --version`).","If history objects are missing, re-clone/rebuild the dotfile history repo or reset the sync state."],"exampleFix":"// before\nError: cannot merge dotfile Git history: fatal: not a valid object name origin/main\n\n// after: fix the stale remote ref in the history repo\n$ cd ~/.local/share/mise/dotfiles-history\n$ git fetch origin","handlingStrategy":"try-catch","validationCode":"let local_ok = git_ok([\"rev-parse\", \"--verify\", local]);\nlet remote_ok = git_ok([\"rev-parse\", \"--verify\", remote]);\nif !(local_ok && remote_ok) { eprintln!(\"history refs missing; refetch remote\"); }","typeGuard":"fn merge_inputs_valid(local: &str, remote: &str) -> bool {\n  git_ok([\"rev-parse\", \"--verify\", local])\n    && git_ok([\"rev-parse\", \"--verify\", remote])\n}","tryCatchPattern":"match result {\n  Err(e) if e.to_string().contains(\"cannot merge dotfile Git history\") => {\n    // refetch/rebuild history refs, check git version\n  }\n  other => other?,\n}","preventionTips":["Fetch the remote history before merging so its objects exist locally.","Avoid force-rewriting the remote dotfile history.","Ensure a reasonably modern git is installed."],"tags":["git","dotfiles","merge","history-repo"],"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"}