diff --git a/src/commands/worktree.rs b/src/commands/worktree.rs index 10970b269..516b787e7 100644 --- a/src/commands/worktree.rs +++ b/src/commands/worktree.rs @@ -754,18 +754,11 @@ pub fn handle_remove( no_delete_branch: bool, force_delete: bool, force_worktree: bool, - background: bool, config: &WorktrunkConfig, ) -> anyhow::Result { let repo = Repository::current(); - // Show progress (unless running in background - output handler will show command) - if !background { - crate::output::print(progress_message(cformat!( - "Removing {worktree_name} worktree..." - )))?; - } - + // Progress message is shown in handle_removed_worktree_output() after pre-remove hooks run repo.prepare_worktree_removal( RemoveTarget::Branch(worktree_name), BranchDeletionMode::from_flags(no_delete_branch, force_delete), @@ -782,16 +775,11 @@ pub fn handle_remove_current( no_delete_branch: bool, force_delete: bool, force_worktree: bool, - background: bool, config: &WorktrunkConfig, ) -> anyhow::Result { let repo = Repository::current(); - // Show progress (unless running in background - output handler will show command) - if !background { - crate::output::print(progress_message("Removing current worktree..."))?; - } - + // Progress message is shown in handle_removed_worktree_output() after pre-remove hooks run repo.prepare_worktree_removal( RemoveTarget::Current, BranchDeletionMode::from_flags(no_delete_branch, force_delete), diff --git a/src/main.rs b/src/main.rs index 64c566994..497a59403 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1484,14 +1484,9 @@ fn main() { if branches.is_empty() { // No branches specified, remove current worktree // Uses path-based removal to handle detached HEAD state - let result = handle_remove_current( - !delete_branch, - force_delete, - force, - background, - &config, - ) - .context("Failed to remove worktree")?; + let result = + handle_remove_current(!delete_branch, force_delete, force, &config) + .context("Failed to remove worktree")?; // Approval was handled at the gate // Post-switch hooks are spawned internally by handle_remove_output handle_remove_output(&result, background, verify) @@ -1545,7 +1540,6 @@ fn main() { !delete_branch, force_delete, force, - background, &config, ) { Ok(result) => { @@ -1560,14 +1554,7 @@ fn main() { // Handle branch-only cases (no worktree) for branch in &branch_only { - match handle_remove( - branch, - !delete_branch, - force_delete, - force, - background, - &config, - ) { + match handle_remove(branch, !delete_branch, force_delete, force, &config) { Ok(result) => { handle_remove_output(&result, background, verify)?; } @@ -1581,13 +1568,7 @@ fn main() { // Remove current worktree last (if it was in the list) // Post-switch hooks are spawned internally by handle_remove_output if let Some((_path, _branch)) = current { - match handle_remove_current( - !delete_branch, - force_delete, - force, - background, - &config, - ) { + match handle_remove_current(!delete_branch, force_delete, force, &config) { Ok(result) => { handle_remove_output(&result, background, verify)?; } diff --git a/src/output/handlers.rs b/src/output/handlers.rs index 12c3b30c5..b2147f3b5 100644 --- a/src/output/handlers.rs +++ b/src/output/handlers.rs @@ -619,6 +619,10 @@ fn handle_removed_worktree_output( None, )?; } else { + // Progress message after pre-remove hooks, before actual removal + super::print(progress_message( + "Removing worktree (detached HEAD, no branch to delete)...", + ))?; let target_repo = worktrunk::git::Repository::at(worktree_path); let _ = target_repo.run_command(&["fsmonitor--daemon", "stop"]); if let Err(err) = repo.remove_worktree(worktree_path, force_worktree) { @@ -742,6 +746,11 @@ fn handle_removed_worktree_output( } else { // Synchronous mode: remove immediately and report actual results + // Progress message after pre-remove hooks, before actual removal + super::print(progress_message(cformat!( + "Removing {branch_name} worktree..." + )))?; + // Stop fsmonitor daemon first (best effort - ignore errors) // This prevents zombie daemons from accumulating when using builtin fsmonitor let target_repo = worktrunk::git::Repository::at(worktree_path); diff --git a/tests/snapshots/integration__integration_tests__remove__pre_remove_hook_executes.snap b/tests/snapshots/integration__integration_tests__remove__pre_remove_hook_executes.snap index 6ae597ebb..beaf7cf8b 100644 --- a/tests/snapshots/integration__integration_tests__remove__pre_remove_hook_executes.snap +++ b/tests/snapshots/integration__integration_tests__remove__pre_remove_hook_executes.snap @@ -9,7 +9,7 @@ info: env: APPDATA: "[TEST_CONFIG_HOME]" CLICOLOR_FORCE: "1" - COLUMNS: "150" + COLUMNS: "500" GIT_AUTHOR_DATE: "2025-01-01T00:00:00Z" GIT_COMMITTER_DATE: "2025-01-01T00:00:00Z" GIT_CONFIG_GLOBAL: "[TEST_GIT_CONFIG]" @@ -33,8 +33,8 @@ exit_code: 0 ----- stdout ----- ----- stderr ----- -◎ Removing feature-hook worktree... ◎ Running pre-remove project hook @ _REPO_.feature-hook:   echo 'About to remove worktree' About to remove worktree +◎ Removing feature-hook worktree... ✓ Removed feature-hook worktree & branch (same commit as main, _) diff --git a/tests/snapshots/integration__integration_tests__remove__pre_remove_hook_failure_aborts.snap b/tests/snapshots/integration__integration_tests__remove__pre_remove_hook_failure_aborts.snap index cf398862d..e888e85e5 100644 --- a/tests/snapshots/integration__integration_tests__remove__pre_remove_hook_failure_aborts.snap +++ b/tests/snapshots/integration__integration_tests__remove__pre_remove_hook_failure_aborts.snap @@ -9,7 +9,7 @@ info: env: APPDATA: "[TEST_CONFIG_HOME]" CLICOLOR_FORCE: "1" - COLUMNS: "150" + COLUMNS: "500" GIT_AUTHOR_DATE: "2025-01-01T00:00:00Z" GIT_COMMITTER_DATE: "2025-01-01T00:00:00Z" GIT_CONFIG_GLOBAL: "[TEST_GIT_CONFIG]" @@ -33,7 +33,6 @@ exit_code: 1 ----- stdout ----- ----- stderr ----- -◎ Removing feature-fail worktree... ◎ Running pre-remove project hook @ _REPO_.feature-fail:   exit 1 ✗ pre-remove command failed: exit status: 1 diff --git a/tests/snapshots/integration__integration_tests__remove__pre_remove_hook_runs_for_detached_head.snap b/tests/snapshots/integration__integration_tests__remove__pre_remove_hook_runs_for_detached_head.snap index 6418b8985..aa6de5e1b 100644 --- a/tests/snapshots/integration__integration_tests__remove__pre_remove_hook_runs_for_detached_head.snap +++ b/tests/snapshots/integration__integration_tests__remove__pre_remove_hook_runs_for_detached_head.snap @@ -8,7 +8,7 @@ info: env: APPDATA: "[TEST_CONFIG_HOME]" CLICOLOR_FORCE: "1" - COLUMNS: "150" + COLUMNS: "500" GIT_AUTHOR_DATE: "2025-01-01T00:00:00Z" GIT_COMMITTER_DATE: "2025-01-01T00:00:00Z" GIT_CONFIG_GLOBAL: "[TEST_GIT_CONFIG]" @@ -32,7 +32,7 @@ exit_code: 0 ----- stdout ----- ----- stderr ----- -◎ Removing current worktree... ◎ Running pre-remove project hook:   touch _REPO_/m.txt -✓ Removed worktree (detached HEAD, no branch to delete) +◎ Removing worktree (detached HEAD, no branch to delete)... +✓ Removed worktree (detached HEAD, no branch to delete) diff --git a/tests/snapshots/integration__integration_tests__remove__pre_remove_hook_template_variables.snap b/tests/snapshots/integration__integration_tests__remove__pre_remove_hook_template_variables.snap index c2a89c90a..f982587c0 100644 --- a/tests/snapshots/integration__integration_tests__remove__pre_remove_hook_template_variables.snap +++ b/tests/snapshots/integration__integration_tests__remove__pre_remove_hook_template_variables.snap @@ -9,7 +9,7 @@ info: env: APPDATA: "[TEST_CONFIG_HOME]" CLICOLOR_FORCE: "1" - COLUMNS: "150" + COLUMNS: "500" GIT_AUTHOR_DATE: "2025-01-01T00:00:00Z" GIT_COMMITTER_DATE: "2025-01-01T00:00:00Z" GIT_CONFIG_GLOBAL: "[TEST_GIT_CONFIG]" @@ -33,7 +33,6 @@ exit_code: 0 ----- stdout ----- ----- stderr ----- -◎ Removing feature-templates worktree... ◎ Running pre-remove project:branch @ _REPO_.feature-templates:   echo 'Branch: feature-templates' Branch: feature-templates @@ -43,4 +42,5 @@ exit_code: 0 ◎ Running pre-remove project:worktree_name @ _REPO_.feature-templates:   echo 'Name: repo.feature-templates' Name: repo.feature-templates +◎ Removing feature-templates worktree... ✓ Removed feature-templates worktree & branch (same commit as main, _) diff --git a/tests/snapshots/integration__integration_tests__remove__remove_foreground_detached_head.snap b/tests/snapshots/integration__integration_tests__remove__remove_foreground_detached_head.snap index 8c1cb8754..a5c14dcc3 100644 --- a/tests/snapshots/integration__integration_tests__remove__remove_foreground_detached_head.snap +++ b/tests/snapshots/integration__integration_tests__remove__remove_foreground_detached_head.snap @@ -8,7 +8,7 @@ info: env: APPDATA: "[TEST_CONFIG_HOME]" CLICOLOR_FORCE: "1" - COLUMNS: "150" + COLUMNS: "500" GIT_AUTHOR_DATE: "2025-01-01T00:00:00Z" GIT_COMMITTER_DATE: "2025-01-01T00:00:00Z" GIT_CONFIG_GLOBAL: "[TEST_GIT_CONFIG]" @@ -32,5 +32,5 @@ exit_code: 0 ----- stdout ----- ----- stderr ----- -◎ Removing current worktree... +◎ Removing worktree (detached HEAD, no branch to delete)... ✓ Removed worktree (detached HEAD, no branch to delete) diff --git a/tests/snapshots/integration__integration_tests__remove__remove_main_vs_linked__from_linked_succeeds.snap b/tests/snapshots/integration__integration_tests__remove__remove_main_vs_linked__from_linked_succeeds.snap index eea3a9cbf..ffa9e82b2 100644 --- a/tests/snapshots/integration__integration_tests__remove__remove_main_vs_linked__from_linked_succeeds.snap +++ b/tests/snapshots/integration__integration_tests__remove__remove_main_vs_linked__from_linked_succeeds.snap @@ -8,7 +8,7 @@ info: env: APPDATA: "[TEST_CONFIG_HOME]" CLICOLOR_FORCE: "1" - COLUMNS: "150" + COLUMNS: "500" GIT_AUTHOR_DATE: "2025-01-01T00:00:00Z" GIT_COMMITTER_DATE: "2025-01-01T00:00:00Z" GIT_CONFIG_GLOBAL: "[TEST_GIT_CONFIG]" @@ -32,7 +32,7 @@ exit_code: 0 ----- stdout ----- ----- stderr ----- -◎ Removing current worktree... +◎ Removing feature worktree... ✓ Removed feature worktree & branch (same commit as main, _) ▲ Cannot change directory — shell integration not installed ↳ To enable automatic cd, run wt config shell install