aboutsummaryrefslogtreecommitdiff
path: root/src/app
diff options
context:
space:
mode:
authorOgulcan Celik <ogulcancelik@gmail.com>2026-06-07 15:12:59 +0300
committerOgulcan Celik <ogulcancelik@gmail.com>2026-06-07 16:29:45 +0300
commit745ce4254c646922d667ec13dd21963656405c12 (patch)
tree96704b9884d95d810be16b1dad5cb48c07ccdcc8 /src/app
parentf61ed48eff622de4f970adff220603ea50292f07 (diff)
fix: handle windows worktree paths and removal
Diffstat (limited to 'src/app')
-rw-r--r--src/app/api/worktrees.rs16
-rw-r--r--src/app/worktrees.rs84
2 files changed, 80 insertions, 20 deletions
diff --git a/src/app/api/worktrees.rs b/src/app/api/worktrees.rs
index d6a269ca..573771e2 100644
--- a/src/app/api/worktrees.rs
+++ b/src/app/api/worktrees.rs
@@ -292,6 +292,22 @@ impl App {
);
}
+ #[cfg(windows)]
+ {
+ if !params.force
+ && crate::worktree::checkout_has_dirty_files(&space.checkout_path).unwrap_or(false)
+ {
+ return encode_error(
+ id,
+ "dirty_worktree_requires_force",
+ crate::worktree::worktree_dirty_remove_message(&space.checkout_path),
+ );
+ }
+ }
+
+ #[cfg(windows)]
+ self.shutdown_workspace_terminal_runtimes_for_worktree_remove(ws_idx);
+
let command = crate::worktree::build_worktree_remove_command(
&space.repo_root,
&space.checkout_path,
diff --git a/src/app/worktrees.rs b/src/app/worktrees.rs
index f7d906ee..f6635c23 100644
--- a/src/app/worktrees.rs
+++ b/src/app/worktrees.rs
@@ -548,21 +548,44 @@ impl App {
}
pub(crate) fn start_worktree_remove(&mut self) {
- let Some(remove) = &mut self.state.worktree_remove else {
+ let Some((workspace_id, repo_root, path, force)) =
+ self.state.worktree_remove.as_mut().and_then(|remove| {
+ if remove.removing {
+ return None;
+ }
+ #[cfg(windows)]
+ if !remove.force_confirmation
+ && crate::worktree::checkout_has_dirty_files(&remove.path).unwrap_or(false)
+ {
+ remove.force_confirmation = true;
+ remove.error = None;
+ return None;
+ }
+ remove.removing = true;
+ remove.error = None;
+ Some((
+ remove.workspace_id.clone(),
+ remove.repo_root.clone(),
+ remove.path.clone(),
+ remove.force_confirmation,
+ ))
+ })
+ else {
return;
};
- if remove.removing {
- return;
+
+ #[cfg(windows)]
+ if let Some(ws_idx) = self
+ .state
+ .workspaces
+ .iter()
+ .position(|ws| ws.id == workspace_id)
+ {
+ self.shutdown_workspace_terminal_runtimes_for_worktree_remove(ws_idx);
}
- remove.removing = true;
- remove.error = None;
- let force = remove.force_confirmation;
-
- let command =
- crate::worktree::build_worktree_remove_command(&remove.repo_root, &remove.path, force);
- tracing::info!(workspace_id = %remove.workspace_id, path = %remove.path.display(), force, "starting git worktree remove");
- let path = remove.path.clone();
- let workspace_id = remove.workspace_id.clone();
+
+ let command = crate::worktree::build_worktree_remove_command(&repo_root, &path, force);
+ tracing::info!(workspace_id = %workspace_id, path = %path.display(), force, "starting git worktree remove");
let event_tx = self.event_tx.clone();
std::thread::spawn(move || {
let result = crate::worktree::run_worktree_command(&command);
@@ -697,6 +720,23 @@ impl App {
}
}
}
+
+ #[cfg(windows)]
+ pub(crate) fn shutdown_workspace_terminal_runtimes_for_worktree_remove(
+ &mut self,
+ ws_idx: usize,
+ ) {
+ for terminal_id in self.state.terminal_ids_for_workspace(ws_idx) {
+ if let Some(runtime) = self.terminal_runtimes.remove(&terminal_id) {
+ tracing::debug!(
+ workspace_index = ws_idx,
+ terminal_id = %terminal_id,
+ "shutting down terminal runtime before Windows worktree removal"
+ );
+ runtime.shutdown();
+ }
+ }
+ }
}
#[cfg(test)]
@@ -1212,15 +1252,19 @@ mod tests {
app.open_remove_linked_worktree_confirmation(0);
app.start_worktree_remove();
- let safe_event = wait_for_worktree_event(&mut app);
- match safe_event {
- AppEvent::WorktreeRemoveFinished(result) => {
- assert_eq!(result.workspace_id, workspace_id);
- assert_eq!(result.path, checkout);
- assert!(result.result.is_err());
- app.handle_worktree_remove_finished(result);
+
+ #[cfg(not(windows))]
+ {
+ let safe_event = wait_for_worktree_event(&mut app);
+ match safe_event {
+ AppEvent::WorktreeRemoveFinished(result) => {
+ assert_eq!(result.workspace_id, workspace_id);
+ assert_eq!(result.path, checkout);
+ assert!(result.result.is_err());
+ app.handle_worktree_remove_finished(result);
+ }
+ other => panic!("unexpected event: {other:?}"),
}
- other => panic!("unexpected event: {other:?}"),
}
let remove = app.state.worktree_remove.as_ref().unwrap();