{"record":{"id":"d250e65a2ef5dbde","repo":"GitoxideLabs/gitoxide","slug":"there-are-no-worktree-or-index-changes-to-stash","errorCode":null,"errorMessage":"there are no worktree or index changes to stash","messagePattern":"there are no worktree or index changes to stash","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"gix-tix/src/edit/stash.rs","lineNumber":147,"sourceCode":"    if head != id {\n        anyhow::bail!(\"changes can only be stashed at the current HEAD\");\n    }\n    if repo\n        .index_or_empty()\n        .context(\"could not inspect the index before stashing\")?\n        .entries()\n        .iter()\n        .any(|entry| entry.stage() != gix::index::entry::Stage::Unconflicted)\n    {\n        anyhow::bail!(\"cannot stash changes with unresolved index conflicts\");\n    }\n    let name = reference(id)?;\n    if repo.try_find_reference(name.as_ref())?.is_some() {\n        anyhow::bail!(\"{} already has saved worktree state\", id.to_hex_with_len(7));\n    }\n    drop(repo);\n    if !super::review::is_dirty(&workdir)? {\n        anyhow::bail!(\"there are no worktree or index changes to stash\");\n    }\n    let saved = save(\n        repository_path,\n        bare,\n        &workdir,\n        name,\n        format!(\"tix {}\", id.to_hex_with_len(7)),\n        \"tix commit stash\",\n        \"commit state\",\n    )?;\n    let mut notice = format!(\"stashed changes at {}\", id.to_hex_with_len(7));\n    if let Some(warning) = saved.warning {\n        write!(notice, \"; {warning}\").expect(\"writing to a string cannot fail\");\n    }\n    Ok(notice)\n}\n\n#[tracing::instrument(skip_all, fields(commit_id = %id))]","sourceCodeStart":129,"sourceCodeEnd":165,"githubUrl":"https://github.com/GitoxideLabs/gitoxide/blob/e73179060badf27222d790981fac3f84c1830a7e/gix-tix/src/edit/stash.rs#L129-L165","documentation":"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.","triggerScenarios":"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`.","commonSituations":"Running stash in a script after changes were already committed or stashed; automation that assumes changes exist; testing against a freshly cloned clean worktree.","solutions":["Verify there are local changes (`git status`) before stashing","Make the intended edits or stage changes, then stash","Treat a clean worktree as a no-op in scripts: skip the stash call when `is_dirty` is false"],"exampleFix":"// before unconditional stash\nstash::save_manual(path, bare, workdir, head_id)?;\n// after\nif is_dirty(&workdir)? {\n    stash::save_manual(path, bare, workdir, head_id)?;\n}","handlingStrategy":"validation","validationCode":"if !tix::edit::review::is_dirty(&workdir)? {\n    // nothing to stash; skip the operation entirely\n    return Ok(());\n}","typeGuard":null,"tryCatchPattern":"if let Err(e) = stash::save_manual(path, bare, workdir, head_id) {\n    if !e.to_string().contains(\"no worktree or index changes\") {\n        return Err(e.into());\n    } // clean tree: treat as no-op\n}","preventionTips":["Call `is_dirty` on the worktree before stashing","Don't stash in scripts after commits or prior stashes may have consumed the changes","Treat a clean worktree as an expected, skippable condition rather than an error"],"tags":["git","worktree","clean-state","stash"],"backgroundTag":"empty-required-field","analyzedSha":"e73179060badf27222d790981fac3f84c1830a7e","analyzedAt":"2026-09-08T11:26:50.865Z","contentChangedAt":"2026-09-08T11:26:50.865Z","schemaVersion":2},"datasetVersion":"2026-09-16T04:17:20.429Z"}