Skip to content

Commit 115ce65

Browse files
authored
fix: rename cascade to restack more generally (#94)
`cascade` is still retained as an alias of `restack`. **WARNING**: This may invalidate in-progress cascade operations if you happen to upgrade `gh-stack` in the middle of one. Don't do that.
1 parent 96fb5b9 commit 115ce65

18 files changed

Lines changed: 188 additions & 188 deletions

cmd/abort.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ func runAbort(cmd *cobra.Command, args []string) error {
3333

3434
g := git.New(cwd)
3535

36-
// Check if cascade in progress
36+
// Check if restack in progress
3737
st, err := state.Load(g.GetGitDir())
3838
if err != nil {
3939
return errors.New("no operation in progress")

cmd/continue.go

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,7 @@ func runContinue(cmd *cobra.Command, args []string) error {
6969
}
7070

7171
// Update fork point for the branch that just finished rebasing.
72-
// The cascade loop's fork point update only fires after a non-conflicting
72+
// The restack loop's fork point update only fires after a non-conflicting
7373
// rebase, so branches that hit a conflict never get their fork point
7474
// refreshed -- leaving it stale for future operations.
7575
if parent, parentErr := cfg.GetParent(st.Current); parentErr == nil {
@@ -84,7 +84,7 @@ func runContinue(cmd *cobra.Command, args []string) error {
8484
return err
8585
}
8686

87-
// If there are more branches to cascade, continue cascading
87+
// If there are more branches to restack, continue cascading
8888
if len(st.Pending) > 0 {
8989
var branches []*tree.Node
9090
for _, name := range st.Pending {
@@ -96,26 +96,26 @@ func runContinue(cmd *cobra.Command, args []string) error {
9696
// Remove state file before continuing (will be recreated if conflict)
9797
_ = state.Remove(g.GetGitDir()) //nolint:errcheck // cleanup
9898

99-
if cascadeErr := doCascadeWithState(g, cfg, branches, CascadeOptions{
99+
if restackErr := doRestackWithState(g, cfg, branches, RestackOptions{
100100
Operation: st.Operation,
101101
UpdateOnly: st.UpdateOnly,
102102
OpenWeb: st.Web,
103103
PushOnly: st.PushOnly,
104104
Branches: st.Branches,
105105
StashRef: st.StashRef,
106106
Worktrees: st.Worktrees,
107-
}, s); cascadeErr != nil {
108-
// Stash handling is done by doCascadeWithState (conflict saves in state, errors restore)
109-
if !errors.Is(cascadeErr, ErrConflict) && st.StashRef != "" {
107+
}, s); restackErr != nil {
108+
// Stash handling is done by doRestackWithState (conflict saves in state, errors restore)
109+
if !errors.Is(restackErr, ErrConflict) && st.StashRef != "" {
110110
fmt.Println("Restoring auto-stashed changes...")
111111
if popErr := g.StashPop(st.StashRef); popErr != nil {
112112
fmt.Printf("%s could not restore stashed changes (commit %s): %v\n", s.WarningIcon(), git.AbbrevSHA(st.StashRef), popErr)
113113
}
114114
}
115-
return cascadeErr // Another conflict - state saved
115+
return restackErr // Another conflict - state saved
116116
}
117117
} else {
118-
// No more branches to cascade - cleanup state
118+
// No more branches to restack - cleanup state
119119
_ = state.Remove(g.GetGitDir()) //nolint:errcheck // cleanup
120120
}
121121

@@ -160,7 +160,7 @@ func runContinue(cmd *cobra.Command, args []string) error {
160160
return err
161161
}
162162

163-
// Restore stash after cascade completes
163+
// Restore stash after restack completes
164164
if st.StashRef != "" {
165165
fmt.Println("Restoring auto-stashed changes...")
166166
if popErr := g.StashPop(st.StashRef); popErr != nil {

cmd/cascade.go renamed to cmd/restack.go

Lines changed: 32 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// cmd/cascade.go
1+
// cmd/restack.go
22
package cmd
33

44
import (
@@ -15,31 +15,31 @@ import (
1515
"github.com/spf13/cobra"
1616
)
1717

18-
// ErrConflict indicates a rebase conflict occurred during cascade.
18+
// ErrConflict indicates a rebase conflict occurred during restack.
1919
var ErrConflict = errors.New("rebase conflict: resolve and run 'gh stack continue', or 'gh stack abort'")
2020

21-
var cascadeCmd = &cobra.Command{
21+
var restackCmd = &cobra.Command{
2222
Use: "restack",
2323
Aliases: []string{"cascade"},
2424
Short: "Rebase current branch and descendants onto their parents",
2525
Long: `Rebase the current branch onto its parent, then recursively restack descendants.`,
26-
RunE: runCascade,
26+
RunE: runRestack,
2727
}
2828

2929
var (
30-
cascadeOnlyFlag bool
31-
cascadeDryRunFlag bool
32-
cascadeWorktreesFlag bool
30+
restackOnlyFlag bool
31+
restackDryRunFlag bool
32+
restackWorktreesFlag bool
3333
)
3434

3535
func init() {
36-
cascadeCmd.Flags().BoolVar(&cascadeOnlyFlag, "only", false, "only restack current branch, not descendants")
37-
cascadeCmd.Flags().BoolVar(&cascadeDryRunFlag, "dry-run", false, "show what would be done")
38-
cascadeCmd.Flags().BoolVar(&cascadeWorktreesFlag, "worktrees", false, "rebase branches checked out in linked worktrees in-place")
39-
rootCmd.AddCommand(cascadeCmd)
36+
restackCmd.Flags().BoolVar(&restackOnlyFlag, "only", false, "only restack current branch, not descendants")
37+
restackCmd.Flags().BoolVar(&restackDryRunFlag, "dry-run", false, "show what would be done")
38+
restackCmd.Flags().BoolVar(&restackWorktreesFlag, "worktrees", false, "rebase branches checked out in linked worktrees in-place")
39+
rootCmd.AddCommand(restackCmd)
4040
}
4141

42-
func runCascade(cmd *cobra.Command, args []string) error {
42+
func runRestack(cmd *cobra.Command, args []string) error {
4343
s := style.New()
4444

4545
cwd, err := os.Getwd()
@@ -54,7 +54,7 @@ func runCascade(cmd *cobra.Command, args []string) error {
5454

5555
g := git.New(cwd)
5656

57-
// Check if cascade already in progress
57+
// Check if restack already in progress
5858
if state.Exists(g.GetGitDir()) {
5959
return errors.New("operation already in progress; use 'gh stack continue' or 'gh stack abort'")
6060
}
@@ -76,36 +76,36 @@ func runCascade(cmd *cobra.Command, args []string) error {
7676
return fmt.Errorf("branch %q is not tracked in the stack\n\nTo add it, run:\n gh stack adopt %s # to stack on %s\n gh stack adopt -p <parent> # to stack on a different branch", currentBranch, trunk, trunk)
7777
}
7878

79-
// Collect branches to cascade
79+
// Collect branches to restack
8080
var branches []*tree.Node
8181
branches = append(branches, node)
82-
if !cascadeOnlyFlag {
82+
if !restackOnlyFlag {
8383
branches = append(branches, tree.GetDescendants(node)...)
8484
}
8585

8686
// Save undo snapshot (unless dry-run)
8787
var stashRef string
88-
if !cascadeDryRunFlag {
88+
if !restackDryRunFlag {
8989
var saveErr error
90-
stashRef, saveErr = saveUndoSnapshot(g, cfg, branches, nil, "cascade", "gh stack restack", s)
90+
stashRef, saveErr = saveUndoSnapshot(g, cfg, branches, nil, "restack", "gh stack restack", s)
9191
if saveErr != nil {
9292
fmt.Printf("%s could not save undo state: %v\n", s.WarningIcon(), saveErr)
9393
}
9494
}
9595

9696
// Build worktree map if --worktrees flag is set
9797
var worktrees map[string]string
98-
if cascadeWorktreesFlag {
98+
if restackWorktreesFlag {
9999
var wtErr error
100100
worktrees, wtErr = g.ListWorktrees()
101101
if wtErr != nil {
102102
return fmt.Errorf("failed to list worktrees: %w", wtErr)
103103
}
104104
}
105105

106-
err = doCascadeWithState(g, cfg, branches, CascadeOptions{
107-
DryRun: cascadeDryRunFlag,
108-
Operation: state.OperationCascade,
106+
err = doRestackWithState(g, cfg, branches, RestackOptions{
107+
DryRun: restackDryRunFlag,
108+
Operation: state.OperationRestack,
109109
StashRef: stashRef,
110110
Worktrees: worktrees,
111111
}, s)
@@ -121,15 +121,15 @@ func runCascade(cmd *cobra.Command, args []string) error {
121121
return err
122122
}
123123

124-
// CascadeOptions configures the behaviour of doCascadeWithState.
124+
// RestackOptions configures the behaviour of doRestackWithState.
125125
//
126126
// The submit-specific fields (UpdateOnly, OpenWeb, PushOnly, Branches) are
127127
// only meaningful when Operation is state.OperationSubmit; they are persisted
128-
// to cascade state so that the push/PR phases can be resumed after a conflict.
129-
type CascadeOptions struct {
128+
// to restack state so that the push/PR phases can be resumed after a conflict.
129+
type RestackOptions struct {
130130
// DryRun prints what would be done without actually rebasing.
131131
DryRun bool
132-
// Operation is the type of operation being performed (state.OperationCascade
132+
// Operation is the type of operation being performed (state.OperationRestack
133133
// or state.OperationSubmit).
134134
Operation string
135135
// UpdateOnly skips creating new PRs; only existing PRs are updated.
@@ -140,8 +140,8 @@ type CascadeOptions struct {
140140
// PushOnly skips the PR creation/update phase entirely. Submit-only.
141141
PushOnly bool
142142
// Branches is the complete list of branch names being submitted, used
143-
// to rebuild the full set for push/PR phases after cascade completes.
144-
// Submit-only. Mirrors state.CascadeState.Branches.
143+
// to rebuild the full set for push/PR phases after restack completes.
144+
// Submit-only. Mirrors state.RestackState.Branches.
145145
Branches []string
146146
// StashRef is the commit hash of auto-stashed changes (if any), persisted
147147
// to state so they can be restored when the operation completes or is aborted.
@@ -152,8 +152,8 @@ type CascadeOptions struct {
152152
Worktrees map[string]string
153153
}
154154

155-
// doCascadeWithState performs cascade and saves state with the given operation type.
156-
func doCascadeWithState(g *git.Git, cfg *config.Config, branches []*tree.Node, opts CascadeOptions, s *style.Style) error {
155+
// doRestackWithState performs restack and saves state with the given operation type.
156+
func doRestackWithState(g *git.Git, cfg *config.Config, branches []*tree.Node, opts RestackOptions, s *style.Style) error {
157157
originalBranch, err := g.CurrentBranch()
158158
if err != nil {
159159
return err
@@ -287,7 +287,7 @@ func doCascadeWithState(g *git.Git, cfg *config.Config, branches []*tree.Node, o
287287
remaining = append(remaining, r.Name)
288288
}
289289

290-
st := &state.CascadeState{
290+
st := &state.RestackState{
291291
Current: b.Name,
292292
Pending: remaining,
293293
OriginalHead: originalHead,
@@ -323,7 +323,7 @@ func doCascadeWithState(g *git.Git, cfg *config.Config, branches []*tree.Node, o
323323

324324
// Return to original branch
325325
if !opts.DryRun {
326-
_ = g.Checkout(originalBranch) //nolint:errcheck // best effort - cascade succeeded
326+
_ = g.Checkout(originalBranch) //nolint:errcheck // best effort - restack succeeded
327327
}
328328

329329
return nil
@@ -332,7 +332,7 @@ func doCascadeWithState(g *git.Git, cfg *config.Config, branches []*tree.Node, o
332332
// displayOperationName maps internal operation constants to user-facing names.
333333
func displayOperationName(op string) string {
334334
switch op {
335-
case state.OperationCascade:
335+
case state.OperationRestack:
336336
return "Restack"
337337
case state.OperationSubmit:
338338
return "Submit"

cmd/submit.go

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -204,23 +204,23 @@ func runSubmit(cmd *cobra.Command, args []string) error {
204204

205205
// Phase 1: Restack
206206
fmt.Println(s.Bold("=== Phase 1: Restack ==="))
207-
if cascadeErr := doCascadeWithState(g, cfg, branches, CascadeOptions{
207+
if restackErr := doRestackWithState(g, cfg, branches, RestackOptions{
208208
DryRun: submitDryRunFlag,
209209
Operation: state.OperationSubmit,
210210
UpdateOnly: submitUpdateOnlyFlag,
211211
OpenWeb: submitWebFlag,
212212
PushOnly: submitPushOnlyFlag,
213213
Branches: branchNames,
214214
StashRef: stashRef,
215-
}, s); cascadeErr != nil {
215+
}, s); restackErr != nil {
216216
// Stash is saved in state for conflicts; restore on other errors
217-
if !errors.Is(cascadeErr, ErrConflict) && stashRef != "" {
217+
if !errors.Is(restackErr, ErrConflict) && stashRef != "" {
218218
fmt.Println("Restoring auto-stashed changes...")
219219
if popErr := g.StashPop(stashRef); popErr != nil {
220220
fmt.Printf("%s could not restore stashed changes (commit %s): %v\n", s.WarningIcon(), git.AbbrevSHA(stashRef), popErr)
221221
}
222222
}
223-
return cascadeErr
223+
return restackErr
224224
}
225225

226226
// Phases 2 & 3
@@ -255,7 +255,7 @@ type SubmitOptions struct {
255255
}
256256

257257
// doSubmitPushAndPR handles push and PR creation/update phases.
258-
// This is called after cascade succeeds (or from continue after conflict resolution).
258+
// This is called after restack succeeds (or from continue after conflict resolution).
259259
func doSubmitPushAndPR(g *git.Git, cfg *config.Config, root *tree.Node, branches []*tree.Node, opts SubmitOptions, s *style.Style) error {
260260
var decisions []*prDecision
261261
var ghClient *github.Client

cmd/sync.go

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -25,13 +25,13 @@ var syncCmd = &cobra.Command{
2525
}
2626

2727
var (
28-
syncNoCascadeFlag bool
28+
syncNoRestackFlag bool
2929
syncDryRunFlag bool
3030
syncWorktreesFlag bool
3131
)
3232

3333
func init() {
34-
syncCmd.Flags().BoolVar(&syncNoCascadeFlag, "no-restack", false, "skip restacking branches")
34+
syncCmd.Flags().BoolVar(&syncNoRestackFlag, "no-restack", false, "skip restacking branches")
3535
syncCmd.Flags().BoolVar(&syncDryRunFlag, "dry-run", false, "show what would be done")
3636
syncCmd.Flags().BoolVar(&syncWorktreesFlag, "worktrees", false, "rebase branches checked out in linked worktrees in-place")
3737
rootCmd.AddCommand(syncCmd)
@@ -202,7 +202,7 @@ func runSync(cmd *cobra.Command, args []string) error {
202202
// Check if branch content is identical to trunk (squash merge detection)
203203
isContentMerged, diffErr := g.IsContentMerged(branch, trunk)
204204
if diffErr != nil {
205-
// Can't determine, let cascade try
205+
// Can't determine, let restack try
206206
continue
207207
}
208208

@@ -330,7 +330,7 @@ func runSync(cmd *cobra.Command, args []string) error {
330330
fmt.Printf("Rebasing %s onto %s (from fork point %s)...\n", s.Branch(rt.childName), s.Branch(trunk), displayForkPoint)
331331
if rebaseErr := g.RebaseOnto(trunk, rt.forkPoint, rt.childName); rebaseErr != nil {
332332
fmt.Printf("%s --onto rebase failed, will try normal restack: %v\n", s.WarningIcon(), rebaseErr)
333-
// Don't return error - let cascade try
333+
// Don't return error - let restack try
334334
} else {
335335
fmt.Printf("%s Rebased %s successfully\n", s.SuccessIcon(), s.Branch(rt.childName))
336336

@@ -348,8 +348,8 @@ func runSync(cmd *cobra.Command, args []string) error {
348348
_ = g.Checkout(currentBranch) //nolint:errcheck // best effort
349349
}
350350

351-
// Cascade all (if not disabled)
352-
if !syncNoCascadeFlag {
351+
// Restack all (if not disabled)
352+
if !syncNoRestackFlag {
353353
fmt.Println(s.Bold("\nRestacking all branches..."))
354354
// Rebuild tree after modifications
355355
root, err = tree.Build(cfg)
@@ -367,13 +367,13 @@ func runSync(cmd *cobra.Command, args []string) error {
367367
}
368368
}
369369

370-
// Cascade from trunk's children
370+
// Restack from trunk's children
371371
for _, child := range root.Children {
372372
allBranches := []*tree.Node{child}
373373
allBranches = append(allBranches, tree.GetDescendants(child)...)
374-
if err := doCascadeWithState(g, cfg, allBranches, CascadeOptions{
374+
if err := doRestackWithState(g, cfg, allBranches, RestackOptions{
375375
DryRun: syncDryRunFlag,
376-
Operation: state.OperationCascade,
376+
Operation: state.OperationRestack,
377377
StashRef: stashRef,
378378
Worktrees: worktrees,
379379
}, s); err != nil {

cmd/undo.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ func runUndo(cmd *cobra.Command, args []string) error {
5252
g := git.New(cwd)
5353
gitDir := g.GetGitDir()
5454

55-
// Check if a cascade/submit is in progress
55+
// Check if a restack/submit is in progress
5656
if state.Exists(gitDir) {
5757
return errors.New("cannot undo while an operation is in progress; run 'gh stack continue' or 'gh stack abort' first")
5858
}

e2e/chaos_manual_git_test.go

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@ func TestManualRebase(t *testing.T) {
6060
env.Git("checkout", "main")
6161
env.CreateCommit("main moved")
6262

63-
// User rebases manually with git instead of cascade
63+
// User rebases manually with git instead of restack
6464
env.Git("checkout", "feature-1")
6565
env.Git("rebase", "main")
6666

@@ -105,20 +105,20 @@ func TestManualBranchDelete(t *testing.T) {
105105
}
106106
}
107107

108-
func TestManualRebaseAbortDuringCascade(t *testing.T) {
108+
func TestManualRebaseAbortDuringRestack(t *testing.T) {
109109
env := NewTestEnv(t)
110110
env.MustRun("init")
111111

112112
// Set up conflict scenario
113113
env.CreateStackWithConflict()
114-
env.Run("cascade") // Will conflict and leave rebase in progress
114+
env.Run("restack") // Will conflict and leave rebase in progress
115115

116116
env.AssertRebaseInProgress()
117117

118118
// User manually aborts with git instead of gh-stack abort
119119
env.Git("rebase", "--abort")
120120

121-
// gh-stack abort should still work (cleans up cascade state)
121+
// gh-stack abort should still work (cleans up restack state)
122122
result := env.Run("abort")
123123
if result.Failed() {
124124
t.Errorf("abort should succeed after manual rebase --abort, got: %s", result.Stderr)

0 commit comments

Comments
 (0)