jdx/mise · error
cannot merge dotfile Git history
Error message
cannot merge dotfile Git history: {} What it means
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.
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.
Example fix
// before Error: cannot merge dotfile Git history: fatal: not a valid object name origin/main // after: fix the stale remote ref in the history repo $ cd ~/.local/share/mise/dotfiles-history $ git fetch origin
Defensive patterns
Strategy: try-catch
Validate before calling
let local_ok = git_ok(["rev-parse", "--verify", local]);
let remote_ok = git_ok(["rev-parse", "--verify", remote]);
if !(local_ok && remote_ok) { eprintln!("history refs missing; refetch remote"); } Type guard
fn merge_inputs_valid(local: &str, remote: &str) -> bool {
git_ok(["rev-parse", "--verify", local])
&& git_ok(["rev-parse", "--verify", remote])
} Try / catch
match result {
Err(e) if e.to_string().contains("cannot merge dotfile Git history") => {
// refetch/rebuild history refs, check git version
}
other => other?,
} Prevention
- 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.
When it happens
Trigger: 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.
Common situations: 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.
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
- cannot determine dotfile Git ancestry
- changed in the complete repository merge; reconcile again
- checkpoint has no protective checkpoint to undo from
- comparing checkpoints requires git
- dotfile enrollment metadata is too large
AI-assisted analysis of jdx/mise@533346cc37 (2026-09-17).
Data as JSON: /api/errors/36fb451065e0de2a.
Report an issue: GitHub.
Appendix: source
Thrown at src/system/history/shadow.rs:1540
}
let text = String::from_utf8(output.stdout)?;
Ok(text.lines().map(str::to_owned).collect())
}
/// Merge complete ordinary trees using Git's recursive merge-base handling.
/// Conflict trees are never adopted or written into live configuration.
pub(crate) fn merge_tree(&self, local: &str, remote: &str) -> Result<(String, Vec<String>)> {
let output = self.git.output_unchecked(PlumbingCall::new([
"merge-tree",
"--write-tree",
"--name-only",
"--no-messages",
"-z",
local,
remote,
]))?;
if !output.status.success() && output.status.code() != Some(1) {
bail!(
"cannot merge dotfile Git history: {}",
String::from_utf8_lossy(&output.stderr).trim()
);
}
let text = String::from_utf8(output.stdout)?;
let mut fields = text.split('\0');
let tree = fields
.next()
.filter(|tree| !tree.is_empty())
.ok_or_else(|| eyre::eyre!("Git did not return a merged tree"))?
.to_owned();
let conflicts = fields
.filter(|path| !path.is_empty())
.map(str::to_owned)
.collect();
Ok((tree, conflicts))
}
View on GitHub (pinned to 533346cc37)