{"record":{"id":"9bf854c404bcc377","repo":"gitbutlerapp/gitbutler","slug":"cannot-operate-on-uncommitted-changes-in-worktree","errorCode":null,"errorMessage":"Cannot operate on uncommitted changes in worktree {name} yet","messagePattern":"Cannot operate on uncommitted changes in worktree (.+?) yet","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/but/src/utils/diff_specs.rs","lineNumber":112,"sourceCode":"            }\n            CliId::CommittedHunk(_) => {\n                anyhow::bail!(\"Cannot compute diff specs for committed hunks\")\n            }\n        }\n    }\n\n    pub fn push_changes_from_uncommitted(\n        &mut self,\n        uncommitted: &UncommittedHunkOrFile,\n    ) -> anyhow::Result<()> {\n        // Specs are built against one checkout's repository, so a hunk from\n        // another would silently address the wrong files. Operations that support\n        // worktree sources validate the selection and construct the builder via\n        // [`Self::for_change_source`]; the rest read the main worktree and refuse\n        // worktree hunks here.\n        if uncommitted.source != self.source {\n            if let Some(name) = uncommitted.source.worktree_name() {\n                anyhow::bail!(\"Cannot operate on uncommitted changes in worktree {name} yet\");\n            }\n            anyhow::bail!(\n                \"BUG: a change from {} was pushed into a builder reading {}\",\n                uncommitted.source.describe(),\n                self.source.describe()\n            );\n        }\n        let hunks = uncommitted.hunks.iter().cloned();\n        self.push_hunks(hunks.map(|id_and_hunk| id_and_hunk.hunk))\n    }\n\n    pub fn push_changes_from_path_prefix(\n        &mut self,\n        hunks: &nonempty::NonEmpty<IdAndHunk>,\n    ) -> anyhow::Result<()> {\n        self.push_hunks(hunks.iter().map(|id_and_hunk| id_and_hunk.hunk.clone()))\n    }\n","sourceCodeStart":94,"sourceCodeEnd":130,"githubUrl":"https://github.com/gitbutlerapp/gitbutler/blob/58e5313667b857ef39a730e380af31816a7b1768/crates/but/src/utils/diff_specs.rs#L94-L130","documentation":"The diff-specs builder was constructed to read one change source (by default the main worktree), but was pushed an `UncommittedChanges` whose source is a different worktree. Since hunks from different worktrees address different files, the builder refuses rather than silently operating on the wrong files; operations that legitimately support worktree sources must use `DiffSpecsBuilder::for_change_source`.","triggerScenarios":"Calling `push_changes_from_uncommitted` (directly or via `push_changes_from_id` with an uncommitted id) where `uncommitted.source != self.source` and the incoming source is a linked worktree; the current builder was not created with `for_change_source`.","commonSituations":"Targeting uncommitted changes that live in a linked worktree with a command that only supports the main worktree; passing a worktree's uncommitted id to a main-worktree builder.","solutions":["Run the operation with the worktree as the active context, or use the worktree-aware construction path (`for_change_source`) if the operation supports worktree sources","Operate on the main worktree's uncommitted changes instead","Move/commit the changes in the linked worktree first, then reference the resulting commit"],"exampleFix":null,"handlingStrategy":"validation","validationCode":"if let Some(name) = uncommitted.source.worktree_name() {\n    if builder_source != uncommitted.source {\n        eprintln!(\"uncommitted changes belong to worktree '{name}'; run the operation there or use a worktree-capable builder\");\n        return Ok(());\n    }\n}","typeGuard":"fn source_matches(b: &DiffSpecsBuilder, u: &UncommittedChanges) -> bool { b.source == u.source }","tryCatchPattern":"match result { Err(e) if e.to_string().contains(\"Cannot operate on uncommitted changes in worktree\") => { /* re-run inside the worktree */ }, other => other }","preventionTips":["Construct the builder with `for_change_source` when worktree sources must be supported","Only feed uncommitted changes whose source equals the builder's source","Run worktree-scoped operations from within that worktree"],"tags":["cli","worktree","uncommitted-changes"],"backgroundTag":"incompatible-source-type","analyzedSha":"58e5313667b857ef39a730e380af31816a7b1768","analyzedAt":"2026-09-18T06:50:32.052Z","contentChangedAt":"2026-09-18T06:50:32.052Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}