jdx/mise · error
local and origin histories are unrelated; use a fresh setup
Error message
local and origin histories are unrelated; use a fresh setup store to adopt origin, or reconcile the repositories explicitly with Git. Neither history was replaced
What it means
When computing the sync base, read() finds both a local history ref and an origin ref but repo.merge_bases() returns no common ancestor — the two histories are unrelated. The sync deliberately aborts without replacing either history, because fast-forwarding or adopting origin would silently discard one lineage of saved files.
Source
Thrown at src/system/history/sync/graph.rs:31
pub base: Option<String>,
}
#[derive(Debug)]
pub(crate) struct Candidate {
pub commit: String,
expected_local: Option<String>,
expected_remote: Option<String>,
}
impl Heads {
pub(crate) fn read(repo: &HistoryRepo) -> Result<Self> {
let local = repo.ref_oid(HistoryRepo::HISTORY_REF)?;
let remote = repo.ref_oid(UPSTREAM_REF)?;
let base = match (&local, &remote) {
(Some(local), Some(remote)) => {
let bases = repo.merge_bases(local, remote)?;
if bases.is_empty() {
bail!(
"local and origin histories are unrelated; use a fresh setup store to adopt origin, or reconcile the repositories explicitly with Git. Neither history was replaced"
);
}
// A criss-cross merge has shared ancestry but no unique base.
// It needs a merge commit, never an arbitrary fast-forward.
(bases.len() == 1).then(|| bases[0].clone())
}
_ => None,
};
Ok(Self {
local,
remote,
base,
})
}
/// Preparing a candidate does not advance a branch or write live files.
/// The caller must finish its complete application before adopting it.View on GitHub (pinned to afd2eddd3a)
Solutions
- Force-adopt origin by initializing a fresh setup store from origin (discarding unrelated local history) if origin is authoritative.
- Reconcile explicitly with git: graft or merge the two roots manually in the history repo, then push.
- Back up saved files, delete the local history ref, and re-pull to start from origin.
Example fix
# before: divergent unrelated histories $ mise bootstrap dotfiles sync # fails # after: adopt origin with a fresh store $ rm -rf ~/.local/share/mise/history && mise bootstrap dotfiles pull
Defensive patterns
Strategy: fallback
Validate before calling
let local = repo.ref_oid(HistoryRepo::HISTORY_REF)?;
let remote = repo.ref_oid(UPSTREAM_REF)?;
if let (Some(l), Some(r)) = (&local, &remote) {
if repo.merge_bases(l, r)?.is_empty() {
eprintln!("histories unrelated; decide adopt-origin vs manual reconcile");
}
} Try / catch
match read(repo) {
Ok(base) => proceed(base),
Err(e) if e.to_string().contains("histories are unrelated") => {
eprintln!("prompt: adopt origin (fresh store) or reconcile with git");
prompt_unrelated_history_action()
}
Err(e) => return Err(e),
} Prevention
- Always clone/adopt the origin store instead of re-initializing independently.
- Avoid force-pushing or recreating the origin history store.
- Back up saved dotfiles before any history surgery.
When it happens
Trigger: Calling read() on a HistoryRepo where HISTORY_REF and UPSTREAM_REF both exist but share no merge base (disjoint commit graphs).
Common situations: A fresh origin store was force-pushed/re-created while the local machine kept its old history; two machines independently initialized setup stores and both were pushed; restoring origin from a new init instead of cloning.
Understand the failure class
Background: "Invalid state transition" errors: "status must be X, actually Y", "already rejected/charging/uninstalled", "cannot ... while running" — what they mean when a library rejects your call — this error's family across 31 libraries.
Related errors
- setup history changed during adoption; retry pull
- cannot check staged changes in {}: {}
- incoming files changed while preparing adoption; plan again
- incoming history.origin is machine-local configuration; remo
- required source is not a regular file: {}
AI-assisted analysis of jdx/mise@afd2eddd3a (2026-09-09).
Data as JSON: /api/errors/05d79a73808c8870.
Report an issue: GitHub.