GitoxideLabs/gitoxide · error

an unborn history is required to create a root commit

Error message

an unborn history is required to create a root commit

What it means

Commit creation in tix requires an unborn HEAD when no parent commit was supplied, i.e. creating a root commit is only valid when the repository has no commits yet. If a parent is not given but HEAD points at an existing commit, the operation would silently orphan history, so it bails with this message. Supplying an explicit parent is the supported way to create non-root commits.

Solutions

  1. Pass the intended parent commit explicitly (e.g. the current HEAD commit) instead of relying on root-commit mode.
  2. Use the amend workflow if the goal is to modify the existing HEAD commit.
  3. Only create root commits in a repository with unborn HEAD (no commits yet).

Example fix

// before: parent=None on a repo with existing history -> bail
let prepared = create::prepare(&repo, None, ...)?;
// after
let head_id = repo.head_id()?.detach();
let prepared = create::prepare(&repo, Some(head_id), ...)?;
Defensive patterns

Strategy: validation

Validate before calling

let head = repo.head()?;
let is_unborn = head.is_unborn();
if parent.is_none() && !is_unborn {
    anyhow::bail!("supply an explicit parent (or use amend) on a repo with history");
}

Try / catch

match result {
    Err(e) if e.to_string().contains("unborn history is required") => {
        // retry with current HEAD as parent
    }
    other => other?,
}

Prevention

When it happens

Trigger: Calling `Prepared::prepare`/`prepare_empty`/`prepare_from` (via `prepare_inner`) with `parent == None` while HEAD resolves to an existing commit instead of being unborn.

Common situations: Running a create/edit command in a repository that already has history without specifying the intended parent; confusing 'new commit' with 'amend'; scripting that drops the parent argument on non-empty repos.

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


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

Appendix: source

Thrown at gix-tix/src/edit/create.rs:61

    author: Option<&gix::bstr::BStr>,
    todo: bool,
) -> Result<Prepared> {
    prepare_inner(repo, parent, false, source, author, todo)
}

fn prepare_inner(
    mut repo: gix::Repository,
    parent: Option<ObjectId>,
    empty: bool,
    source: Source,
    author_override: Option<&gix::bstr::BStr>,
    todo: bool,
) -> Result<Prepared> {
    repo.workdir().context("creating a commit requires a worktree")?;
    let head = repo.head().context("could not read HEAD before creating a commit")?;
    let head_id = head.id().map(gix::Id::detach);
    if parent.is_none() && !head.is_unborn() {
        anyhow::bail!("an unborn history is required to create a root commit");
    }
    if let Some(parent) = parent {
        repo.find_commit(parent)
            .context("could not find the selected parent commit")?;
    }
    if parent.is_none() {
        head.referent_name().context("an unborn HEAD must point to a branch")?;
    }
    let editor = repo
        .editor_command()
        .context("could not prepare Git editor")?
        .context("no Git editor is available")?;
    let mut author = repo
        .author()
        .context("no Git author is configured")?
        .context("could not resolve the Git author")?
        .to_owned()
        .context("could not own the Git author")?;

View on GitHub (pinned to e73179060b)