Documentation
¶
Overview ¶
Package sync provides functionality for synchronizing stacked branches with remote repositories.
Index ¶
- func Action(ctx context.Context, deps Deps, opts Options, handler Handler) error
- type Config
- type Deps
- type DryRunCleanItem
- type DryRunPlan
- type DryRunRestackItem
- type DryRunResult
- type Event
- type EventType
- type GitHubSyncResult
- type Handler
- type NullHandler
- func (h *NullHandler) Complete(Summary)
- func (h *NullHandler) EmitEvent(Event)
- func (h *NullHandler) PromptBranchDeletions(branches map[string]string, unpushedBranches map[string]bool) (map[string]bool, error)
- func (h *NullHandler) PromptMetadataConflict(_ *engine.MetadataDiff) (bool, error)
- func (h *NullHandler) PromptOrphanedMetadata(_ engine.OrphanedMetadataInfo) (bool, error)
- func (h *NullHandler) PromptResolveConflicts(_ []string) (bool, error)
- func (h *NullHandler) Start(int)
- type Options
- type ParentsToGitHubResult
- type Phase
- type PlanEngine
- type PlanRequest
- type StackMetadataGCResult
- type Summary
- type WorktreeCleanupResult
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
Types ¶
type Config ¶ added in v0.30.1
type Config interface {
WorktreeAutoClean() bool
}
Config lists the configuration getters sync reads. A nil Config behaves as if no configuration was loaded.
type Deps ¶ added in v0.30.1
type Deps struct {
// Engine is the full engine: sync reconciles the whole repository —
// trunk, remote and stack metadata, PR info, worktrees, branch cleanup —
// so the surface it touches spans nearly every engine role, and the
// restack and cleanup pipelines it delegates to take engine.Engine too.
Engine engine.Engine
Out output.Output
Log output.Logger
// GitHub returns the client, or nil when GitHub is unavailable. It is a
// function so the client is only built when sync actually needs it.
GitHub func() github.Client
// GHRunner runs the GraphQL queries that fetch PR info.
GHRunner github.GitCommandRunner
// PRSync refreshes PR footers and titles for flagged branches and pushes
// orphaned metadata the user chose to keep.
PRSync actions.PRSync
// Restack is what the restack phase runs actions.RunRestack with. Its
// Interactive and Quiet flags also decide whether sync may prompt to
// enable rerere.
Restack actions.RestackDeps
// Cleanup is what the merged/closed branch cleanup phase runs with.
Cleanup actions.CleanBranchesDeps
Snapshots actions.Snapshots
// Here is where sync runs; a managed worktree never removes itself and
// cannot delete branches checked out elsewhere.
Here actions.Here
Config Config
}
Deps are the collaborators sync needs. Adapters build them from their own runtime state; the action never sees bootstrap types.
type DryRunCleanItem ¶ added in v0.29.0
type DryRunCleanItem struct {
Branch string
Reason string // e.g. "merged into main", "closed on GitHub"
}
DryRunCleanItem is a branch a sync would delete, with the reason.
type DryRunPlan ¶ added in v0.29.0
type DryRunPlan struct {
PullBranch string // trunk that would be pulled (empty if up to date)
PullRevision string // short remote SHA the trunk would move to
Clean []DryRunCleanItem // branches that would be deleted
Restack []DryRunRestackItem // branches that would be restacked
RestackStacks []string // deduped stack roots covering the restack set (JSON only)
SkippedStacks []string // dirty-worktree anchors whose stacks are skipped
RestackRequested bool // whether --restack was requested
TrunkStateUnknown bool // trunk's remote relationship could not be resolved
}
DryRunPlan is the read-only snapshot of what a sync WOULD do, built from the current (remote-aware) state. It carries enough detail to render a preview that mirrors the live run — target revision, deletion reasons, restack parents. The JSON contract is a stable, names-only projection (see Result); the richer fields exist only to make the human-readable preview as informative as the real sync.
func PlanDryRun ¶ added in v0.29.0
func PlanDryRun(ctx context.Context, eng PlanEngine, req PlanRequest) DryRunPlan
PlanDryRun builds a read-only snapshot of what a sync WOULD do from the current (remote-aware) state. It never mutates: it probes remote status and reads PR/deletion state, but performs no fetch-and-merge, deletion, restack, or GitHub write. It is a query rather than a simulation of Action with a special handler; the dirty-worktree skip decision is shared with Action via actions.ManagedWorktreeHolds so the preview cannot promise work the run then skips.
ctx should be the bounded remote-operation context so every remote-status and deletion read shares one deadline.
func (DryRunPlan) Result ¶ added in v0.29.0
func (p DryRunPlan) Result() DryRunResult
Result projects the plan onto the stable JSON contract (branch names only). The shape is byte-compatible with what scripts already consume, so the richer preview fields are deliberately dropped here.
type DryRunRestackItem ¶ added in v0.29.0
DryRunRestackItem is a branch a sync would restack onto Parent.
type DryRunResult ¶
type DryRunResult struct {
WouldPull string `json:"would_pull,omitempty"` // Trunk branch that would be pulled
WouldClean []string `json:"would_clean,omitempty"` // Branches that would be deleted
WouldRestack []string `json:"would_restack,omitempty"` // Branches that would be restacked
WouldRestackStacks []string `json:"would_restack_stacks,omitempty"` // Deduped independent stack roots covering the current dry-run's would_restack set; recompute after sync before passing to `restack --stacks <roots>` because cleanup/reparenting can change roots
SkippedStacks []string `json:"skipped_stacks,omitempty"` // Stacks skipped due to dirty worktrees
TrunkStateUnknown bool `json:"trunk_state_unknown,omitempty"` // Trunk's relationship to its remote could not be resolved (objects not fetched); an absent would_pull does NOT mean trunk is current
}
DryRunResult represents the JSON output for sync --dry-run
type Event ¶
type Event struct {
Phase Phase // Current phase
Type EventType // Event type
Branch string // Branch name (if applicable)
PRNumber *git.PRNumber // PR number (if applicable)
Message string // Human-readable description
OldRevision string // For position changes
NewRevision string // For position changes
Conflict bool // Is this a conflict?
HeldBy string // Why a worktree held this branch back (empty if it was not held)
Error error // If non-nil, this step had an error
}
Event represents a progress update during sync
type GitHubSyncResult ¶
type GitHubSyncResult struct {
BranchNames []string
RepoOwner string
RepoName string
PRInfos map[string]*github.PullRequestInfo
// contains filtered or unexported fields
}
GitHubSyncResult holds the results from GitHub PR info sync (network operation)
type Handler ¶
type Handler interface {
// Start is called at the beginning of sync with the total operation count
Start(totalOps int)
// EmitEvent is called for each progress update
EmitEvent(event Event)
// Complete is called when sync finishes with the summary
Complete(summary Summary)
// Cleanup ensures terminal is restored on error (may be no-op for non-TTY handlers)
Cleanup()
// IsInteractive returns true if this handler supports interactive prompts.
// Non-interactive handlers return false and their prompt methods return defaults.
IsInteractive() bool
// PromptMetadataConflict displays a metadata conflict and asks user to accept remote.
// Returns true to accept remote metadata, false to keep local.
// In non-interactive mode, returns (false, nil) to preserve local changes.
PromptMetadataConflict(diff *engine.MetadataDiff) (acceptRemote bool, err error)
// PromptOrphanedMetadata asks what to do when remote metadata was deleted but local has changes.
// Returns true to push local metadata to remote, false to accept deletion.
// In non-interactive mode, returns (false, nil) to accept the remote deletion.
PromptOrphanedMetadata(info engine.OrphanedMetadataInfo) (pushLocal bool, err error)
// PromptBranchDeletions displays planned branch deletions and asks user to confirm each one.
// unpushedBranches identifies branches with local commits not yet pushed to remote.
// Returns a map of branch names that the user confirmed for deletion.
// In non-interactive mode, returns all branches except unpushed ones (which are skipped by default).
PromptBranchDeletions(branches map[string]string, unpushedBranches map[string]bool) (confirmed map[string]bool, err error)
// PromptResolveConflicts asks user if they want to resolve restack conflicts now or skip them.
// Returns true to start conflict resolution workflow, false to skip and continue.
// In non-interactive mode, returns (false, nil) to skip conflicts.
PromptResolveConflicts(conflictBranches []string) (resolve bool, err error)
// RestackHandler methods are available for restack-specific output
// This allows the same handler to be used for standalone restack operations
actions.RestackHandler
}
Handler abstracts TTY vs non-TTY output for sync operations It embeds actions.RestackHandler to provide a unified interface for operations that include restacking
type NullHandler ¶
type NullHandler struct {
handler.NullBase
actions.NullRestackHandler
}
NullHandler is a no-op handler for testing or when output is not needed NullHandler is a no-op handler for when nil is passed. It embeds handler.NullBase for Cleanup() and IsInteractive(), and actions.NullRestackHandler for the restack-specific no-op methods.
func (*NullHandler) EmitEvent ¶
func (h *NullHandler) EmitEvent(Event)
EmitEvent implements Handler.
func (*NullHandler) PromptBranchDeletions ¶
func (h *NullHandler) PromptBranchDeletions(branches map[string]string, unpushedBranches map[string]bool) (map[string]bool, error)
PromptBranchDeletions implements Handler. Skips unpushed branches, auto-confirms the rest.
func (*NullHandler) PromptMetadataConflict ¶
func (h *NullHandler) PromptMetadataConflict(_ *engine.MetadataDiff) (bool, error)
PromptMetadataConflict implements Handler. Returns false (keep local) in non-interactive mode.
func (*NullHandler) PromptOrphanedMetadata ¶
func (h *NullHandler) PromptOrphanedMetadata(_ engine.OrphanedMetadataInfo) (bool, error)
PromptOrphanedMetadata implements Handler. Returns false (accept deletion) in non-interactive mode.
func (*NullHandler) PromptResolveConflicts ¶
func (h *NullHandler) PromptResolveConflicts(_ []string) (bool, error)
PromptResolveConflicts implements Handler. Returns false (skip) in non-interactive mode.
type Options ¶
type Options struct {
All bool
Force bool
Restack bool // Explicitly restack the full current stack (opt-in)
NoRestack bool // Skip all restacking entirely
DryRun bool
RestackScope []string // When non-nil, only restack these branches (skip current-branch expansion)
}
Options contains options for the sync command
type ParentsToGitHubResult ¶
type ParentsToGitHubResult struct {
BranchesUpdated []string // Branches whose PR base was updated on GitHub
}
ParentsToGitHubResult contains the result of pushing local parents to GitHub
func PushParentsToGitHub ¶
func PushParentsToGitHub(ctx context.Context, deps Deps, result *GitHubSyncResult, dirtyAnchors dirtyAnchorSet) (*ParentsToGitHubResult, error)
PushParentsToGitHub pushes local parent relationships to GitHub PR bases. Local metadata is authoritative - if local parent differs from GitHub PR base, update GitHub.
type PlanEngine ¶ added in v0.29.0
type PlanEngine interface {
actions.ManagedWorktreeSource
Trunk() engine.Branch
AllBranches() engine.Branches
ReadBranchRemoteStatuses(ctx context.Context, branches engine.Branches) engine.BranchRemoteStatuses
ReadBranchStatuses(ctx context.Context, branches engine.Branches) engine.BranchStatuses
GetDeletionStatuses(ctx context.Context, branchNames []string) (engine.DeletionStatuses, error)
GetStackRootForBranch(branch engine.Branch) string
}
PlanEngine is the read-only engine surface PlanDryRun needs.
type PlanRequest ¶ added in v0.29.0
type PlanRequest struct {
// Restack previews restacking of every out-of-date tracked branch, as
// `sync --restack` would.
Restack bool
}
PlanRequest configures a dry-run sync plan.
type StackMetadataGCResult ¶
type StackMetadataGCResult struct {
DeletedStackIDs []string // Stack IDs whose refs were deleted
Errors []string // Any errors encountered (non-fatal)
}
StackMetadataGCResult contains the results of stack metadata garbage collection.
type Summary ¶
type Summary struct {
TrunkUpdated bool // Was trunk updated?
TrunkRevision string // New trunk revision (short hash)
BranchesSynced int // Number of branches synced from remote
BranchesRestacked int // Number of branches restacked
BranchesDeleted int // Number of branches deleted
BranchesSkipped int // Number of branches skipped (due to conflicts)
ConflictBranches []string // Names of branches that conflicted
BranchesBlocked int // Number of branches left untouched because their stack conflicted
UpToDate bool // Everything was already current
WorktreesCleaned int // Number of orphaned worktrees cleaned up
SkippedStacks []string // Stacks skipped due to dirty worktrees
}
Summary holds aggregate results from a sync operation
func (*Summary) HasChanges ¶
HasChanges returns true if any operations were performed
type WorktreeCleanupResult ¶
type WorktreeCleanupResult struct {
RemovedWorktrees []string // Stack roots whose worktrees were removed
Errors []string // Any errors encountered (non-fatal)
}
WorktreeCleanupResult contains the results of worktree cleanup