diff --git a/README.md b/README.md index f25b75a..38e00b3 100644 --- a/README.md +++ b/README.md @@ -433,19 +433,17 @@ gh stack view --json Remove a stack from local tracking and delete it on GitHub. Also available as `gh stack delete`. ``` -gh stack unstack [flags] [branch] +gh stack unstack [flags] ``` -If no branch is specified, uses the current branch to find the stack. Deletes the stack on GitHub first, then removes local tracking. Use `--local` to only remove the local tracking entry. +You must have an active stack checked out locally. The command targets the active stack — the one that contains the currently checked out branch. + +Deletes the stack on GitHub first, if it exists, then removes local tracking. Use `--local` to only remove from local tracking. | Flag | Description | |------|-------------| | `--local` | Only delete the stack locally (keep it on GitHub) | -| Argument | Description | -|----------|-------------| -| `[branch]` | A branch in the stack to delete (defaults to the current branch) | - **Examples:** ```sh @@ -454,9 +452,6 @@ gh stack unstack # Only remove local tracking gh stack unstack --local - -# Specify a branch to identify the stack -gh stack unstack feature-auth ``` ### `gh stack merge` diff --git a/cmd/unstack.go b/cmd/unstack.go index dd0b9ca..67762fc 100644 --- a/cmd/unstack.go +++ b/cmd/unstack.go @@ -11,23 +11,19 @@ import ( ) type unstackOptions struct { - target string - local bool + local bool } func UnstackCmd(cfg *config.Config) *cobra.Command { opts := &unstackOptions{} cmd := &cobra.Command{ - Use: "unstack [branch]", + Use: "unstack", Aliases: []string{"delete"}, Short: "Delete a stack locally and on GitHub", - Long: "Remove a stack from local tracking and delete it on GitHub. Use --local to only remove local tracking.", - Args: cobra.MaximumNArgs(1), + Long: "Remove the current active stack from local tracking and delete it on GitHub. Use --local to only remove local tracking.", + Args: cobra.NoArgs, RunE: func(cmd *cobra.Command, args []string) error { - if len(args) > 0 { - opts.target = args[0] - } return runUnstack(cfg, opts) }, } @@ -38,7 +34,7 @@ func UnstackCmd(cfg *config.Config) *cobra.Command { } func runUnstack(cfg *config.Config, opts *unstackOptions) error { - result, err := loadStack(cfg, opts.target) + result, err := loadStack(cfg, "") if err != nil { return ErrNotInStack } diff --git a/cmd/unstack_test.go b/cmd/unstack_test.go index 6cfab57..5f74883 100644 --- a/cmd/unstack_test.go +++ b/cmd/unstack_test.go @@ -94,37 +94,6 @@ func TestUnstack_Local(t *testing.T) { assert.Empty(t, sf.Stacks) } -func TestUnstack_WithTarget(t *testing.T) { - gitDir := t.TempDir() - restore := git.SetOps(&git.MockOps{ - GitDirFn: func() (string, error) { return gitDir, nil }, - CurrentBranchFn: func() (string, error) { return "unrelated", nil }, - }) - defer restore() - - s1 := stack.Stack{ - Trunk: stack.BranchRef{Branch: "main"}, - Branches: []stack.BranchRef{{Branch: "b1"}, {Branch: "b2"}}, - } - s2 := stack.Stack{ - Trunk: stack.BranchRef{Branch: "main"}, - Branches: []stack.BranchRef{{Branch: "b3"}, {Branch: "b4"}}, - } - writeTwoStacks(t, gitDir, s1, s2) - - cfg, outR, errR := config.NewTestConfig() - err := runUnstack(cfg, &unstackOptions{target: "b3", local: true}) - output := collectOutput(cfg, outR, errR) - - require.NoError(t, err) - assert.Contains(t, output, "Stack removed") - - sf, err := stack.Load(gitDir) - require.NoError(t, err) - require.Len(t, sf.Stacks, 1) - assert.Equal(t, []string{"b1", "b2"}, sf.Stacks[0].BranchNames()) -} - func TestUnstack_NoStackID_WarnsAndSkipsAPI(t *testing.T) { gitDir := t.TempDir() restore := git.SetOps(&git.MockOps{ @@ -225,7 +194,7 @@ func TestUnstack_API409_ShowsErrorAndStopsLocalDeletion(t *testing.T) { } func TestUnstack_RemovesCorrectStackByPointer(t *testing.T) { - // Two stacks share the same trunk "main". Targeting "b3" should remove + // Two stacks share the same trunk "main". Current branch "b3" should remove // only the second stack (b3,b4), leaving the first (b1,b2) intact. // This verifies pointer-based removal instead of branch-name-based. gitDir := t.TempDir() @@ -246,7 +215,7 @@ func TestUnstack_RemovesCorrectStackByPointer(t *testing.T) { writeTwoStacks(t, gitDir, s1, s2) cfg, outR, errR := config.NewTestConfig() - err := runUnstack(cfg, &unstackOptions{target: "b3", local: true}) + err := runUnstack(cfg, &unstackOptions{local: true}) output := collectOutput(cfg, outR, errR) require.NoError(t, err) diff --git a/docs/src/content/docs/reference/cli.md b/docs/src/content/docs/reference/cli.md index b4e4cc5..e346def 100644 --- a/docs/src/content/docs/reference/cli.md +++ b/docs/src/content/docs/reference/cli.md @@ -346,10 +346,12 @@ gh stack push --remote upstream Remove a stack from local tracking and delete it on GitHub. Also available as `gh stack delete`. ```sh -gh stack unstack [flags] [branch] +gh stack unstack [flags] ``` -Deletes the stack on GitHub first, then removes it from local tracking. If the remote deletion fails, the local state is left untouched so you can retry. Use `--local` to skip the remote deletion and only remove local tracking. +You must have a branch from the stack checked out locally. The command targets the active stack — the one that contains the currently checked out branch. + +Deletes the stack on GitHub first, if it exists, then removes it from local tracking. If the remote deletion fails, the local state is left untouched so you can retry. Use `--local` to skip the remote deletion and only remove local tracking. This is useful when you need to restructure a stack — remove a branch, reorder branches, rename branches, or make other large changes. After unstacking, use `gh stack init --adopt` to re-create the stack with the desired structure. @@ -357,10 +359,6 @@ This is useful when you need to restructure a stack — remove a branch, reorder |------|-------------| | `--local` | Only delete the stack locally (keep it on GitHub) | -| Argument | Description | -|----------|-------------| -| `[branch]` | A branch in the stack to identify which stack to delete (defaults to the current branch) | - **Examples:** ```sh @@ -369,9 +367,6 @@ gh stack unstack # Only remove local tracking gh stack unstack --local - -# Specify a branch to identify which stack -gh stack unstack feature-auth ``` ### `gh stack link` diff --git a/skills/gh-stack/SKILL.md b/skills/gh-stack/SKILL.md index 0717dde..7ec397a 100644 --- a/skills/gh-stack/SKILL.md +++ b/skills/gh-stack/SKILL.md @@ -788,8 +788,10 @@ When a branch name is provided, the command resolves it against locally tracked Tear down a stack so you can restructure it — remove a branch, reorder branches, rename branches, or make other large changes. After unstacking, use `gh stack init` to re-create the stack with the desired structure. +You must have a branch from the stack checked out locally. The command targets the active stack — the one that contains the currently checked out branch. + ``` -gh stack unstack [flags] [branch] +gh stack unstack [flags] ``` ```bash @@ -799,19 +801,12 @@ gh stack init --base main --adopt branch-2 branch-1 branch-3 # reordered # Only remove local tracking (keep the stack on GitHub) gh stack unstack --local - -# Specify a branch to identify which stack to tear down -gh stack unstack feature-auth ``` | Flag | Description | |------|-------------| | `--local` | Only delete the stack locally (keep it on GitHub) | -| Argument | Description | -|----------|-------------| -| `[branch]` | A branch in the stack (defaults to the current branch) | - --- ## Output conventions