{"record":{"id":"39ce83bfc6afab7a","repo":"GitoxideLabs/gitoxide","slug":"changes-can-only-be-unstashed-at-the-current-head","errorCode":null,"errorMessage":"changes can only be unstashed at the current HEAD","messagePattern":"changes can only be unstashed at the current HEAD","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"gix-tix/src/edit/stash.rs","lineNumber":178,"sourceCode":"        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))]\npub(crate) fn restore_manual(repository_path: &Path, bare: bool, id: ObjectId) -> Result<String> {\n    let repo = open_repository(repository_path, bare, false).context(\"could not open repository to unstash changes\")?;\n    let workdir = repo\n        .workdir()\n        .context(\"unstashing changes requires a worktree\")?\n        .to_owned();\n    if repo\n        .head_id()\n        .context(\"unstashing changes requires a born HEAD\")?\n        .detach()\n        != id\n    {\n        anyhow::bail!(\"changes can only be unstashed at the current HEAD\");\n    }\n    let name = reference(id)?;\n    drop(repo);\n    let saved = find(repository_path, bare, name)?.context(\"the selected commit has no saved worktree state\")?;\n    apply(repository_path, bare, &workdir, saved)\n}\n\n#[derive(Clone)]\npub(super) struct SavedStash {\n    pub name: gix::refs::FullName,\n    pub target: Target,\n    pub warning: Option<String>,\n}\n\n#[tracing::instrument(skip_all, fields(stash = %name))]\npub(super) fn save(\n    repository_path: &Path,\n    bare: bool,","sourceCodeStart":160,"sourceCodeEnd":196,"githubUrl":"https://github.com/GitoxideLabs/gitoxide/blob/e73179060badf27222d790981fac3f84c1830a7e/gix-tix/src/edit/stash.rs#L160-L196","documentation":"Restoring saved worktree state is keyed by the commit the state was saved at; tix requires that commit to be the current HEAD. This error fires when `restore_manual` is given an `id` that differs from `repo.head_id()`, because applying the saved state at any other position could corrupt the correspondence between the stash and the tree it was captured against.","triggerScenarios":"Calling `stash::restore_manual` with an `id` not equal to the repository's current `head_id()` — e.g. after HEAD moved via checkout/reset/rebase between stashing and unstashing, or passing an arbitrary commit id.","commonSituations":"Trying to unstash after switching branches or rebasing; scripts holding a stale HEAD id; attempting to apply a stash recorded on another commit.","solutions":["Move HEAD back to the commit the stash was saved at (checkout/reset), then unstash","Verify `repo.head_id()` equals the stash's commit id before calling restore","If the original commit is gone from history, recover it or manually apply the saved state from its reference"],"exampleFix":"// before\nlet stash_id = saved_commit_id;\nstash::restore_manual(path, bare, stash_id)?;\n// after\nlet repo = gix::open(path)?;\nlet head = repo.head_id().expect(\"born HEAD\").detach();\nassert_eq!(head, stash_id, \"checkout the stash's commit first\");\nstash::restore_manual(path, bare, stash_id)?;","handlingStrategy":"validation","validationCode":"let repo = gix::open(path)?;\nlet head = repo.head_id().context(\"born HEAD required\")?.detach();\nif head != stash_id {\n    anyhow::bail!(\"checkout {} before unstashing\", stash_id);\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Do not checkout/reset/rebase between stashing and unstashing","Compare `repo.head_id()` with the stash's commit id before restoring","Automate unstash immediately after the operation that required the stash, so HEAD cannot drift"],"tags":["git","head","precondition","stash"],"backgroundTag":"invalid-state-transition","analyzedSha":"e73179060badf27222d790981fac3f84c1830a7e","analyzedAt":"2026-09-08T11:26:50.865Z","contentChangedAt":"2026-09-08T11:26:50.865Z","schemaVersion":2},"datasetVersion":"2026-09-15T23:17:13.987Z"}