GitoxideLabs/gitoxide · warning

there are no worktree or index changes to stash

Error message

there are no worktree or index changes to stash

What it means

Stashing only makes sense when there is something to save. `save_manual` checks the worktree dirtiness via `super::review::is_dirty` and bails when neither the index nor the worktree differs from HEAD, so an empty stash is never created. This mirrors `git stash`'s "No local changes to save" behavior but as a hard error.

Solutions

  1. Verify there are local changes (`git status`) before stashing
  2. Make the intended edits or stage changes, then stash
  3. Treat a clean worktree as a no-op in scripts: skip the stash call when `is_dirty` is false

Example fix

// before unconditional stash
stash::save_manual(path, bare, workdir, head_id)?;
// after
if is_dirty(&workdir)? {
    stash::save_manual(path, bare, workdir, head_id)?;
}
Defensive patterns

Strategy: validation

Validate before calling

if !tix::edit::review::is_dirty(&workdir)? {
    // nothing to stash; skip the operation entirely
    return Ok(());
}

Try / catch

if let Err(e) = stash::save_manual(path, bare, workdir, head_id) {
    if !e.to_string().contains("no worktree or index changes") {
        return Err(e.into());
    } // clean tree: treat as no-op
}

Prevention

When it happens

Trigger: Calling `stash::save_manual` (CLI `tix stash`) when the working tree is clean and the index matches HEAD — no modifications, additions, or deletions detected by `is_dirty`.

Common situations: Running stash in a script after changes were already committed or stashed; automation that assumes changes exist; testing against a freshly cloned clean worktree.

Understand the failure class

Background: "must not be empty", "cannot be empty" — required-field validation errors across open-source libraries — this error's family across 41 libraries.

Related errors


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

Appendix: source

Thrown at gix-tix/src/edit/stash.rs:147

    if head != id {
        anyhow::bail!("changes can only be stashed at the current HEAD");
    }
    if repo
        .index_or_empty()
        .context("could not inspect the index before stashing")?
        .entries()
        .iter()
        .any(|entry| entry.stage() != gix::index::entry::Stage::Unconflicted)
    {
        anyhow::bail!("cannot stash changes with unresolved index conflicts");
    }
    let name = reference(id)?;
    if repo.try_find_reference(name.as_ref())?.is_some() {
        anyhow::bail!("{} already has saved worktree state", id.to_hex_with_len(7));
    }
    drop(repo);
    if !super::review::is_dirty(&workdir)? {
        anyhow::bail!("there are no worktree or index changes to stash");
    }
    let saved = save(
        repository_path,
        bare,
        &workdir,
        name,
        format!("tix {}", id.to_hex_with_len(7)),
        "tix commit stash",
        "commit state",
    )?;
    let mut notice = format!("stashed changes at {}", id.to_hex_with_len(7));
    if let Some(warning) = saved.warning {
        write!(notice, "; {warning}").expect("writing to a string cannot fail");
    }
    Ok(notice)
}

#[tracing::instrument(skip_all, fields(commit_id = %id))]

View on GitHub (pinned to e73179060b)