From fb132c3861df1a49b09ca8825a9b36bf3ad460e1 Mon Sep 17 00:00:00 2001 From: Jonatan Dahl Date: Thu, 4 Dec 2025 10:41:04 -0500 Subject: [PATCH 1/2] Add up and down commands to root command --- cmd/down.go | 90 +++++++++++++++++++++++++++++++++++++++++++++++++++++ cmd/root.go | 2 ++ cmd/up.go | 53 +++++++++++++++++++++++++++++++ 3 files changed, 145 insertions(+) create mode 100644 cmd/down.go create mode 100644 cmd/up.go diff --git a/cmd/down.go b/cmd/down.go new file mode 100644 index 0000000..cbd5b6b --- /dev/null +++ b/cmd/down.go @@ -0,0 +1,90 @@ +package cmd + +import ( + "bufio" + "fmt" + "os" + "strconv" + "strings" + + "github.com/javoire/stackinator/internal/git" + "github.com/javoire/stackinator/internal/stack" + "github.com/spf13/cobra" +) + +var downCmd = &cobra.Command{ + Use: "down", + Short: "Move to a child branch in the stack", + Long: `Checkout a child branch of the current branch in the stack. + +If the current branch has no children (is at the tip of the stack), +an error message will be displayed. + +If there are multiple children, you will be prompted to select one.`, + Example: ` # Move to child branch + stack down`, + Run: func(cmd *cobra.Command, args []string) { + gitClient := git.NewGitClient() + + if err := runDown(gitClient); err != nil { + fmt.Fprintf(os.Stderr, "Error: %v\n", err) + os.Exit(1) + } + }, +} + +func runDown(gitClient git.GitClient) error { + // Get current branch + currentBranch, err := gitClient.GetCurrentBranch() + if err != nil { + return fmt.Errorf("failed to get current branch: %w", err) + } + + // Get children of current branch + children, err := stack.GetChildrenOf(gitClient, currentBranch) + if err != nil { + return fmt.Errorf("failed to get children: %w", err) + } + + if len(children) == 0 { + return fmt.Errorf("no children (tip of stack)") + } + + var targetBranch string + + if len(children) == 1 { + // Only one child, checkout directly + targetBranch = children[0].Name + } else { + // Multiple children, prompt for selection + fmt.Printf("Multiple children found for %s:\n", currentBranch) + for i, child := range children { + fmt.Printf(" %d) %s\n", i+1, child.Name) + } + fmt.Print("\nSelect branch (1-" + strconv.Itoa(len(children)) + "): ") + + reader := bufio.NewReader(os.Stdin) + input, err := reader.ReadString('\n') + if err != nil { + return fmt.Errorf("failed to read input: %w", err) + } + + input = strings.TrimSpace(input) + selection, err := strconv.Atoi(input) + if err != nil || selection < 1 || selection > len(children) { + return fmt.Errorf("invalid selection: %s", input) + } + + targetBranch = children[selection-1].Name + } + + // Checkout the target branch + if err := gitClient.CheckoutBranch(targetBranch); err != nil { + return fmt.Errorf("failed to checkout child branch %s: %w", targetBranch, err) + } + + fmt.Printf("Switched to child branch: %s\n", targetBranch) + return nil +} + + diff --git a/cmd/root.go b/cmd/root.go index c386bb2..e369529 100644 --- a/cmd/root.go +++ b/cmd/root.go @@ -72,6 +72,8 @@ func init() { rootCmd.AddCommand(renameCmd) rootCmd.AddCommand(reparentCmd) rootCmd.AddCommand(worktreeCmd) + rootCmd.AddCommand(upCmd) + rootCmd.AddCommand(downCmd) } // Execute runs the root command diff --git a/cmd/up.go b/cmd/up.go new file mode 100644 index 0000000..62bc849 --- /dev/null +++ b/cmd/up.go @@ -0,0 +1,53 @@ +package cmd + +import ( + "fmt" + "os" + + "github.com/javoire/stackinator/internal/git" + "github.com/spf13/cobra" +) + +var upCmd = &cobra.Command{ + Use: "up", + Short: "Move to the parent branch in the stack", + Long: `Checkout the parent branch of the current branch in the stack. + +If the current branch has no parent (is at the root of the stack), +an error message will be displayed.`, + Example: ` # Move to parent branch + stack up`, + Run: func(cmd *cobra.Command, args []string) { + gitClient := git.NewGitClient() + + if err := runUp(gitClient); err != nil { + fmt.Fprintf(os.Stderr, "Error: %v\n", err) + os.Exit(1) + } + }, +} + +func runUp(gitClient git.GitClient) error { + // Get current branch + currentBranch, err := gitClient.GetCurrentBranch() + if err != nil { + return fmt.Errorf("failed to get current branch: %w", err) + } + + // Get parent from git config + parent := gitClient.GetConfig(fmt.Sprintf("branch.%s.stackparent", currentBranch)) + + if parent == "" { + return fmt.Errorf("already at stack root (no parent for %s)", currentBranch) + } + + // Checkout the parent branch + if err := gitClient.CheckoutBranch(parent); err != nil { + return fmt.Errorf("failed to checkout parent branch %s: %w", parent, err) + } + + fmt.Printf("Switched to parent branch: %s\n", parent) + return nil +} + + From 244b5586431efb1a16a3680f6f706ac427add7d8 Mon Sep 17 00:00:00 2001 From: Jonatan Dahl Date: Thu, 4 Dec 2025 10:41:37 -0500 Subject: [PATCH 2/2] Remove unnecessary blank lines in down.go and up.go for cleaner code. --- cmd/down.go | 2 -- cmd/up.go | 2 -- 2 files changed, 4 deletions(-) diff --git a/cmd/down.go b/cmd/down.go index cbd5b6b..cd667fc 100644 --- a/cmd/down.go +++ b/cmd/down.go @@ -86,5 +86,3 @@ func runDown(gitClient git.GitClient) error { fmt.Printf("Switched to child branch: %s\n", targetBranch) return nil } - - diff --git a/cmd/up.go b/cmd/up.go index 62bc849..5fa27a3 100644 --- a/cmd/up.go +++ b/cmd/up.go @@ -49,5 +49,3 @@ func runUp(gitClient git.GitClient) error { fmt.Printf("Switched to parent branch: %s\n", parent) return nil } - -