@@ -30,33 +30,47 @@ _clean_detect_provider() {
3030
3131# Check if a worktree should be skipped during merged cleanup.
3232# Returns 0 if should skip, 1 if should process.
33- # Usage: _clean_should_skip <dir> <branch>
33+ # Usage: _clean_should_skip <dir> <branch> [force] [active_worktree_path]
3434_clean_should_skip () {
35- local dir=" $1 " branch=" $2 "
35+ local dir=" $1 " branch=" $2 " force=" ${3:- 0} " active_worktree_path=" ${4:- } "
36+ local dir_canonical=" $dir "
37+ local active_worktree_canonical=" $active_worktree_path "
3638
37- if [ -z " $branch " ] || [ " $branch " = " (detached) " ]; then
38- log_warn " Skipping $dir (detached HEAD) "
39- return 0
39+ if [ -n " $active_worktree_path " ]; then
40+ dir_canonical= $( canonicalize_path " $dir " || printf " %s " " $dir " )
41+ active_worktree_canonical= $( canonicalize_path " $active_worktree_path " || printf " %s " " $active_worktree_path " )
4042 fi
4143
42- if ! git -C " $dir " diff --quiet 2> /dev/null || \
43- ! git -C " $dir " diff --cached --quiet 2> /dev/null; then
44- log_warn " Skipping $branch (has uncommitted changes)"
44+ if [ -n " $active_worktree_path " ] && [ " $dir_canonical " = " $active_worktree_canonical " ]; then
45+ log_warn " Skipping $branch (current active worktree)"
4546 return 0
4647 fi
4748
48- if [ -n " $( git -C " $dir " ls-files --others --exclude-standard 2> /dev/null ) " ]; then
49- log_warn " Skipping $branch (has untracked files )"
49+ if [ -z " $branch " ] || [ " $branch " = " (detached )" ]; then
50+ log_warn " Skipping $dir (detached HEAD )"
5051 return 0
5152 fi
5253
54+ if [ " $force " -eq 0 ]; then
55+ if ! git -C " $dir " diff --quiet 2> /dev/null || \
56+ ! git -C " $dir " diff --cached --quiet 2> /dev/null; then
57+ log_warn " Skipping $branch (has uncommitted changes)"
58+ return 0
59+ fi
60+
61+ if [ -n " $( git -C " $dir " ls-files --others --exclude-standard 2> /dev/null) " ]; then
62+ log_warn " Skipping $branch (has untracked files)"
63+ return 0
64+ fi
65+ fi
66+
5367 return 1
5468}
5569
5670# Remove worktrees whose PRs/MRs are merged (handles squash merges)
57- # Usage: _clean_merged repo_root base_dir prefix yes_mode dry_run
71+ # Usage: _clean_merged repo_root base_dir prefix yes_mode dry_run [force] [active_worktree_path]
5872_clean_merged () {
59- local repo_root=" $1 " base_dir=" $2 " prefix=" $3 " yes_mode=" $4 " dry_run=" $5 "
73+ local repo_root=" $1 " base_dir=" $2 " prefix=" $3 " yes_mode=" $4 " dry_run=" $5 " force= " ${6 :- 0} " active_worktree_path= " ${7 :- } "
6074
6175 log_step " Checking for worktrees with merged PRs/MRs..."
6276
@@ -80,7 +94,7 @@ _clean_merged() {
8094 # Skip main repo branch silently (not counted)
8195 [ " $branch " = " $main_branch " ] && continue
8296
83- if _clean_should_skip " $dir " " $branch " ; then
97+ if _clean_should_skip " $dir " " $branch " " $force " " $active_worktree_path " ; then
8498 skipped=$(( skipped + 1 ))
8599 continue
86100 fi
@@ -102,7 +116,7 @@ _clean_merged() {
102116 continue
103117 fi
104118
105- if remove_worktree " $dir " 0 ; then
119+ if remove_worktree " $dir " " $force " ; then
106120 git branch -d " $branch " 2> /dev/null || git branch -D " $branch " 2> /dev/null || true
107121 removed=$(( removed + 1 ))
108122
@@ -133,12 +147,15 @@ cmd_clean() {
133147 local _spec
134148 _spec=" --merged
135149--yes|-y
136- --dry-run|-n"
150+ --dry-run|-n
151+ --force|-f"
137152 parse_args " $_spec " " $@ "
138153
139154 local merged_mode=" ${_arg_merged:- 0} "
140155 local yes_mode=" ${_arg_yes:- 0} "
141156 local dry_run=" ${_arg_dry_run:- 0} "
157+ local force=" ${_arg_force:- 0} "
158+ local active_worktree_path=" "
142159
143160 log_step " Cleaning up stale worktrees..."
144161
@@ -151,6 +168,11 @@ cmd_clean() {
151168
152169 local repo_root=" $_ctx_repo_root " base_dir=" $_ctx_base_dir " prefix=" $_ctx_prefix "
153170
171+ active_worktree_path=$( git rev-parse --show-toplevel 2> /dev/null || true)
172+ if [ -n " $active_worktree_path " ]; then
173+ active_worktree_path=$( canonicalize_path " $active_worktree_path " || printf " %s" " $active_worktree_path " )
174+ fi
175+
154176 if [ ! -d " $base_dir " ]; then
155177 log_info " No worktrees directory to clean"
156178 return 0
182204
183205 # --merged mode: remove worktrees with merged PRs/MRs (handles squash merges)
184206 if [ " $merged_mode " -eq 1 ]; then
185- _clean_merged " $repo_root " " $base_dir " " $prefix " " $yes_mode " " $dry_run "
207+ _clean_merged " $repo_root " " $base_dir " " $prefix " " $yes_mode " " $dry_run " " $force " " $active_worktree_path "
186208 fi
187- }
209+ }
0 commit comments