gitbutlerapp/gitbutler · error
Cannot restore branch
Error message
Cannot restore branch '{}' because it is checked out in worktrees: {dirs:?} What it means
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`.
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
Example fix
// before: branch 'main' checked out in ../main-wt blocks restore // after: // git worktree remove ../main-wt // but oplog restore # now succeeds
Defensive patterns
Strategy: validation
Validate before calling
// fail fast before restore if the ref is checked out elsewhere
let safe = but_core::branch::SafeDelete::new(&repo)?;
if let Some(reference) = repo.try_find_reference(branch_ref)? {
let dirs = safe.worktree_dirs_with_ref(&reference)?;
if !dirs.is_empty() { return Err(format!("branch checked out in {dirs:?}")); }
} Prevention
- 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
When it happens
Trigger: `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.
Common situations: 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.
Related errors
- `but setup` cannot run from a linked worktree; run it from…
- Cannot currently work in repositories without a worktree
- Cannot currently work in repositories without a worktree
- Cannot hash directory entries that aren't files or symlinks
- cannot restore a snapshot without checkout identity outside…
AI-assisted analysis of gitbutlerapp/gitbutler@58e5313667 (2026-09-18).
Data as JSON: /api/errors/bf11bcac1d5ffef2.
Report an issue: GitHub.
Appendix: source
Thrown at crates/gitbutler-oplog/src/oplog.rs:1057
let repo = ctx.repo.get()?;
let snapshot_commit = repo.find_commit(snapshot_commit_id)?;
let snapshot_tree = snapshot_commit.tree()?;
// Validate all metadata formats before creating the before-restore snapshot or mutating the
// worktree, refs, config, TOML, or database.
let (restored_project_meta, restored_virtual_branches, restored_branch_order) =
snapshot_metadata(&snapshot_tree, &repo)?;
let restored_checkout = snapshot_checkout(&snapshot_tree, &repo)?;
let restored_reference = snapshot_reference(&snapshot_tree, &repo)?;
let restored_target = restored_project_meta.target_commit_id_or_err()?;
let restored_vb_toml = toml::to_string(&restored_virtual_branches)?;
if let Some(reference) = restored_reference.as_ref()
&& let Some(current_reference) = repo.try_find_reference(reference.ref_name.as_ref())?
&& current_reference.target().try_id().map(ToOwned::to_owned) != reference.target
&& let Some(dirs) =
but_core::branch::SafeDelete::new(&repo)?.worktree_dirs_with_ref(¤t_reference)
{
bail!(
"Cannot restore branch '{}' because it is checked out in worktrees: {dirs:?}",
reference.ref_name.shorten()
);
}
let before_restore_snapshot_tree_id = match restored_reference.as_ref() {
Some(reference) => {
prepare_snapshot_with_target_and_ref(
ctx,
exclusive_access.read_permission(),
Some(reference.ref_name.as_ref()),
)?
.tree_id
}
None => prepare_snapshot(ctx, exclusive_access.read_permission())?,
};
let before_restore_snapshot_workdir_tree_id =
get_v3_workdir_tree(repo.find_tree(before_restore_snapshot_tree_id)?)?View on GitHub (pinned to 58e5313667)