Documentation
¶
Index ¶
- type AfterRebaseCallback
- type BeforeRebaseCallback
- type CleanupResult
- type FullyMergedStackInfo
- type Manager
- func (m *Manager) AddBranchToStack(name, parentBranch, worktreeDir, targetStackHash string) (*config.Branch, error)
- func (m *Manager) AddWorktreeToStack(branchName, worktreePath, parentName string) (*config.Branch, error)
- func (m *Manager) ApplyBranchRenames(renames []RenamedBranchInfo) error
- func (m *Manager) CleanupMergedBranches(branches []MergedBranchInfo, currentDir string) []CleanupResult
- func (m *Manager) CreateBranch(name, parentBranch, worktreeDir, targetStackHash string) (*config.Branch, error)
- func (m *Manager) CreateBranchNoWorktree(name, parentBranch, targetStackHash string) (*config.Branch, error)
- func (m *Manager) CreateWorktreeOnly(name, parentBranch, worktreeDir string) error
- func (m *Manager) DeclineStackDelete(stackHash string) error
- func (m *Manager) DeleteBranch(branchName string, force bool) error
- func (m *Manager) DeleteStack(stackHash string) (bool, error)
- func (m *Manager) DetectFullyMergedStacks(stacks []*config.Stack) []FullyMergedStackInfo
- func (m *Manager) DetectMergedBranches(gh *github.Client) ([]MergedBranchInfo, error)
- func (m *Manager) DetectMergedBranchesAllStacks(gh *github.Client) ([]MergedBranchInfo, error)
- func (m *Manager) DetectMergedBranchesForStacks(gh *github.Client, stacks []*config.Stack) ([]MergedBranchInfo, error)
- func (m *Manager) DetectMissingWorktrees() []MissingWorktreeInfo
- func (m *Manager) DetectOrphanedBranches() []string
- func (m *Manager) DetectRenamedBranches(orphaned []string, untracked []git.Worktree) []RenamedBranchInfo
- func (m *Manager) DetectSyncNeeded(gh *github.Client) ([]SyncInfo, error)
- func (m *Manager) DetectSyncNeededAllStacks(gh *github.Client) ([]SyncInfo, error)
- func (m *Manager) DetectSyncNeededForBranch(branchName string, gh *github.Client) *SyncInfo
- func (m *Manager) DetectSyncNeededForStacks(gh *github.Client, stacks []*config.Stack) ([]SyncInfo, error)
- func (m *Manager) Fetch() error
- func (m *Manager) FindStackForBranch(branchName string) *config.Stack
- func (m *Manager) GetAllBranchesInAllStacks() []*config.Branch
- func (m *Manager) GetBranch(name string) *config.Branch
- func (m *Manager) GetChildren(branchName string) []*config.Branch
- func (m *Manager) GetConfig() *config.Config
- func (m *Manager) GetCurrentStack() (*config.Stack, *config.Branch, error)
- func (m *Manager) GetRepoDir() string
- func (m *Manager) GetStackByHash(prefix string) (*config.Stack, error)
- func (m *Manager) GetStackByHashExact(hash string) *config.Stack
- func (m *Manager) GetStackForBranch(branchName string) *config.Stack
- func (m *Manager) GetStacksWithRoot(rootName string) []*config.Stack
- func (m *Manager) GetTreeChildren(branchName string) []*config.Branch
- func (m *Manager) GetUnregisteredWorktrees() ([]git.Worktree, error)
- func (m *Manager) HandleMissingWorktrees(branches []MissingWorktreeInfo) error
- func (m *Manager) HasStackWithRoot(rootName string) bool
- func (m *Manager) IsMainBranch(name string) bool
- func (m *Manager) ListStacks() []*config.Stack
- func (m *Manager) MarkBranchMerged(branchName string) error
- func (m *Manager) MarkBranchRemote(branchName, prURL, remote string) error
- func (m *Manager) RebaseChildren(useMerge ...bool) ([]RebaseResult, error)
- func (m *Manager) RebaseOnParent(useMerge ...bool) error
- func (m *Manager) Reconcile()
- func (m *Manager) RegisterExistingBranch(branchName, worktreePath, baseBranch string) (*config.Branch, error)
- func (m *Manager) RegisterRemoteBranch(branchName, baseBranch string, prNumber int, prURL string) (string, error)
- func (m *Manager) RemoveOrphanedBranches(branchNames []string) error
- func (m *Manager) ReparentBranch(branchName, newParentName string, doRebase bool, useMerge ...bool) (*ReparentResult, error)
- func (m *Manager) SetStackName(stackHash, name string) error
- func (m *Manager) SyncBranch(branchName string, gh *github.Client, useMerge ...bool) (*RebaseResult, error)
- func (m *Manager) SyncSpecificStacks(stacks []*config.Stack, gh *github.Client, callbacks *SyncCallbacks) ([]RebaseResult, error)
- func (m *Manager) SyncStack(gh *github.Client, callbacks *SyncCallbacks) ([]RebaseResult, error)
- func (m *Manager) SyncStackAll(gh *github.Client, callbacks *SyncCallbacks) ([]RebaseResult, error)
- func (m *Manager) UntrackBranch(branchName string) error
- type MergedBranchInfo
- type MissingWorktreeInfo
- type RebaseResult
- type RenamedBranchInfo
- type ReparentInfo
- type ReparentResult
- type SyncCallbacks
- type SyncInfo
- type UpdateResult
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
This section is empty.
Types ¶
type AfterRebaseCallback ¶
type AfterRebaseCallback func(result RebaseResult, g *git.Git) bool
AfterRebaseCallback is called after each successful rebase It receives the result and the git instance for the worktree Returns true if sync should continue, false to stop
type BeforeRebaseCallback ¶
BeforeRebaseCallback is called before each rebase to ask for confirmation It receives the sync info for the branch about to be synced Returns true to proceed with rebase, false to skip this branch
type CleanupResult ¶
type CleanupResult struct {
Branch string
Success bool
Error string
WorktreeWasDeleted bool // True if worktree was already deleted before cleanup
WasCurrentWorktree bool // True if this was the worktree we were in when cleanup started
}
CleanupResult contains information about a branch cleanup operation
type FullyMergedStackInfo ¶
type FullyMergedStackInfo struct {
StackHash string
Stack *config.Stack
HasLocalArtifacts bool // true if worktrees or git branches still exist locally
}
FullyMergedStackInfo contains information about a fully merged stack
type Manager ¶
type Manager struct {
// contains filtered or unexported fields
}
Manager handles stack operations
func NewManager ¶
NewManager creates a new stack manager and reconciles config with git state. Use this for commands that mutate state (new, delete, sync, reparent, stack, etc.).
func NewReadOnlyManager ¶
NewReadOnlyManager creates a stack manager without reconciliation. Use this for read-only commands (diff, goto, list, status, up, down, push) where the ~100ms reconciliation cost is unnecessary.
func (*Manager) AddBranchToStack ¶
func (m *Manager) AddBranchToStack(name, parentBranch, worktreeDir, targetStackHash string) (*config.Branch, error)
AddBranchToStack adds an existing branch to a stack (worktree should already exist) This is used when the worktree was created externally (e.g., from a remote branch) If targetStackHash is non-empty, the branch is added to that specific stack. Otherwise, the stack is found by looking up the parent branch.
func (*Manager) AddWorktreeToStack ¶
func (m *Manager) AddWorktreeToStack(branchName, worktreePath, parentName string) (*config.Branch, error)
AddWorktreeToStack adds an unregistered worktree to a stack with the specified parent
func (*Manager) ApplyBranchRenames ¶
func (m *Manager) ApplyBranchRenames(renames []RenamedBranchInfo) error
ApplyBranchRenames updates the config to reflect branch renames. For each rename, it updates the tree key, moves the cache entry, and preserves all metadata.
func (*Manager) CleanupMergedBranches ¶
func (m *Manager) CleanupMergedBranches(branches []MergedBranchInfo, currentDir string) []CleanupResult
CleanupMergedBranches marks branches as merged - deletes worktrees and git branches but keeps metadata in config This allows merged PRs to still show up in ezs ls/status with strikethrough styling Returns detailed results for each branch cleanup operation
func (*Manager) CreateBranch ¶
func (m *Manager) CreateBranch(name, parentBranch, worktreeDir, targetStackHash string) (*config.Branch, error)
CreateBranch creates a new branch in the stack. targetStackHash controls stack placement: "" for auto-detect, "new" for a new stack, or a specific stack hash to add to.
func (*Manager) CreateBranchNoWorktree ¶
func (m *Manager) CreateBranchNoWorktree(name, parentBranch, targetStackHash string) (*config.Branch, error)
CreateBranchNoWorktree creates a new branch without a worktree and adds it to a stack. targetStackHash controls stack placement: "" for auto-detect, "new" for a new stack, or a specific stack hash to add to.
func (*Manager) CreateWorktreeOnly ¶
CreateWorktreeOnly creates a worktree without adding it to a stack This is used when the user wants to create a standalone worktree from main/master
func (*Manager) DeclineStackDelete ¶
DeclineStackDelete marks a stack so cleanup prompts are not repeated.
func (*Manager) DeleteBranch ¶
DeleteBranch removes a branch from the stack and deletes its worktree Returns an error if the branch has child branches
func (*Manager) DeleteStack ¶
DeleteStack removes an entire stack from config, cleaning up any remaining worktrees and git branches. This is intended for fully merged stacks where all branches have been completed. Returns (needsCd, error) — needsCd is true when the process had to leave a worktree that was deleted, so the caller can emit a cd to the main repo.
func (*Manager) DetectFullyMergedStacks ¶
func (m *Manager) DetectFullyMergedStacks(stacks []*config.Stack) []FullyMergedStackInfo
DetectFullyMergedStacks finds stacks where every branch is merged
func (*Manager) DetectMergedBranches ¶
func (m *Manager) DetectMergedBranches(gh *github.Client) ([]MergedBranchInfo, error)
DetectMergedBranches finds branches in the CURRENT stack whose PRs have been merged to main These are candidates for cleanup (deleting local branch and worktree)
func (*Manager) DetectMergedBranchesAllStacks ¶
func (m *Manager) DetectMergedBranchesAllStacks(gh *github.Client) ([]MergedBranchInfo, error)
DetectMergedBranchesAllStacks finds branches across ALL stacks whose PRs have been merged to main
func (*Manager) DetectMergedBranchesForStacks ¶
func (m *Manager) DetectMergedBranchesForStacks(gh *github.Client, stacks []*config.Stack) ([]MergedBranchInfo, error)
DetectMergedBranchesForStacks finds branches in specific stacks whose PRs have been merged
func (*Manager) DetectMissingWorktrees ¶
func (m *Manager) DetectMissingWorktrees() []MissingWorktreeInfo
DetectMissingWorktrees finds branches whose worktree directories no longer exist on disk This can happen when a user manually removes a worktree with `rm -rf`
func (*Manager) DetectOrphanedBranches ¶
DetectOrphanedBranches finds branches in config that no longer exist in git
func (*Manager) DetectRenamedBranches ¶
func (m *Manager) DetectRenamedBranches(orphaned []string, untracked []git.Worktree) []RenamedBranchInfo
DetectRenamedBranches correlates orphaned branches (in config but not in git) with untracked worktrees (in git but not in config) by matching worktree paths. If an orphaned branch's cached worktree path matches an untracked worktree's path, it's almost certainly a rename (git branch -m old new).
func (*Manager) DetectSyncNeeded ¶
DetectSyncNeeded checks for branches that need syncing in the CURRENT stack only: - Branches whose parents have been merged to main - Branches whose parent is main but are behind origin/main
func (*Manager) DetectSyncNeededAllStacks ¶
DetectSyncNeededAllStacks checks for branches that need syncing across ALL stacks: - Branches whose parents have been merged to main - Branches whose parent is main but are behind origin/main
func (*Manager) DetectSyncNeededForBranch ¶
DetectSyncNeededForBranch checks if a specific branch needs syncing Returns SyncInfo if the branch needs syncing, nil otherwise
func (*Manager) DetectSyncNeededForStacks ¶
func (m *Manager) DetectSyncNeededForStacks(gh *github.Client, stacks []*config.Stack) ([]SyncInfo, error)
DetectSyncNeededForStacks checks for branches that need syncing in specific stacks
func (*Manager) Fetch ¶
Fetch runs git fetch once per Manager lifetime. Subsequent calls are no-ops.
func (*Manager) FindStackForBranch ¶
FindStackForBranch finds which stack a branch belongs to (exported)
func (*Manager) GetAllBranchesInAllStacks ¶
GetAllBranchesInAllStacks returns all branches across all stacks
func (*Manager) GetChildren ¶
GetChildren returns all child branches of a given branch
func (*Manager) GetConfig ¶
GetConfig returns the loaded global config, avoiding redundant config.Load() calls.
func (*Manager) GetCurrentStack ¶
GetCurrentStack returns the stack for the current branch
func (*Manager) GetRepoDir ¶
GetRepoDir returns the main repository directory
func (*Manager) GetStackByHash ¶
GetStackByHash finds a stack by hash prefix (minimum 3 characters). Returns error if 0 or >1 stacks match.
func (*Manager) GetStackByHashExact ¶
GetStackByHashExact returns a stack by its exact hash (no prefix matching).
func (*Manager) GetStackForBranch ¶
GetStackForBranch returns the stack containing the given branch, or nil.
func (*Manager) GetStacksWithRoot ¶
GetStacksWithRoot returns all stacks that use rootName as their root
func (*Manager) GetTreeChildren ¶
GetTreeChildren returns child branches based on the original tree structure (BaseBranch), not the effective parent. This is used for navigation (up/down) where we want to follow the tree hierarchy even when parents have been merged and children reparented.
func (*Manager) GetUnregisteredWorktrees ¶
GetUnregisteredWorktrees returns worktrees that exist but are not registered in any stack
func (*Manager) HandleMissingWorktrees ¶
func (m *Manager) HandleMissingWorktrees(branches []MissingWorktreeInfo) error
HandleMissingWorktrees cleans up branches whose worktrees were manually removed It removes the branches from the stack config (git worktree prune should be called first)
func (*Manager) HasStackWithRoot ¶
HasStackWithRoot checks if any stack uses rootName as its root
func (*Manager) IsMainBranch ¶
IsMainBranch checks if a branch is the main/master branch. Use only for protection (e.g. preventing deletion of main). For stack-root logic, compare against Stack.Root or use GetStackForBranch instead.
func (*Manager) ListStacks ¶
ListStacks returns all stacks sorted by name for deterministic ordering
func (*Manager) MarkBranchMerged ¶
MarkBranchMerged marks a branch as merged - deletes worktree and git branch but keeps metadata in config This allows merged branches to still show up in ezs ls/status with strikethrough The tree structure is NOT modified - children stay under the merged parent for display order. The effective git parent for children is computed at runtime by skipping merged ancestors.
func (*Manager) MarkBranchRemote ¶
MarkBranchRemote marks a branch as belonging to another contributor. Remote branches are not rebased during sync. Optionally sets PR URL. If remote is non-empty, it specifies the git remote to push to (for fork PRs).
func (*Manager) RebaseChildren ¶
func (m *Manager) RebaseChildren(useMerge ...bool) ([]RebaseResult, error)
RebaseChildren syncs all child branches after updating the current branch. When useMerge is true, git merge is used instead of git rebase. Returns results for each child branch processed.
func (*Manager) RebaseOnParent ¶
RebaseOnParent syncs the current branch onto its updated parent. When useMerge is true, git merge is used instead of git rebase.
func (*Manager) Reconcile ¶
func (m *Manager) Reconcile()
Reconcile silently reconciles ezstack config with git reality. It detects renamed branches, removes orphaned entries, and cleans up missing worktrees. This runs automatically when a Manager is created, so commands always see consistent state.
func (*Manager) RegisterExistingBranch ¶
func (m *Manager) RegisterExistingBranch(branchName, worktreePath, baseBranch string) (*config.Branch, error)
RegisterExistingBranch registers an existing branch/worktree as the root of a new stack
func (*Manager) RegisterRemoteBranch ¶
func (m *Manager) RegisterRemoteBranch(branchName, baseBranch string, prNumber int, prURL string) (string, error)
RegisterRemoteBranch creates a new stack with a remote branch as its root/base. The remote branch is NOT added to the tree — it is the stack root. PR info is stored on the Stack struct for display in stack descriptions.
func (*Manager) RemoveOrphanedBranches ¶
RemoveOrphanedBranches removes branches from config that no longer exist in git
func (*Manager) ReparentBranch ¶
func (m *Manager) ReparentBranch(branchName, newParentName string, doRebase bool, useMerge ...bool) (*ReparentResult, error)
ReparentBranch changes the parent of a branch to a new parent This handles several cases: 1. Branch is already in a stack - just update parent pointer 2. Branch is standalone (not in any stack) - add it to the new parent's stack 3. New parent is in a different stack - merge stacks or move branch If doRebase is true, performs git rebase --onto to move commits. Config changes are always saved first. If rebase has conflicts, the result will have HasConflict=true but the branch will still be returned (config is updated).
func (*Manager) SetStackName ¶
SetStackName sets or updates the name of a stack
func (*Manager) SyncBranch ¶
func (m *Manager) SyncBranch(branchName string, gh *github.Client, useMerge ...bool) (*RebaseResult, error)
SyncBranch syncs a specific branch, handling all cases: - Branch is behind origin/main (parent is main) - Parent branch was merged (rebase --onto main or merge) - Branch is behind its parent (rebase onto parent or merge) When useMerge is true, git merge is used instead of git rebase.
func (*Manager) SyncSpecificStacks ¶
func (m *Manager) SyncSpecificStacks(stacks []*config.Stack, gh *github.Client, callbacks *SyncCallbacks) ([]RebaseResult, error)
SyncSpecificStacks syncs branches in the given stacks
func (*Manager) SyncStack ¶
func (m *Manager) SyncStack(gh *github.Client, callbacks *SyncCallbacks) ([]RebaseResult, error)
SyncStack syncs branches in the CURRENT stack only that need syncing This handles three cases: - Branches whose parent is main but are behind origin/main (simple rebase) - Branches whose parent was merged (rebase onto main using --onto) - Branches whose parent is not merged but has new commits (rebase onto parent) Callbacks can be used to ask for confirmation before each rebase and push after
func (*Manager) SyncStackAll ¶
func (m *Manager) SyncStackAll(gh *github.Client, callbacks *SyncCallbacks) ([]RebaseResult, error)
SyncStackAll syncs branches in ALL stacks that need syncing
func (*Manager) UntrackBranch ¶
UntrackBranch removes a branch from ezstack tracking without deleting the git branch or worktree Children of the untracked branch are reparented to the untracked branch's parent
type MergedBranchInfo ¶
MergedBranchInfo contains information about a branch whose PR has been merged
type MissingWorktreeInfo ¶
MissingWorktreeInfo contains info about a branch whose worktree was removed
type RebaseResult ¶
type RebaseResult struct {
Branch string
Success bool
HasConflict bool
Error error
SyncedParent string // If non-empty, parent was merged and we synced to this new parent
WorktreePath string // Path to the worktree (useful for conflict resolution)
BehindBy int // Number of commits behind (for branches that need sync with origin/main)
StackName string // Display name of the stack this branch belongs to
Remote string // Git remote to push to (empty means "origin")
}
RebaseResult represents the result of a rebase operation
type RenamedBranchInfo ¶
RenamedBranchInfo contains info about a branch that was renamed outside of ezstack
type ReparentInfo ¶
ReparentInfo contains info about a branch that was reparented
type ReparentResult ¶
type ReparentResult struct {
Branch *config.Branch
HasConflict bool // true if rebase had conflicts (config was still saved)
ConflictDir string // worktree path where conflicts need to be resolved
}
ReparentResult holds the result of a reparent operation
type SyncCallbacks ¶
type SyncCallbacks struct {
BeforeRebase BeforeRebaseCallback
AfterRebase AfterRebaseCallback
Autostash bool // Stash uncommitted changes before rebase, pop after
UseMerge bool // Use git merge instead of git rebase
}
SyncCallbacks contains optional callbacks for sync operations
type SyncInfo ¶
type SyncInfo struct {
Branch string
MergedParent string // Non-empty if parent was merged
BehindBy int // Number of commits behind target
BehindParent string // Non-empty if behind a non-main parent
StackRoot string // The root branch of this branch's stack (e.g. "main", "develop")
NeedsSync bool // True if branch needs to be synced
}
SyncInfo contains information about a branch that needs syncing
type UpdateResult ¶
type UpdateResult struct {
// Branches that were removed from config because they no longer exist in git
RemovedBranches []string
// Worktrees that were discovered and added to stacks
AddedBranches []*config.Branch
// Branches whose parent was updated based on merge-base analysis
ReparentedBranches []ReparentInfo
// Branches that were detected as renames and updated
RenamedBranches []RenamedBranchInfo
}
UpdateResult contains the results of an update operation