GitoxideLabs/gitoxide · error

change ID prefix is ambiguous in the default Tix view

Error message

change ID prefix {} is ambiguous in the default Tix view

What it means

`gix_tix::change_id::resolve_prefix` resolves a change-ID prefix to exactly one commit in the default Tix view. If the prefix matches change IDs on more than one commit, the second match trips `found.replace(id).is_some()` and it bails, because an ambiguous prefix cannot identify a single change. Use a longer prefix to disambiguate.

Solutions

  1. Provide a longer change-ID prefix that uniquely identifies one commit.
  2. Use the full change ID copied from the todo/history view.
  3. List matching commits first (search the view by prefix) and pick the intended one explicitly.
  4. Adjust the script to catch ambiguity and retry with a longer prefix.

Example fix

// before
let id = resolve_prefix(repo, &"ab".parse()?)?;
// after
let id = resolve_prefix(repo, &"ab12ef".parse()?)?; // longer, unambiguous prefix
Defensive patterns

Strategy: try-catch

Validate before calling

// Ensure the prefix is long enough: check how many commits' change ids start with it before resolving.

Try / catch

match resolve_prefix(repo, &prefix) { Err(e) if e.to_string().contains("is ambiguous") => { let longer = extend_prefix(&prefix); resolve_prefix(repo, &longer) } other => other }

Prevention

When it happens

Trigger: Calling `resolve_prefix(repo, prefix)` where at least two commits in the default Tix view have change IDs sharing the given prefix — e.g. passing a 1–3 character reverse-hex prefix in a repo with many changes.

Common situations: Typing short change-ID abbreviations by hand in `gix tix` commands; scripted lookups with fixed short prefixes that became ambiguous as the repository grew; repositories where many commits were created in one batch so prefixes collide early.

Related errors


AI-assisted analysis of GitoxideLabs/gitoxide@e73179060b (2026-09-08). Data as JSON: /api/errors/bf757424cf82d6bc. Report an issue: GitHub.

Appendix: source

Thrown at gix-tix/src/change_id.rs:82

    pub ambiguous: HashSet<ObjectId>,
}

pub(crate) fn resolve_prefix(
    repo: &gix::Repository,
    prefix: &str,
    ids: impl IntoIterator<Item = ObjectId>,
) -> Result<Option<ObjectId>> {
    let Ok(prefix) = gix::hash::Prefix::from_reverse_hex(prefix) else {
        return Ok(None);
    };
    let mut found = None;
    for id in ids {
        let change_id = for_commit(repo, id)?;
        if prefix.cmp_oid(&change_id) != CmpOrdering::Equal {
            continue;
        }
        if found.replace(id).is_some() {
            anyhow::bail!(
                "change ID prefix {} is ambiguous in the default Tix view",
                prefix.to_reverse_hex()
            );
        }
    }
    Ok(found)
}

fn collect_abbreviations(values: impl IntoIterator<Item = (ObjectId, ChangeId)>, len: usize) -> Abbreviations {
    let mut by_prefix = HashMap::new();
    let mut all = HashMap::new();
    let mut ambiguous = HashSet::new();
    for (id, change_id) in values {
        let prefix = change_id.to_reverse_hex_with_len(len).to_string();
        if let Some(first) = by_prefix.insert(prefix, id) {
            ambiguous.insert(first);
            ambiguous.insert(id);
        }

View on GitHub (pinned to e73179060b)