mirror of
https://github.com/github/gh-stack.git
synced 2026-09-14 20:26:28 +08:00
7a268fc380
* git primitives for modify cmd * extract reusable TUI parts * modify cmd * recreate stack after modify * add checks to prevent other modifications while modify is applying * modify continue for resuming after resolving conflicts * fix bug with duplicate stack entries after modifying * reuse conflict resolution help msg from rebase * additional confirmation before overwriting stack on remote * fix recreate order of operations Co-authored-by: Copilot <copilot@github.com> * move base commit instead of cherry picking for fold up * check to ensure we aren't left with zero branches * unify and dedupe across view and modify tui * more detailed help instructions Co-authored-by: Copilot <copilot@github.com> * only recommend submit if stack exists on remote Co-authored-by: Copilot <copilot@github.com> * tests for modify tui, apply modifications, submit modifications * refactor submit for regular and pending modifications * rename recover to abort Co-authored-by: Copilot <copilot@github.com> * docs for modify cmd * tui styling updates * updated tui screenshot * addressing review comments * Fix 4 bugs from code review 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> * Fix 7 nit issues from code review 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> * Make cherry-pick conflicts recoverable via --continue 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 * Apply suggestions from code review Co-authored-by: Luke Ghenco <lukeghenco@github.com> Co-authored-by: Sameen Karim <skarim@github.com> --------- Co-authored-by: Copilot <copilot@github.com> Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Co-authored-by: Luke Ghenco <lukeghenco@github.com>
100 lines
2.7 KiB
Go
100 lines
2.7 KiB
Go
package modifyview
|
|
|
|
import (
|
|
"strings"
|
|
|
|
"github.com/charmbracelet/lipgloss"
|
|
)
|
|
|
|
// renderHelpOverlay renders a centered help overlay with a guide to modify operations.
|
|
func renderHelpOverlay(width, height int) string {
|
|
var b strings.Builder
|
|
|
|
title := helpTitleStyle.Render("Modify Stack")
|
|
b.WriteString(title)
|
|
b.WriteString("\n")
|
|
b.WriteString(helpDescStyle.Render("Restructure your stack by dropping, folding, renaming, or reordering branches."))
|
|
b.WriteString("\n")
|
|
|
|
sections := []struct {
|
|
heading string
|
|
body string
|
|
}{
|
|
{
|
|
"Drop (x)",
|
|
"Remove a branch and its commits from the stack.\nThe local branch is preserved; the PR stays open on GitHub.",
|
|
},
|
|
{
|
|
"Fold up / down (u / d)",
|
|
"Merge a branch's commits into an adjacent branch.\nFold up absorbs into the branch above; fold down into the branch below.",
|
|
},
|
|
{
|
|
"Rename (r)",
|
|
"Rename a branch locally. The new name is pushed on submit.",
|
|
},
|
|
{
|
|
"Reorder (Shift+↑/↓)",
|
|
"Move a branch up or down in the stack.\nA cascading rebase adjusts all affected branches.",
|
|
},
|
|
}
|
|
|
|
for _, s := range sections {
|
|
b.WriteString("\n")
|
|
b.WriteString(helpKeyStyle.Render(s.heading))
|
|
b.WriteString("\n")
|
|
for _, line := range strings.Split(s.body, "\n") {
|
|
b.WriteString(helpDescStyle.Render(line))
|
|
b.WriteString("\n")
|
|
}
|
|
}
|
|
|
|
b.WriteString("\n")
|
|
b.WriteString(helpKeyStyle.Render("Applying changes"))
|
|
b.WriteString("\n")
|
|
b.WriteString(helpDescStyle.Render("Press " + helpKeyStyle.Render("Ctrl+S") + " to apply all staged changes. Nothing is modified until you save."))
|
|
b.WriteString("\n")
|
|
b.WriteString(helpDescStyle.Render("If you have open PRs, run ") + helpKeyStyle.Render("gh stack submit") + helpDescStyle.Render(" afterwards to push the updated"))
|
|
b.WriteString("\n")
|
|
b.WriteString(helpDescStyle.Render("branches and recreate the stack of PRs on GitHub."))
|
|
|
|
b.WriteString("\n\n")
|
|
b.WriteString(statusBarStyle.Render("Press ? or Esc to close"))
|
|
|
|
content := b.String()
|
|
|
|
// Apply the overlay style and center it
|
|
styled := helpOverlayStyle.Render(content)
|
|
|
|
// Center vertically and horizontally
|
|
styledLines := strings.Split(styled, "\n")
|
|
styledHeight := len(styledLines)
|
|
styledWidth := 0
|
|
for _, line := range styledLines {
|
|
w := lipgloss.Width(line)
|
|
if w > styledWidth {
|
|
styledWidth = w
|
|
}
|
|
}
|
|
|
|
topPad := (height - styledHeight) / 2
|
|
if topPad < 0 {
|
|
topPad = 0
|
|
}
|
|
leftPad := (width - styledWidth) / 2
|
|
if leftPad < 0 {
|
|
leftPad = 0
|
|
}
|
|
|
|
var result strings.Builder
|
|
for i := 0; i < topPad; i++ {
|
|
result.WriteString("\n")
|
|
}
|
|
for _, line := range styledLines {
|
|
result.WriteString(strings.Repeat(" ", leftPad))
|
|
result.WriteString(line)
|
|
result.WriteString("\n")
|
|
}
|
|
|
|
return result.String()
|
|
}
|