Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
56 changes: 28 additions & 28 deletions cmd/worktree/delete.go
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
package worktree

import (
"bytes"
"fmt"
"os"
"os/exec"
"strings"
"bytes"
"fmt"
"os"
"os/exec"
"strings"

"github.com/spf13/cobra"
"github.com/todoengineering/wt/internal/git"
Expand All @@ -15,8 +15,8 @@ import (
var forceDelete bool

var deleteCmd = &cobra.Command{
Use: "delete [worktree-name]",
Short: "Delete a worktree (interactive)",
Use: "delete [worktree-name]",
Short: "Delete a worktree (interactive)",
Long: `Interactive selection of worktree to delete using fzf.
Shows worktree name and associated branch,
requires explicit confirmation,
Expand Down Expand Up @@ -85,26 +85,26 @@ prevents deletion of main repository worktree.`,
os.Exit(1)
}

if !forceDelete {
fmt.Printf("\n🗑️ Worktree Deletion Confirmation\n")
fmt.Printf("━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n")
fmt.Printf("Worktree: %s\n", selectedWorktree.Name)
fmt.Printf("Branch: %s\n", selectedWorktree.Branch)
fmt.Printf("Path: %s\n", selectedWorktree.Path)
fmt.Printf("\n⚠️ WARNING: This will permanently remove:\n")
fmt.Printf(" • The worktree directory and all its contents\n")
fmt.Printf(" • Any uncommitted changes in this worktree\n")
fmt.Printf(" • Associated tmux session (if exists)\n")
fmt.Printf("\nType 'yes' to confirm deletion: ")

var confirmation string
fmt.Scanln(&confirmation)

if strings.ToLower(confirmation) != "yes" {
fmt.Println("✅ Deletion cancelled")
return
}
}
if !forceDelete {
fmt.Printf("\n🗑️ Worktree Deletion Confirmation\n")
fmt.Printf("━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n")
fmt.Printf("Worktree: %s\n", selectedWorktree.Name)
fmt.Printf("Branch: %s\n", selectedWorktree.Branch)
fmt.Printf("Path: %s\n", selectedWorktree.Path)
fmt.Printf("\n⚠️ WARNING: This will permanently remove:\n")
fmt.Printf(" • The worktree directory and all its contents\n")
fmt.Printf(" • Any uncommitted changes in this worktree\n")
fmt.Printf(" • Associated tmux session (if exists)\n")
fmt.Printf("\nType 'yes' to confirm deletion: ")

var confirmation string
fmt.Scanln(&confirmation)

if strings.ToLower(confirmation) != "yes" {
fmt.Println("✅ Deletion cancelled")
return
}
}

// Check for and kill associated tmux session
// Standard session name is <repo>-<worktree>. For backward compatibility,
Expand Down Expand Up @@ -143,7 +143,7 @@ prevents deletion of main repository worktree.`,
}

func init() {
deleteCmd.Flags().BoolVar(&forceDelete, "force", false, "skip confirmation and delete the worktree")
deleteCmd.Flags().BoolVar(&forceDelete, "force", false, "skip confirmation and delete the worktree")
}

func selectWorktreeForDeletion(worktrees []git.Worktree) (git.Worktree, error) {
Expand Down
238 changes: 119 additions & 119 deletions cmd/worktree/list.go
Original file line number Diff line number Diff line change
@@ -1,136 +1,136 @@
package worktree

import (
"encoding/json"
"fmt"
"os"
"encoding/json"
"fmt"
"os"

"github.com/spf13/cobra"
"github.com/todoengineering/wt/internal/git"
"github.com/spf13/cobra"
"github.com/todoengineering/wt/internal/git"
)

var (
listAll bool
listJSON bool
listPathOnly bool
listAll bool
listJSON bool
listPathOnly bool
)

type listEntry struct {
Project string `json:"project"`
Name string `json:"name"`
Path string `json:"path"`
Branch string `json:"branch"`
Project string `json:"project"`
Name string `json:"name"`
Path string `json:"path"`
Branch string `json:"branch"`
}

var listCmd = &cobra.Command{
Use: "list",
Short: "List worktrees",
Long: `Lists on-disk worktrees for the current repository or across all projects when --all is provided. Supports JSON and path-only output for scripting.`,
Run: func(cmd *cobra.Command, args []string) {
if listAll {
projects, err := git.ListAllProjects()
if err != nil {
fmt.Fprintf(os.Stderr, "Error listing projects: %v\n", err)
os.Exit(1)
}

if listJSON {
var out []listEntry
for _, p := range projects {
for _, wt := range p.Worktrees {
out = append(out, listEntry{Project: p.Name, Name: wt.Name, Path: wt.Path, Branch: wt.Branch})
}
}
enc := json.NewEncoder(os.Stdout)
enc.SetIndent("", " ")
if err := enc.Encode(out); err != nil {
fmt.Fprintf(os.Stderr, "Error encoding JSON: %v\n", err)
os.Exit(1)
}
return
}

if listPathOnly {
for _, p := range projects {
for _, wt := range p.Worktrees {
fmt.Println(wt.Path)
}
}
return
}

if len(projects) == 0 {
fmt.Println("No projects with worktrees found")
fmt.Printf("Worktree base directory: %s\n", git.GetWorktreeBaseDir())
return
}

for _, p := range projects {
fmt.Printf("%s:\n", p.Name)
if len(p.Worktrees) == 0 {
fmt.Println(" (no worktrees)")
continue
}
for _, wt := range p.Worktrees {
fmt.Printf(" %s -> %s\n", wt.Name, wt.Path)
}
}
return
}

if !git.IsGitRepository() {
fmt.Fprintf(os.Stderr, "Error: not in a git repository\n")
os.Exit(1)
}

repoName, err := git.GetRepositoryName()
if err != nil {
fmt.Fprintf(os.Stderr, "Error: %v\n", err)
os.Exit(1)
}

worktrees, err := git.ListWorktrees(repoName)
if err != nil {
fmt.Fprintf(os.Stderr, "Error listing worktrees: %v\n", err)
os.Exit(1)
}

if listJSON {
var out []listEntry
for _, wt := range worktrees {
out = append(out, listEntry{Project: repoName, Name: wt.Name, Path: wt.Path, Branch: wt.Branch})
}
enc := json.NewEncoder(os.Stdout)
enc.SetIndent("", " ")
if err := enc.Encode(out); err != nil {
fmt.Fprintf(os.Stderr, "Error encoding JSON: %v\n", err)
os.Exit(1)
}
return
}

if listPathOnly {
for _, wt := range worktrees {
fmt.Println(wt.Path)
}
return
}

if len(worktrees) == 0 {
fmt.Printf("No worktrees found for repository '%s'\n", repoName)
fmt.Printf("Worktree directory: %s\n", git.GetWorktreeDir(repoName))
return
}

fmt.Printf("Worktrees for repository '%s':\n", repoName)
for _, wt := range worktrees {
fmt.Printf(" %s -> %s\n", wt.Name, wt.Path)
}
},
Use: "list",
Short: "List worktrees",
Long: `Lists on-disk worktrees for the current repository or across all projects when --all is provided. Supports JSON and path-only output for scripting.`,
Run: func(cmd *cobra.Command, args []string) {
if listAll {
projects, err := git.ListAllProjects()
if err != nil {
fmt.Fprintf(os.Stderr, "Error listing projects: %v\n", err)
os.Exit(1)
}

if listJSON {
var out []listEntry
for _, p := range projects {
for _, wt := range p.Worktrees {
out = append(out, listEntry{Project: p.Name, Name: wt.Name, Path: wt.Path, Branch: wt.Branch})
}
}
enc := json.NewEncoder(os.Stdout)
enc.SetIndent("", " ")
if err := enc.Encode(out); err != nil {
fmt.Fprintf(os.Stderr, "Error encoding JSON: %v\n", err)
os.Exit(1)
}
return
}

if listPathOnly {
for _, p := range projects {
for _, wt := range p.Worktrees {
fmt.Println(wt.Path)
}
}
return
}

if len(projects) == 0 {
fmt.Println("No projects with worktrees found")
fmt.Printf("Worktree base directory: %s\n", git.GetWorktreeBaseDir())
return
}

for _, p := range projects {
fmt.Printf("%s:\n", p.Name)
if len(p.Worktrees) == 0 {
fmt.Println(" (no worktrees)")
continue
}
for _, wt := range p.Worktrees {
fmt.Printf(" %s -> %s\n", wt.Name, wt.Path)
}
}
return
}

if !git.IsGitRepository() {
fmt.Fprintf(os.Stderr, "Error: not in a git repository\n")
os.Exit(1)
}

repoName, err := git.GetRepositoryName()
if err != nil {
fmt.Fprintf(os.Stderr, "Error: %v\n", err)
os.Exit(1)
}

worktrees, err := git.ListWorktrees(repoName)
if err != nil {
fmt.Fprintf(os.Stderr, "Error listing worktrees: %v\n", err)
os.Exit(1)
}

if listJSON {
var out []listEntry
for _, wt := range worktrees {
out = append(out, listEntry{Project: repoName, Name: wt.Name, Path: wt.Path, Branch: wt.Branch})
}
enc := json.NewEncoder(os.Stdout)
enc.SetIndent("", " ")
if err := enc.Encode(out); err != nil {
fmt.Fprintf(os.Stderr, "Error encoding JSON: %v\n", err)
os.Exit(1)
}
return
}

if listPathOnly {
for _, wt := range worktrees {
fmt.Println(wt.Path)
}
return
}

if len(worktrees) == 0 {
fmt.Printf("No worktrees found for repository '%s'\n", repoName)
fmt.Printf("Worktree directory: %s\n", git.GetWorktreeDir(repoName))
return
}

fmt.Printf("Worktrees for repository '%s':\n", repoName)
for _, wt := range worktrees {
fmt.Printf(" %s -> %s\n", wt.Name, wt.Path)
}
},
}

func init() {
listCmd.Flags().BoolVar(&listAll, "all", false, "list across all projects")
listCmd.Flags().BoolVar(&listJSON, "json", false, "output JSON for scripting")
listCmd.Flags().BoolVar(&listPathOnly, "path-only", false, "output only worktree paths")
listCmd.Flags().BoolVar(&listAll, "all", false, "list across all projects")
listCmd.Flags().BoolVar(&listJSON, "json", false, "output JSON for scripting")
listCmd.Flags().BoolVar(&listPathOnly, "path-only", false, "output only worktree paths")
}
Loading