On this page
Package coord implements the coordination layer that prevents concurrent agents from corrupting the working tree by guarding tree-mutating operations.
#internal/coord
#internal/coord
Package coord implements the coordination layer that prevents concurrent agents from corrupting the working tree by guarding tree-mutating operations. It checks whether the working tree is clean before allowing switch, merge, rebase, reset, and pull to proceed.
It also owns the other half of that coordination: what safegit does when git itself has an operation in flight. sequencer.Read reports the state and holds no policy; this package decides which commands may run against it (GuardInFlight) and what the operator is told when one may not (WayOutOf, RefuseInFlight). Both refusal paths -- the commit pipeline's and the passthrough guard's -- render their advice from here, so they cannot name different commands for the same state.
#DirtyState
type DirtyState structDirtyState describes why the working tree is not clean.
#SequencerContext
type SequencerContext structSequencerContext is a caller's DECLARATION that it is the conclusion path for an in-flight git operation.
Every ordinary caller passes nil, which means "refuse if anything is in flight" -- a commit, an amend, a reword or an undo taken while git is mid-merge or mid-cherry-pick builds its tree from a parent commit and hands commit-tree a single parent, silently discarding the operation's staged result and its second parent. A non-nil context means the caller IS the command that finishes the named operation and must be allowed to commit during exactly the state everyone else is refused for.
The declaration is checked, not trusted: a context naming an operation other than the one actually in flight is itself a refusal, as is a context supplied when nothing is in flight at all.
#WayOut
type WayOut structWayOut names the commands that end an in-flight operation: the one that concludes it, keeping the work, and the one that abandons it, throwing the work away.
It is the single authority for that advice. Every refusal safegit prints while an operation is in flight renders it from here, so no two refusals can name different commands for the same state.
#InFlightError
type InFlightError structInFlightError is the refusal a command owes an operator when git has an operation in flight that the command cannot run against. Its message states what is in flight, factually, and the way out.
#Check
func Check(ctx context.Context, gitDir string) (*DirtyState, error)Check inspects the working tree of the repository whose git directory is gitDir. Returns nil if clean.
#WayOutOf
func WayOutOf(s sequencer.State) WayOutWayOutOf returns the way out of the state s reports.
Where safegit owns the conclusion it names its own command; where it does not it names git's, and it never names git's rebase commands for a git am or the other way round -- the two share a state directory and an operator sent to the wrong one gets a refusal, not a conclusion.
#RefuseInFlight
func RefuseInFlight(operation string, s sequencer.State) stringRefuseInFlight renders the refusal text for one operation against one state.
#GuardInFlight
func GuardInFlight(gitDir, operation string, declared *SequencerContext) errorGuardInFlight is the one check that decides whether operation may run against whatever git has in flight in gitDir. It returns nil when it may, an *InFlightError when the state forbids it, and a plain error when the state could not be read at all -- which is also a refusal, because a state file safegit cannot parse is not evidence that nothing is in flight.
declared is the caller's SequencerContext: nil for every ordinary caller.
It is filesystem-only (sequencer.Read starts no subprocess), so putting it on the hot path of commit costs a handful of stat calls.
#DirtyState.Refuse
func (d *DirtyState) Refuse(operation string) stringRefuse formats a refusal message from a DirtyState.
The advice depends on WHY the tree is dirty. Ordinarily the dirt is the operator's own uncommitted work and committing it is the way forward. While git has an operation in flight the same dirt is the operation's conflict markers and staged result: committing it is exactly what safegit refuses to do (it would drop the operation's other parent and everything the pathspec does not name), so the message names the operation and the command that ends it instead of advice no one can follow.
#InFlightError.Error
func (e *InFlightError) Error() string { return RefuseInFlight(e.Operation, e.State) }