Help us shape the future of Go! Take the 2026 Go Developer Survey

restack

package
v0.30.1 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Oct 30, 2026 License: MIT Imports: 10 Imported by: 0

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

Constants

This section is empty.

Variables

This section is empty.

Functions

func FormatRerereResolved

func FormatRerereResolved(count int) string

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

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.

func (*Plan) Empty

func (p *Plan) Empty() bool

Empty reports whether the plan moves nothing: no branch needs a rebase and none needs its metadata applied.

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

type Runner struct {
	Planner  Planner
	Executor Executor
}

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

func (r Runner) Restack(ctx context.Context, branches engine.Branches) error

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.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL