jdx/mise · error

cannot determine dotfile Git ancestry: {}

Error message

cannot determine dotfile Git ancestry: {}

What it means

This fires when `git merge-base --all <local> <remote>` exits with a status other than the expected 0 (ancestors found) or 1 (no common ancestor). Since the command cannot determine whether the two dotfile history tips share ancestry, the operation aborts and surfaces git's stderr. It guards the merge/rebase logic that relies on knowing the common history.

Source

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

    /// Deletes a ref if it exists.
    pub(crate) fn delete_ref(&self, name: &str) -> Result<()> {
        if self.ref_oid(name)?.is_some() {
            self.git
                .run(PlumbingCall::new(["update-ref", "-d", name]))?;
        }
        Ok(())
    }

    /// Find all common ancestors without treating Git failures as absence.
    pub(crate) fn merge_bases(&self, local: &str, remote: &str) -> Result<Vec<String>> {
        let output =
            self.git
                .output_unchecked(PlumbingCall::new(["merge-base", "--all", local, remote]))?;
        if output.status.code() == Some(1) {
            return Ok(vec![]);
        }
        if !output.status.success() {
            bail!(
                "cannot determine dotfile Git ancestry: {}",
                String::from_utf8_lossy(&output.stderr).trim()
            );
        }
        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,

View on GitHub (pinned to afd2eddd3a)

Solutions

  1. Run `git merge-base --all <local> <remote>` inside the shadow repo yourself and read the stderr echoed in the error.
  2. Check that both refs/commits exist: `git rev-parse <local> <remote>`.
  3. If refs are dangling after a force-push or GC, re-sync the dotfile history (`mise dot` pull/push) to rebuild the shared base.
  4. As a last resort, `git fsck` the shadow repository and restore it from a fresh clone or backup.
Defensive patterns

Strategy: fallback

Validate before calling

for r in [&local, &remote] {
    if !repo_rev_parse_ok(r) { eprintln!("ref {r} missing from shadow repo"); }
}

Try / catch

match history.common_ancestors(local, remote) {
    Ok(ans) => merge_with(ans),
    Err(e) if e.to_string().contains("cannot determine dotfile Git ancestry") => {
        eprintln!("shadow repo inconsistent; re-syncing history");
        resync_history()?;
    }
    Err(e) => return Err(e),
}

Prevention

When it happens

Trigger: Calling the ancestry check when the `merge-base --all` plumbing call fails for reasons other than 'no common ancestor' — e.g. one of the refs does not exist, the repository is corrupt, or git itself is broken.

Common situations: A dotfile shadow repo whose branch was force-deleted or garbage-collected while a local ref still points at it; a hand-edited or corrupted .git directory; running with a broken or partial git installation.

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/8c7d6ce31d533b74. Report an issue: GitHub.