jdx/mise · error

cannot merge dotfile Git history: {}

Error message

cannot merge dotfile Git history: {}

What it means

Raised when the git call used to merge dotfile histories (e.g. `git merge-tree`/name-status plumbing with `-z`) fails with a status that is neither success nor the tolerated exit code 1. The tool cannot compute the merged view of the two histories, so it aborts and includes git's trimmed stderr. Exit code 1 is deliberately allowed because some plumbing calls use it to mean 'differences/conflicts reported' rather than failure.

Source

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

        }
        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 afd2eddd3a)

Solutions

  1. Reproduce the merge command manually in the shadow repo and read the stderr included in the error message.
  2. Run `git fsck --full` to detect and repair missing/corrupt objects.
  3. If history is unrecoverable, reset the shadow history and re-sync: push/pull the dotfiles afresh to rebuild both sides.
  4. Ensure no other process (backup/AV) is mutating the shadow repo's .git directory concurrently.
Defensive patterns

Strategy: fallback

Validate before calling

if !git_available() { eprintln!("git broken; history merge cannot run"); }
if !shadow_repo_healthy() { run_git_fsck(shadow_repo)?; }

Try / catch

match history.merge(local, remote) {
    Ok(merged) => apply(merged),
    Err(e) if e.to_string().contains("cannot merge dotfile Git history") => {
        repair_or_reset_shadow_repo()?;
    }
    Err(e) => return Err(e),
}

Prevention

When it happens

Trigger: Invoking history merge for dotfiles when the underlying plumbing command exits with an unexpected code (not 0 and not 1): missing object, corrupt repo, invalid ref names, or git binary malfunction.

Common situations: Merging dotfile history after a machine was restored from a partial backup (missing git objects); a shadow repo truncated by disk-full conditions; refs renamed outside of mise while a sync is in flight.

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/36fb451065e0de2a. Report an issue: GitHub.