{"record":{"id":"bf11bcac1d5ffef2","repo":"gitbutlerapp/gitbutler","slug":"cannot-restore-branch-because-it-is-checked-out-in-worktrees","errorCode":null,"errorMessage":"Cannot restore branch '{}' because it is checked out in worktrees: {dirs:?}","messagePattern":"Cannot restore branch '(.+?)' because it is checked out in worktrees: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/gitbutler-oplog/src/oplog.rs","lineNumber":1057,"sourceCode":"    let repo = ctx.repo.get()?;\n    let snapshot_commit = repo.find_commit(snapshot_commit_id)?;\n    let snapshot_tree = snapshot_commit.tree()?;\n    // Validate all metadata formats before creating the before-restore snapshot or mutating the\n    // worktree, refs, config, TOML, or database.\n    let (restored_project_meta, restored_virtual_branches, restored_branch_order) =\n        snapshot_metadata(&snapshot_tree, &repo)?;\n    let restored_checkout = snapshot_checkout(&snapshot_tree, &repo)?;\n    let restored_reference = snapshot_reference(&snapshot_tree, &repo)?;\n    let restored_target = restored_project_meta.target_commit_id_or_err()?;\n    let restored_vb_toml = toml::to_string(&restored_virtual_branches)?;\n\n    if let Some(reference) = restored_reference.as_ref()\n        && let Some(current_reference) = repo.try_find_reference(reference.ref_name.as_ref())?\n        && current_reference.target().try_id().map(ToOwned::to_owned) != reference.target\n        && let Some(dirs) =\n            but_core::branch::SafeDelete::new(&repo)?.worktree_dirs_with_ref(&current_reference)\n    {\n        bail!(\n            \"Cannot restore branch '{}' because it is checked out in worktrees: {dirs:?}\",\n            reference.ref_name.shorten()\n        );\n    }\n\n    let before_restore_snapshot_tree_id = match restored_reference.as_ref() {\n        Some(reference) => {\n            prepare_snapshot_with_target_and_ref(\n                ctx,\n                exclusive_access.read_permission(),\n                Some(reference.ref_name.as_ref()),\n            )?\n            .tree_id\n        }\n        None => prepare_snapshot(ctx, exclusive_access.read_permission())?,\n    };\n    let before_restore_snapshot_workdir_tree_id =\n        get_v3_workdir_tree(repo.find_tree(before_restore_snapshot_tree_id)?)?","sourceCodeStart":1039,"sourceCodeEnd":1075,"githubUrl":"https://github.com/gitbutlerapp/gitbutler/blob/58e5313667b857ef39a730e380af31816a7b1768/crates/gitbutler-oplog/src/oplog.rs#L1039-L1075","documentation":"Thrown during `restore_snapshot` when the snapshot wants to move a branch to a different commit, but that branch is currently checked out in another git worktree. Moving a ref that a worktree has checked out would desynchronize that worktree's index/HEAD, so GitButler refuses via `SafeDelete::worktree_dirs_with_ref`.","triggerScenarios":"`restore_snapshot` restores a `SnapshotReference` whose target differs from the branch's current target while `but_core::branch::SafeDelete` reports the ref is checked out in one or more worktrees.","commonSituations":"Using linked worktrees (`git worktree add`) with GitButler branches; restoring oplog snapshots while the same branch is open in a second terminal/editor worktree; CI checkouts sharing the same repository.","solutions":["Remove the extra worktree holding the branch: `git worktree remove <dir>` (or `git worktree prune` for stale entries)","Check out a different branch in the other worktree so the target branch is free, then retry the restore","Restore the snapshot from the worktree where the branch is actually checked out","Run `but oplog restore` only when the repository has a single worktree referencing the branch"],"exampleFix":"// before: branch 'main' checked out in ../main-wt blocks restore\n// after:\n//   git worktree remove ../main-wt\n//   but oplog restore  # now succeeds","handlingStrategy":"validation","validationCode":"// fail fast before restore if the ref is checked out elsewhere\nlet safe = but_core::branch::SafeDelete::new(&repo)?;\nif let Some(reference) = repo.try_find_reference(branch_ref)? {\n    let dirs = safe.worktree_dirs_with_ref(&reference)?;\n    if !dirs.is_empty() { return Err(format!(\"branch checked out in {dirs:?}\")); }\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Run `git worktree list` and remove stale worktrees before restoring snapshots","Check out a different branch in secondary worktrees holding the target branch","Run `git worktree prune` after deleting worktree directories manually","Restore snapshots from the worktree that owns the branch"],"tags":["git","worktree","snapshot","ref-locked"],"backgroundTag":"resource-conflict","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"}