Conversation
Contributor
There was a problem hiding this comment.
Pull request overview
Adds a new interactive gh stack modify workflow for restructuring a local stack (drop/fold/rename/reorder) with recovery support, while refactoring TUI rendering into shared helpers and adjusting submit behavior to better support post-modify stack recreation.
Changes:
- Introduces
gh stack modifycommand, TUI, apply engine (with snapshot/state for conflict recovery), and docs. - Centralizes TUI styles/rendering/header/scroll/click logic in
internal/tui/sharedand updatesstackviewto use it. - Updates
submitto push branches sequentially and to handle “pending modify” remote stack recreation.
Show a summary per file
| File | Description |
|---|---|
| internal/tui/stackview/styles.go | Removes stackview-specific styles (moved to shared). |
| internal/tui/stackview/model_test.go | Updates header text expectations and shortcut visibility behavior. |
| internal/tui/stackview/model.go | Uses shared header/node rendering and shared click/scroll helpers. |
| internal/tui/shared/styles.go | Adds shared lipgloss styles/icons for TUI views. |
| internal/tui/shared/scroll.go | Adds shared scroll clamp/ensure-visible and scroll slicing helper. |
| internal/tui/shared/render.go | Adds shared branch node rendering + mouse hit-testing + browser open helpers. |
| internal/tui/shared/header.go | Adds shared header rendering with progressive disclosure and shortcut layout. |
| internal/tui/modifyview/types.go | Defines modify-specific action and node state types. |
| internal/tui/modifyview/styles.go | Adds modify-specific badges/overrides and overlay/status styles. |
| internal/tui/modifyview/status.go | Adds pending-change summary and bottom status bar rendering. |
| internal/tui/modifyview/model_test.go | Adds comprehensive TUI behavior tests for modify view. |
| internal/tui/modifyview/model.go | Implements modify TUI interactions, rendering, and state tracking. |
| internal/tui/modifyview/help.go | Adds help overlay content and centering logic. |
| internal/stack/stack.go | Adds SaveWithLock for saving while a lock is already held. |
| internal/modify/state.go | Implements on-disk modify session state (apply/conflict/pending_submit). |
| internal/modify/preconditions.go | Adds modify precondition checks (merge queue + linearity). |
| internal/modify/apply.go | Implements apply engine (snapshot, plan, renames/folds/drops/reorder/rebase, unwind/continue). |
| internal/git/mock_ops.go | Extends git mock ops with rename/cherry-pick/uncommitted/merge-log helpers. |
| internal/git/gitops.go | Extends git ops interface + default implementations for new modify needs. |
| internal/git/git.go | Adds package-level wrappers for the new git ops methods. |
| go.sum | Adds new indirect dependency checksums. |
| go.mod | Adds indirect dependency required by new functionality. |
| docs/src/content/docs/reference/cli.md | Documents gh stack modify command and behavior. |
| docs/src/content/docs/guides/workflows.md | Updates workflow guidance to use gh stack modify. |
| docs/src/content/docs/guides/modify.md | Adds dedicated guide for restructuring stacks via modify. |
| docs/astro.config.mjs | Adds docs navigation entry for the modify guide. |
| cmd/utils.go | Adds new exit code for modify recovery. |
| cmd/unstack.go | Blocks unstack when modify is mid-apply/conflict via state guard. |
| cmd/sync.go | Blocks sync when modify is mid-apply/conflict via state guard. |
| cmd/submit_test.go | Updates push expectations + adds pending-modify/submit integration tests. |
| cmd/submit.go | Adds pending-modify handling and switches to sequential per-branch push flow. |
| cmd/root.go | Registers the new modify command. |
| cmd/rebase.go | Blocks rebase when modify is mid-apply/conflict; refactors conflict printing helper. |
| cmd/push.go | Blocks push when modify is mid-apply/conflict via state guard. |
| cmd/modify_test.go | Adds command-layer tests for modify state/preconditions/builders. |
| cmd/modify.go | Implements gh stack modify, including --continue/--abort and preconditions. |
| cmd/add.go | Blocks add when modify is mid-apply/conflict via state guard. |
| README.md | Documents gh stack modify usage, keys, and preconditions. |
Copilot's findings
Tip
Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
- Files reviewed: 38/40 changed files
- Comments generated: 5
Comment on lines
+999
to
+1016
| // Count fixed bottom lines (always visible, not scrollable). | ||
| // The bottom section always has 2 lines: one for contextual info | ||
| // (rename prompt or error, blank when neither) and one for the status bar. | ||
| bottomLines := 2 // post-scroll newline + context line + status bar | ||
|
|
||
| // Scrolling — reserve space for header and fixed bottom | ||
| reservedLines := bottomLines | ||
| if showHeader { | ||
| reservedLines += shared.HeaderHeight | ||
| } | ||
| viewHeight := m.height - reservedLines | ||
| if viewHeight < 1 { | ||
| viewHeight = 1 | ||
| } | ||
|
|
||
| out.WriteString(shared.ApplyScrollToContent(b.String(), m.scrollOffset, viewHeight)) | ||
| out.WriteString("\n") | ||
|
|
Collaborator
Author
There was a problem hiding this comment.
This is intentional — the extra line ensures the status bar is pinned to the very bottom of the viewport.
Co-authored-by: Copilot <copilot@github.com>
Co-authored-by: Copilot <copilot@github.com>
Co-authored-by: Copilot <copilot@github.com>
Co-authored-by: Copilot <copilot@github.com>
Bug 1: Move RevParseMap error check before using originalRefs. The error from git.RevParseMap() was deferred past iteration of originalRefs, which could panic on a nil map. Bug 2: Differentiate cherry-pick vs rebase conflicts in modify. Cherry-pick conflicts don't save state as 'conflict' phase, so --continue won't work. Now prints --abort-only instructions for cherry-pick conflicts. Bug 3: Unwind now cleans up branches created by renames. After restoring snapshot branches, Unwind deletes renamed branch names that don't belong to the original snapshot. Bug 4: Simplify push message in submit command. Changed from 'Pushing N branches to remote...' to 'Pushing to remote...' since individual branches may fail. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
11: Add named constants for phase strings (PhaseApplying, PhaseConflict, PhasePendingSubmit) in state.go; replace remaining raw literals in state.go CheckStateGuard. 14: Fix bottomLines comment mismatch — listed 3 items but value is 2. 15: Extract magic number 88 to MinWidthForArt constant in header.go. 16: Remove unused stackview import anchor in model.go — the import is used via types.go where BranchNode is embedded. 17: Simplify CheckStackLinearity parent resolution — ActiveBaseBranch already handles skipping merged branches. 18: Fix rename undo matching any rename — add NewName check so only the specific rename being undone is matched. 20: Add TestUndoRename and TestUndoRename_DoesNotAffectOtherRenames to validate rename undo behavior. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Previously, cherry-pick conflicts during fold-down operations could only be resolved with --abort. Now they save full conflict state (phase, conflict type, fold branch/target, remaining branches) to the state file, enabling recovery via 'gh stack modify --continue'. Changes: - Add ConflictType field to StateFile (rebase or cherry_pick) - Add FoldBranch/FoldTarget fields for cherry-pick context - Add CherryPickContinue to git package (cherry-pick --continue) - Save cherry-pick conflict state in ApplyPlan with remaining branches - ContinueApply handles both rebase and cherry-pick conflicts - Unified conflict messaging in cmd/modify.go (both types show --continue) - Updated test to verify cherry-pick conflict state is saved correctly
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Adds a new interactive
modifycommand that lets users restructure an existing stack — drop, fold, rename, and reorder branches — then apply all changes as a single atomic operation with cascading rebases. Includes full conflict recovery (--continue/--abort), submit integration for recreating the stack on GitHub, and comprehensive documentation.Motivation
Today, restructuring a stack requires manually unstacking branches, reordering them, and restacking — a tedious and error-prone workflow. The
modifycommand provides a safe, interactive way to perform these operations with undo support, conflict recovery, and automatic cascading rebases.What's included
New command:
gh stack modifyAn interactive TUI (built on Bubble Tea) for staging structural changes to a stack:
x) — Remove a branch from the stack. The branch is deleted locally; if it had an open PR, the user is reminded to close it manually.d) — Merge a branch's commits into the branch below via cherry-pick. Useful for combining related work.u) — Merge a branch's commits into the branch above by adjusting rebase boundaries so the cascading rebase replays both sets of commits.r) — Rename a branch locally. The rename prompt replaces the bottom status bar, showing the original name for reference.Shift+↑/↓) — Move a branch up or down in the stack. Reorder and structural changes (drop/fold/rename) are mutually exclusive to prevent ambiguous operations.z) — Revert the last staged action.All changes are staged visually in the TUI and applied together when the user presses
Ctrl+S. The TUI shows annotations for each pending change (red strikethrough for drops, yellow for folds, magenta for moves, cyan for renames).Conflict recovery
--continue— Resume after resolving rebase or cherry-pick conflicts. The state file tracks conflict type, branch context, and remaining work so the cascading rebase picks up exactly where it left off.--abort— Restore the stack to its exact pre-modify state using the snapshot saved before any changes were applied. All branch tips, names, and stack metadata are rolled back.State is persisted to
.git/gh-stack-modify-statewith phases (applying→conflict→pending_submit) and a full snapshot for recovery.Submit integration
After modifying a stack that exists on GitHub,
gh stack submitdetects the pending modifications and:Shared TUI components
The modify TUI shares a common rendering foundation with the existing
viewcommand:internal/tui/shared/— Extracted styles, node rendering, scroll math, header with progressive disclosure, and mouse handling into a shared packageviewcommand was refactored to use these shared components (no behavioral changes)modifycommand extends the shared base with action annotations, keyboard shortcuts, and the rename promptPrecondition guards
add,push,sync,rebase,unstack) check for an in-progress modify session and block with a helpful messageArchitecture
Key design decisions
originalParentTipsso the cascading rebase naturally replays both commit sets.main).Testing
internal/modify/apply_test.go— tests covering drop, fold-down, fold-up, rename, reorder, mixed operations, rebase conflicts, cherry-pick conflicts, continue/abort, multi-stack identification, unwindinternal/tui/modifyview/model_test.go— TUI tests covering keyboard navigation, all action types, undo, mutual exclusivity, fold validation, help toggle, mouse supportcmd/modify_test.go— command-level tests covering preconditions, state guards, continue/abort flowscmd/submit_test.go— tests for submit with pending modifications