Skip to content

Clean up empty parent dirs when removing a worktree#116

Open
bigs wants to merge 2 commits intosatococoa:mainfrom
bigs:feat/cleanup-empty-parent-dirs
Open

Clean up empty parent dirs when removing a worktree#116
bigs wants to merge 2 commits intosatococoa:mainfrom
bigs:feat/cleanup-empty-parent-dirs

Conversation

@bigs
Copy link
Copy Markdown
Contributor

@bigs bigs commented Apr 22, 2026

Heya, as always feel free to close this if you’re not interested!

I frequently use slashes in my branch names, e.g. fix/foo, feat/bar. wtp creates these in nested directories within base_dir which is fine, but when cleaning up a worktree, it doesn’t iteratively remove empty directories back up to base_dir. This PR changes that to keep my worktree base_dir nice and tidy. I’m using it locally.

Details

After git worktree remove, walk from the worktree's parent up to the resolved base_dir, removing each directory that is still empty. This keeps prefixed branch layouts like feat/my-feature from leaving behind empty feat/ dirs under base_dir. Cleanup is best-effort and stops at the first non-empty directory or when it reaches base_dir.

Summary by CodeRabbit

  • New Features
    • Worktree removal now automatically cleans up empty parent directories down to the configured base directory.

After `git worktree remove`, walk from the worktree's parent up to the
resolved `base_dir`, removing each directory that is still empty. This
keeps prefixed branch layouts like `feat/my-feature` from leaving behind
empty `feat/` dirs under `base_dir`. Cleanup is best-effort and stops at
the first non-empty directory or when it reaches `base_dir`.
@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Apr 22, 2026

Warning

Rate limit exceeded

@bigs has exceeded the limit for the number of commits that can be reviewed per hour. Please wait 54 minutes and 1 seconds before requesting another review.

Your organization is not enrolled in usage-based pricing. Contact your admin to enable usage-based pricing to continue reviews beyond the rate limit, or try again in 54 minutes and 1 seconds.

⌛ How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout.

Please see our FAQ for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 814f4408-57da-4a5d-9088-83ab243b5548

📥 Commits

Reviewing files that changed from the base of the PR and between 184066f and 776e74f.

📒 Files selected for processing (1)
  • cmd/wtp/remove.go
📝 Walkthrough

Walkthrough

The wtp remove command now includes best-effort cleanup of empty parent directories after successfully removing a worktree. New helper functions load the main worktree's configuration to determine the base directory, then traverse upward from the removed worktree's parent, removing empty directories until encountering a non-empty directory or the base directory boundary.

Changes

Cohort / File(s) Summary
Worktree Removal Cleanup
cmd/wtp/remove.go, cmd/wtp/remove_test.go
Added helper functions removeEmptyParentsUpTo() and cleanupEmptyParentDirs() for post-removal directory cleanup. Includes comprehensive test coverage for single/multiple nested empty directory removal, boundary conditions, and error tolerance scenarios.

Sequence Diagram

sequenceDiagram
    participant User
    participant WtpCommand
    participant ConfigLoader
    participant FileSystem

    User->>WtpCommand: wtp remove [worktree]
    WtpCommand->>FileSystem: Remove worktree
    WtpCommand->>ConfigLoader: Load .wtp.yml from main worktree
    ConfigLoader->>FileSystem: Read config file
    ConfigLoader-->>WtpCommand: Return base_dir (absolute path)
    WtpCommand->>FileSystem: Check parent directory of removed worktree
    loop Traverse upward to base_dir
        WtpCommand->>FileSystem: Is directory empty?
        alt Directory is empty
            WtpCommand->>FileSystem: Remove directory
            WtpCommand->>FileSystem: Check next parent
        else Directory is non-empty or is base_dir
            WtpCommand->>WtpCommand: Stop cleanup
        end
    end
    WtpCommand-->>User: Command completes
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Suggested labels

codex

Poem

🐰 A worktree departs, leaving trails behind,
So up we hop, empty nests to find—
From child to parent, we bound and clean,
Till a cozy home stops our tidying spree.
One less clutter in the forest scene! 🌳

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 57.14% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and accurately describes the main change: adding empty parent directory cleanup when removing a worktree.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@codecov-commenter
Copy link
Copy Markdown

Welcome to Codecov 🎉

Once you merge this PR into your default branch, you're all set! Codecov will compare coverage reports and display results in all future pull requests.

Thanks for integrating Codecov - We've got you covered ☂️

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
cmd/wtp/remove.go (1)

151-158: ⚠️ Potential issue | 🟡 Minor

Defer parent cleanup until after branch deletion.

If the user runs wtp remove --with-branch from an empty prefix directory that cleanup removes, the subsequent git branch command may inherit a deleted current directory. Deferring cleanup keeps the best-effort behavior but runs it after all git operations complete.

🐛 Proposed fix
-	// Clean up empty parent directories between the worktree and base_dir
-	cleanupEmptyParentDirs(absTargetPath, worktrees)
+	// Clean up empty parent directories between the worktree and base_dir
+	// after all git operations complete.
+	defer cleanupEmptyParentDirs(absTargetPath, worktrees)
 
 	// Remove branch if requested
 	if withBranch && targetWorktree.Branch != "" {
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@cmd/wtp/remove.go` around lines 151 - 158, Move the call to
cleanupEmptyParentDirs so it runs after all git operations (specifically after
removeBranchWithCommandExecutor completes) to avoid deleting the current working
directory before running git branch commands; locate the
cleanupEmptyParentDirs(absTargetPath, worktrees) invocation and the block that
calls removeBranchWithCommandExecutor(w, executor, targetWorktree.Branch,
forceBranch) (guarded by withBranch and targetWorktree.Branch) and reposition
the cleanup call to execute after that branch-removal block (and any other git
commands) so cleanup remains best-effort but occurs last.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Outside diff comments:
In `@cmd/wtp/remove.go`:
- Around line 151-158: Move the call to cleanupEmptyParentDirs so it runs after
all git operations (specifically after removeBranchWithCommandExecutor
completes) to avoid deleting the current working directory before running git
branch commands; locate the cleanupEmptyParentDirs(absTargetPath, worktrees)
invocation and the block that calls removeBranchWithCommandExecutor(w, executor,
targetWorktree.Branch, forceBranch) (guarded by withBranch and
targetWorktree.Branch) and reposition the cleanup call to execute after that
branch-removal block (and any other git commands) so cleanup remains best-effort
but occurs last.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: f4759adf-8833-465b-b7e0-4e71bed5b04b

📥 Commits

Reviewing files that changed from the base of the PR and between 842920d and 184066f.

📒 Files selected for processing (2)
  • cmd/wtp/remove.go
  • cmd/wtp/remove_test.go

When `wtp remove --with-branch` is invoked from inside a directory that
cleanup removes (a prefix parent under base_dir), the subsequent
`git branch -d` inherits a deleted cwd and can fail. Defer cleanup so it
runs last, after all git operations.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants