Class: Ace::Git::Worktree::Molecules::WorktreeRemover
- Inherits:
-
Object
- Object
- Ace::Git::Worktree::Molecules::WorktreeRemover
- Defined in:
- lib/ace/git/worktree/molecules/worktree_remover.rb
Overview
Worktree remover molecule
Removes git worktrees with proper cleanup, validation, and error handling. Provides options for force removal and handles various edge cases.
Constant Summary collapse
- FALLBACK_TIMEOUT =
Fallback timeout for git commands Used only when config is unavailable
30
Instance Method Summary collapse
-
#check_removal_safety(worktree_path) ⇒ Hash
Check if a worktree can be safely removed.
-
#delete_branch_if_safe(branch_name, force) ⇒ Hash
Delete a branch if it’s safe to do so.
-
#initialize(timeout: nil) ⇒ WorktreeRemover
constructor
Initialize a new WorktreeRemover.
-
#prune ⇒ Hash
Prune deleted worktrees (cleanup git metadata).
-
#remove(worktree_path, force: false, remove_directory: true, delete_branch: false, ignore_untracked: false) ⇒ Hash
Remove a worktree by path.
-
#remove_by_branch(branch_name, force: false) ⇒ Hash
Remove a worktree by branch name.
-
#remove_by_task_id(task_id, force: false) ⇒ Hash
Remove a worktree by task ID.
-
#remove_multiple(worktree_paths, force: false) ⇒ Hash
Remove multiple worktrees.
Constructor Details
#initialize(timeout: nil) ⇒ WorktreeRemover
Initialize a new WorktreeRemover
26 27 28 |
# File 'lib/ace/git/worktree/molecules/worktree_remover.rb', line 26 def initialize(timeout: nil) @timeout = timeout || config_timeout end |
Instance Method Details
#check_removal_safety(worktree_path) ⇒ Hash
Check if a worktree can be safely removed
218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 |
# File 'lib/ace/git/worktree/molecules/worktree_remover.rb', line 218 def check_removal_safety(worktree_path) = File.(worktree_path) result = { safe: true, warnings: [], errors: [] } # Check if worktree exists worktree_info = find_worktree_info() unless worktree_info result[:safe] = false result[:errors] << "Worktree not found" return result end # Check for uncommitted changes if has_uncommitted_changes?() result[:safe] = false result[:errors] << "Worktree has uncommitted changes" end # Check if it's the current worktree current_dir = Dir.pwd if File.(current_dir) == result[:warnings] << "Currently in this worktree" end # Check if it's the main worktree if worktree_info.branch.nil || worktree_info.detached || worktree_info. result[:warnings] << "This might be the main worktree" end result end |
#delete_branch_if_safe(branch_name, force) ⇒ Hash
Delete a branch if it’s safe to do so
389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 |
# File 'lib/ace/git/worktree/molecules/worktree_remover.rb', line 389 def delete_branch_if_safe(branch_name, force) require_relative "../atoms/git_command" # Check if branch is already merged (unless forcing) unless force # Check if branch is merged into current branch result = Atoms::GitCommand.execute("branch", "--merged", timeout: @timeout) if result[:success] merged_branches = result[:output].split("\n").map(&:strip).map { |b| b.gsub(/^\*?\s*/, "") } unless merged_branches.include?(branch_name) # Branch is not merged, don't delete unless forced warn "Warning: Branch #{branch_name} is not merged. Skipping deletion. Use --force to delete anyway." return {success: false, message: "Branch not merged", error: nil} end end end # Delete the branch delete_flag = force ? "-D" : "-d" result = Atoms::GitCommand.execute("branch", delete_flag, branch_name, timeout: @timeout) if result[:success] {success: true, message: "Branch #{branch_name} deleted", error: nil} else {success: false, message: nil, error: "Failed to delete branch: #{result[:error]}"} end end |
#prune ⇒ Hash
Prune deleted worktrees (cleanup git metadata)
187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 |
# File 'lib/ace/git/worktree/molecules/worktree_remover.rb', line 187 def prune result = execute_git_worktree_prune if result[:success] # Parse output to count pruned worktrees pruned_count = parse_prune_output(result[:output]) { success: true, message: "Pruned #{pruned_count} worktree(s)", pruned_count: pruned_count, error: nil } else error_result("Failed to prune worktrees: #{result[:error]}") end rescue => e error_result("Unexpected error during prune: #{e.}") end |
#remove(worktree_path, force: false, remove_directory: true, delete_branch: false, ignore_untracked: false) ⇒ Hash
Remove a worktree by path
55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 |
# File 'lib/ace/git/worktree/molecules/worktree_remover.rb', line 55 def remove( worktree_path, force: false, remove_directory: true, delete_branch: false, ignore_untracked: false ) return error_result("Worktree path is required") if worktree_path.nil? || worktree_path.empty? begin = File.(worktree_path) # Check if worktree exists worktree_info = find_worktree_info() return error_result("Worktree not found at #{}") unless worktree_info # Check for uncommitted changes if !force && has_uncommitted_changes?(, ignore_untracked: ignore_untracked) return error_result("Worktree has uncommitted changes. Use --force to remove anyway.") end # Store branch name before removal branch_name = worktree_info.branch # Remove the worktree using git # When ignore_untracked is true, we've already verified there are no tracked changes, # so pass force: true to skip git's own untracked-file check. result = remove_git_worktree(, force: force || ignore_untracked) return result unless result[:success] # Optionally remove the directory if remove_directory && File.exist?() directory_result = remove_worktree_directory() return directory_result unless directory_result[:success] end # Optionally delete the branch branch_deleted = false if delete_branch && branch_name && !branch_name.empty? delete_result = delete_branch_if_safe(branch_name, force) branch_deleted = delete_result[:success] end { success: true, message: "Worktree removed successfully", path: , branch: branch_name, branch_deleted: branch_deleted, error: nil } rescue => e error_result("Unexpected error: #{e.}") end end |
#remove_by_branch(branch_name, force: false) ⇒ Hash
Remove a worktree by branch name
119 120 121 122 123 124 125 126 127 |
# File 'lib/ace/git/worktree/molecules/worktree_remover.rb', line 119 def remove_by_branch(branch_name, force: false) return error_result("Branch name is required") if branch_name.nil? || branch_name.empty? # Find worktree by branch worktree_info = find_worktree_by_branch(branch_name) return error_result("No worktree found for branch: #{branch_name}") unless worktree_info remove(worktree_info.path, force: force) end |
#remove_by_task_id(task_id, force: false) ⇒ Hash
Remove a worktree by task ID
137 138 139 140 141 142 143 144 145 |
# File 'lib/ace/git/worktree/molecules/worktree_remover.rb', line 137 def remove_by_task_id(task_id, force: false) return error_result("Task ID is required") if task_id.nil? || task_id.empty? # Find worktree by task ID worktree_info = find_worktree_by_task_id(task_id) return error_result("No worktree found for task: #{task_id}") unless worktree_info remove(worktree_info.path, force: force) end |
#remove_multiple(worktree_paths, force: false) ⇒ Hash
Remove multiple worktrees
156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 |
# File 'lib/ace/git/worktree/molecules/worktree_remover.rb', line 156 def remove_multiple(worktree_paths, force: false) return error_result("Worktree paths array is required") if worktree_paths.nil? || worktree_paths.empty? results = { success: true, removed: [], failed: [], errors: {} } Array(worktree_paths).each do |path| result = remove(path, force: force) if result[:success] results[:removed] << path else results[:success] = false results[:failed] << path results[:errors][path] = result[:error] end end results end |