diff --git a/README.md b/README.md index e9b3007..b7a1c6a 100644 --- a/README.md +++ b/README.md @@ -87,7 +87,7 @@ git -C worktree remove --force git -C worktree prune ``` -This only cleans stale Git worktree metadata, such as records left after a worktree directory was removed manually. It does not remove branches. +This only cleans stale Git worktree metadata, such as records left after a worktree directory was removed manually. By itself, `--prune` does not inspect or remove active linked worktrees. It does not remove branches. ## Help diff --git a/internal/wtclean/app.go b/internal/wtclean/app.go index aeccea0..ea8dcbd 100644 --- a/internal/wtclean/app.go +++ b/internal/wtclean/app.go @@ -98,20 +98,24 @@ func (a *App) processRepo(ctx context.Context, opts Options, repo string, summar return } - paths, err := a.listLinkedWorktreePaths(ctx, repo) - if err != nil { - summary.Failed++ - writef(a.stderr, "git wtclean: failed to list worktrees: %s: %v\n", repo, err) - return - } + // In pure prune mode (--prune without a delete option), only clean stale + // worktree metadata and skip listing active worktrees. + if opts.DeleteMode != "" || !opts.Prune { + paths, err := a.listLinkedWorktreePaths(ctx, repo) + if err != nil { + summary.Failed++ + writef(a.stderr, "git wtclean: failed to list worktrees: %s: %v\n", repo, err) + return + } - for _, path := range paths { - summary.Found++ - if opts.DeleteMode == "" { - writef(a.stdout, "Would remove: %s\n", path) - continue + for _, path := range paths { + summary.Found++ + if opts.DeleteMode == "" { + writef(a.stdout, "Would remove: %s\n", path) + continue + } + a.removeWorktree(ctx, opts, repo, path, summary) } - a.removeWorktree(ctx, opts, repo, path, summary) } if opts.Prune { @@ -182,7 +186,7 @@ func (a *App) pruneRepo(ctx context.Context, opts Options, repo string, summary func (a *App) printSummary(opts Options, summary Summary) { if opts.DeleteMode == "" { if opts.Prune { - writef(a.stdout, "Done. found=%d prune_checked=%d failed=%d\n", summary.Found, summary.PruneChecked, summary.Failed) + writef(a.stdout, "Done. prune_checked=%d failed=%d\n", summary.PruneChecked, summary.Failed) return } writef(a.stdout, "Dry run. found=%d. Run %s to remove, or %s to force remove.\n", summary.Found, "'git wtclean -d'", "'git wtclean -D'") diff --git a/internal/wtclean/app_test.go b/internal/wtclean/app_test.go index e11e1e4..867cafc 100644 --- a/internal/wtclean/app_test.go +++ b/internal/wtclean/app_test.go @@ -107,9 +107,7 @@ func TestRunPruneQuietByDefault(t *testing.T) { } want := strings.Join([]string{ - "Would remove: /tmp/repo1/.wt/feature-a", - "Would remove: /tmp/repo2/.wt/feature-b", - "Done. found=2 prune_checked=2 failed=0", + "Done. prune_checked=2 failed=0", "", }, "\n") if stdout.String() != want { @@ -119,6 +117,10 @@ func TestRunPruneQuietByDefault(t *testing.T) { if got := runner.callsContaining("worktree prune"); len(got) != 2 { t.Fatalf("prune call count = %d, want 2: %#v", len(got), got) } + + if got := runner.callsContaining("worktree list"); len(got) != 0 { + t.Fatalf("worktree list calls = %#v, want none", got) + } } func TestRunPruneVerbosePrintsRepositories(t *testing.T) { @@ -131,11 +133,9 @@ func TestRunPruneVerbosePrintsRepositories(t *testing.T) { } want := strings.Join([]string{ - "Would remove: /tmp/repo1/.wt/feature-a", "Pruning: /tmp/repo1", - "Would remove: /tmp/repo2/.wt/feature-b", "Pruning: /tmp/repo2", - "Done. found=2 prune_checked=2 failed=0", + "Done. prune_checked=2 failed=0", "", }, "\n") if stdout.String() != want {