Documentation
¶
Overview ¶
Package restack is the core of every command that rebases branches onto their parents. It is split in two so each half depends only on what it uses:
- Planner works out what a restack would do and proves it in a scratch worktree. It reads the repository and never changes it.
- Executor applies a Plan: it moves branch refs, or stops at the first conflict and leaves the repository mid-rebase for `stackit continue`.
Neither touches bootstrap state. Adapters build them from whatever runtime they have (see actions.RestackDepsFrom for the CLI's).
Index ¶
- func FormatRerereResolved(count int) string
- func HeldWorktreeReason(ctx context.Context, eng WorktreeInspector, branchName string) string
- type ApplyEngine
- type ConflictMode
- type ConflictReporter
- type ContinuationFile
- type ContinuationStore
- type Executor
- type Logger
- type Plan
- type PlanEngine
- type Planner
- type Printer
- type Progress
- type ProgressFunc
- type RebaseStateReader
- type Runner
- type WorktreeInspector
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func FormatRerereResolved ¶
FormatRerereResolved renders the standard message describing how many rebase conflicts git rerere auto-resolved during an operation.
func HeldWorktreeReason ¶
func HeldWorktreeReason(ctx context.Context, eng WorktreeInspector, branchName string) string
HeldWorktreeReason returns why branchName's own checkout blocks a restack, or "" when nothing does.
Restack holds a branch whose worktree it cannot safely reset, and a held branch is reported as RestackUnneeded — the same status as a branch that needed no work. Callers that expected a rebase to start need to tell those apart, because the remedy lives in the other worktree.
Only the branch's own checkout is examined. A branch held because an ancestor is held returns "", and the caller falls back to its generic message.
Types ¶
type ApplyEngine ¶
type ApplyEngine interface {
engine.BranchLookup
Trunk() engine.Branch
Graph(ctx context.Context, strategy engine.SortStrategy) *engine.StackGraph
CurrentBranch(ctx context.Context) *engine.Branch
GetCurrentRevision(ctx context.Context) (string, error)
RestackBranches(ctx context.Context, branches engine.Branches, opts engine.RestackOpts) (engine.RestackBatchResult, error)
IsRebaseInProgress(ctx context.Context) bool
RebaseAbort(ctx context.Context) error
CheckoutBranch(ctx context.Context, branch engine.Branch) error
Detach(ctx context.Context, revision string) error
LastSnapshotID() string
ListWorktrees(ctx context.Context) (git.WorktreeList, error)
WorktreeRebaseInProgress(ctx context.Context, worktreePath engine.WorktreePath) bool
WorktreeHasUncommittedChanges(ctx context.Context, worktreePath engine.WorktreePath) (bool, error)
}
ApplyEngine lists exactly the engine methods applying a plan calls.
type ConflictMode ¶
type ConflictMode int
ConflictMode controls how Execute responds to a conflicting branch.
const ( // ConflictEnterWorkflow stops at the first conflict, writes rebase state to // the working tree, and expects the user to resolve it with stackit // continue. This is the standalone CLI default. ConflictEnterWorkflow ConflictMode = iota // ConflictContinue restacks the stacks that apply cleanly and reports // conflicts without writing rebase state. Use it in sync, parallel workers // (rebase state would be torn down with the worktree), and // --continue-on-conflict flows. ConflictContinue )
type ConflictReporter ¶
type ConflictReporter struct {
Engine RebaseStateReader
Out Printer
RepoRoot string
}
ConflictReporter prints where a conflicted rebase stopped and how to finish it.
func (*ConflictReporter) Print ¶
func (r *ConflictReporter) Print(ctx context.Context, branchName string) error
Print displays conflict information and instructions to the user. It assumes a rebase is in progress: HEAD-side markers reflect the parent/base and the ">>>>>>>" side reflects the branch being replayed.
type ContinuationFile ¶
type ContinuationFile string
ContinuationFile stores continuation state in the repository at its root.
func (ContinuationFile) Save ¶
func (f ContinuationFile) Save(state *config.ContinuationState) error
Save implements ContinuationStore.
type ContinuationStore ¶
type ContinuationStore interface {
Save(state *config.ContinuationState) error
}
ContinuationStore persists where an interrupted restack resumes.
type Executor ¶
type Executor struct {
Engine ApplyEngine
Log Logger
// Report receives each branch's outcome. Use TextReporter for plain output.
Report ProgressFunc
// Continuations and Conflicts are used only when a plan enters the
// conflict workflow.
Continuations ContinuationStore
Conflicts *ConflictReporter
}
Executor applies Plans.
func (Executor) Execute ¶
func (e Executor) Execute(ctx context.Context, plan *Plan, mode ConflictMode, resume *config.ContinuationState) error
Execute applies plan. Under ConflictEnterWorkflow, a conflict applies the branches before it, leaves the repository mid-rebase on the first conflicting branch, and returns a ConflictWorkflowError; resume records the interrupted command when Execute is itself resuming one (stackit continue), and is nil otherwise. Under ConflictContinue, every stack free of conflicts is applied and the rest are reported.
type Logger ¶
type Logger interface {
Debug(msg string, args ...any)
Info(msg string, args ...any)
Warn(msg string, args ...any)
}
Logger receives diagnostic lines. output.Logger satisfies it.
type Plan ¶
type Plan struct {
// Branches is the requested set, in topological order.
Branches engine.Branches
// Engine is the engine's per-branch plan.
Engine *engine.RestackPlan
// Validation is the result of trial-rebasing Engine.Specs.
Validation *engine.RebaseValidation
// Apply holds the branches proven safe to apply, in order.
Apply engine.Branches
// Conflicts holds branches whose trial rebase conflicted.
Conflicts []string
// Blocked holds branches that were not tried because an ancestor failed.
Blocked []string
}
Plan is a restack worked out in full before anything moves.
type PlanEngine ¶
type PlanEngine interface {
BatchRevisions(ctx context.Context, branches engine.Branches) engine.RevisionMap
GetMergeBase(ctx context.Context, rev1, rev2 string) (string, error)
PlanRestack(ctx context.Context, branches engine.Branches) (*engine.RestackPlan, error)
ValidateRebases(ctx context.Context, specs []engine.RebaseSpec) (*engine.RebaseValidation, error)
}
PlanEngine lists exactly the engine methods planning calls. All of them read; validation rebases in a temporary worktree, never in the user's.
type Planner ¶
type Planner struct {
Engine PlanEngine
Log Logger
}
Planner computes Plans.
func (Planner) Plan ¶
func (p Planner) Plan(ctx context.Context, branches engine.Branches, prePlan *engine.RestackPlan) (*Plan, error)
Plan validates branch ancestry, builds the engine plan (or reuses prePlan when the caller already has one for these branches), trial-rebases it, and classifies every branch. It returns an error only for a system failure; a conflict is a classification, not an error.
type Printer ¶
type Printer interface {
Info(format string, args ...any)
Warn(format string, args ...any)
Newline()
}
Printer is the terminal surface TextReporter and ConflictReporter write to. output.Output satisfies it.
type Progress ¶
type Progress struct {
Branch string // the branch being processed
Result engine.RestackResult // Done, Unneeded, Conflict, or Blocked
NewRev string // new revision if restacked (empty otherwise)
RerereResolvedCount int // number of rebase continuations handled by git rerere
Conflict bool // true if this is a conflict
LockReason engine.LockReason // why the branch is locked (empty if not locked)
Frozen bool // true if the branch is frozen
HeldBy string // why a worktree held this branch back (empty if it was not held)
IsCurrent bool // true if this is the current branch
Reparented bool // true if the branch was reparented
OldParent string // the old parent name if reparented
NewParent string // the new parent name if reparented
StackRoot string // independent stack root (set by multi-stack callers; empty for single-stack)
// contains filtered or unexported fields
}
Progress describes the outcome of restacking a single branch.
type ProgressFunc ¶
type ProgressFunc func(Progress)
ProgressFunc receives one Progress per processed branch.
func TextReporter ¶
func TextReporter(out Printer) ProgressFunc
TextReporter prints one line per restacked branch, for commands that have no progress UI of their own. Conflicts and blocked branches print nothing: the conflict workflow, or the caller's summary, reports those.
type RebaseStateReader ¶
type RebaseStateReader interface {
engine.BranchLookup
GetUnmergedFiles(ctx context.Context) ([]string, error)
GetRebaseHead(ctx context.Context) (string, error)
}
RebaseStateReader is the engine surface ConflictReporter reads.
type Runner ¶
Runner plans and applies in one call, for the common case of restacking a set of branches and stopping at the first conflict.
func (Runner) Restack ¶
Restack plans branches and applies the plan, entering the conflict workflow on the first conflict.
func (Runner) RestackWithReport ¶
func (r Runner) RestackWithReport(ctx context.Context, branches engine.Branches, report ProgressFunc, mode ConflictMode) error
RestackWithReport is Restack with a progress sink and conflict mode. A nil report keeps the executor's own.
type WorktreeInspector ¶
type WorktreeInspector interface {
ListWorktrees(ctx context.Context) (git.WorktreeList, error)
WorktreeRebaseInProgress(ctx context.Context, worktreePath engine.WorktreePath) bool
WorktreeHasUncommittedChanges(ctx context.Context, worktreePath engine.WorktreePath) (bool, error)
}
WorktreeInspector is the engine surface HeldWorktreeReason reads.