Documentation
¶
Index ¶
- Variables
- func Save(gitDir string, sf *StackFile) error
- func SaveNonBlocking(gitDir string, sf *StackFile)
- type BranchRef
- type FileLock
- type LockError
- type PullRequestRef
- type Stack
- func (s *Stack) ActiveBaseBranch(branch string) string
- func (s *Stack) ActiveBranchIndices() []int
- func (s *Stack) ActiveBranches() []BranchRef
- func (s *Stack) BaseBranch(branch string) string
- func (s *Stack) BranchNames() []string
- func (s *Stack) Contains(branch string) bool
- func (s *Stack) DisplayChain() string
- func (s *Stack) FirstActiveBranchIndex() int
- func (s *Stack) IndexOf(branch string) int
- func (s *Stack) IsFullyMerged() bool
- func (s *Stack) MergedBranches() []BranchRef
- func (s *Stack) QueuedBranches() []BranchRef
- type StackFile
- func (sf *StackFile) AddStack(s Stack)
- func (sf *StackFile) FindAllStacksForBranch(branch string) []*Stack
- func (sf *StackFile) FindStackByPRNumber(prNumber int) (*Stack, *BranchRef)
- func (sf *StackFile) RemoveStack(idx int)
- func (sf *StackFile) RemoveStackForBranch(branch string) bool
- func (sf *StackFile) ValidateNoDuplicateBranch(branch string) error
- type StaleError
Constants ¶
This section is empty.
Variables ¶
var LockTimeout = 5 * time.Second
LockTimeout is how long Lock() will wait for the exclusive lock before giving up. With the lock held only during file writes (milliseconds), this timeout primarily guards against a hung process holding the lock.
Functions ¶
func Save ¶
Save acquires an exclusive lock on the stack file, verifies the file hasn't been modified since Load (optimistic concurrency), writes sf as JSON, and releases the lock. The lock is held only for the read-compare-write window. Returns *LockError if the lock times out, or *StaleError if another process modified the file since it was loaded.
func SaveNonBlocking ¶
SaveNonBlocking attempts to save without blocking. If another process holds the lock or the file was modified since Load, the save is silently skipped. Use this for best-effort metadata persistence (e.g. syncing PR state in view).
Types ¶
type BranchRef ¶
type BranchRef struct {
Branch string `json:"branch"`
Head string `json:"head,omitempty"`
Base string `json:"base,omitempty"`
PullRequest *PullRequestRef `json:"pullRequest,omitempty"`
// Queued is a transient (not persisted) flag indicating the branch's
// PR is currently in a merge queue. It is populated by syncStackPRs
// from the GitHub API on each command run.
Queued bool `json:"-"`
}
BranchRef represents a branch and its associated commit hash. For the trunk, Head stores the HEAD commit SHA. For stacked branches, Base stores the parent branch's HEAD SHA at the time of last sync/rebase, used to identify unique commits.
type FileLock ¶
type FileLock struct {
// contains filtered or unexported fields
}
FileLock provides an exclusive advisory lock on the stack file to prevent concurrent writes between multiple gh-stack processes.
func Lock ¶
Lock acquires an exclusive lock on the stack file in the given git directory. It retries with a non-blocking attempt every 100ms for up to LockTimeout.
Most callers should not use Lock directly — stack.Save() acquires the lock automatically. Use Lock only when you need to hold the lock across multiple operations (e.g. Load-Modify-Save as an atomic unit).
func (*FileLock) Unlock ¶
func (l *FileLock) Unlock()
Unlock releases the lock. The lock file is intentionally left on disk to avoid a race where another process opens the same path, blocks on flock, then wakes up holding a lock on an unlinked inode while a third process creates a new file and locks a different inode.
type LockError ¶
type LockError struct {
Err error
}
LockError is returned when the stack file lock cannot be acquired. Callers can check for this with errors.As to distinguish lock failures from other errors.
type PullRequestRef ¶
type PullRequestRef struct {
Number int `json:"number"`
ID string `json:"id,omitempty"`
URL string `json:"url,omitempty"`
Merged bool `json:"merged,omitempty"`
}
PullRequestRef holds relatively immutable metadata about an associated PR.
type Stack ¶
type Stack struct {
ID string `json:"id,omitempty"`
Prefix string `json:"prefix,omitempty"`
Numbered bool `json:"numbered,omitempty"`
Trunk BranchRef `json:"trunk"`
Branches []BranchRef `json:"branches"`
}
Stack represents a single stack of branches.
func (*Stack) ActiveBaseBranch ¶
ActiveBaseBranch returns the effective parent for a branch, skipping merged and queued ancestors. For the first active branch (or any branch whose downstack is all merged/queued), this returns the trunk.
func (*Stack) ActiveBranchIndices ¶
ActiveBranchIndices returns the indices of all active (not merged, not queued) branches.
func (*Stack) ActiveBranches ¶
ActiveBranches returns only branches that are pushable (not merged, not queued).
func (*Stack) BaseBranch ¶
BaseBranch returns the base branch for the given branch in the stack. For the first branch, this is the trunk. For others, it's the previous branch.
func (*Stack) BranchNames ¶
BranchNames returns the list of branch names in order.
func (*Stack) Contains ¶
Contains returns true if the branch is part of this stack (including trunk).
func (*Stack) DisplayChain ¶
DisplayChain returns a human-readable chain representation of the stack. Format: (trunk) <- branch1 <- branch2 <- branch3
func (*Stack) FirstActiveBranchIndex ¶
FirstActiveBranchIndex returns the index of the first active (not merged, not queued) branch, or -1.
func (*Stack) IndexOf ¶
IndexOf returns the index of the given branch in the stack, or -1 if not found.
func (*Stack) IsFullyMerged ¶
IsFullyMerged returns true if all branches in the stack have been merged.
func (*Stack) MergedBranches ¶
MergedBranches returns only merged branches, preserving order.
func (*Stack) QueuedBranches ¶
QueuedBranches returns only queued branches, preserving order.
type StackFile ¶
type StackFile struct {
SchemaVersion int `json:"schemaVersion"`
Repository string `json:"repository"`
Stacks []Stack `json:"stacks"`
// contains filtered or unexported fields
}
StackFile represents the JSON file stored in .git/gh-stack.
func Load ¶
Load reads the stack file from the given git directory. Returns an empty StackFile if the file does not exist. The returned StackFile records a checksum of the on-disk content so that Save can detect concurrent modifications.
func (*StackFile) FindAllStacksForBranch ¶
FindAllStacksForBranch returns all stacks that contain the given branch.
func (*StackFile) FindStackByPRNumber ¶
FindStackByPRNumber returns the first stack and branch whose PR number matches. Returns nil, nil if no match is found.
func (*StackFile) RemoveStack ¶
RemoveStack removes the stack at the given index.
func (*StackFile) RemoveStackForBranch ¶
RemoveStackForBranch removes the stack containing the given branch.
func (*StackFile) ValidateNoDuplicateBranch ¶
ValidateNoDuplicateBranch checks that the branch is not already in any stack.
type StaleError ¶
type StaleError struct {
Err error
}
StaleError is returned when the stack file was modified on disk since it was loaded. This indicates another process wrote to the file concurrently. Callers can check for this with errors.As.
func (*StaleError) Error ¶
func (e *StaleError) Error() string
func (*StaleError) Unwrap ¶
func (e *StaleError) Unwrap() error