git

package
v0.12.0 Latest Latest
Warning

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

Go to latest
Published: May 31, 2026 License: MIT Imports: 15 Imported by: 0

Documentation

Overview

Package git wraps all git CLI interactions. No other package shells out to git.

Index

Constants

View Source
const (
	OpFetch      = "fetch"
	OpCommit     = "commit"
	OpPush       = "push"
	OpRecover    = "recover"
	OpQueueFlush = "queue-flush"
)

Sync audit operation kinds recorded via the injected Recorder.

View Source
const (
	OutcomeOK       = "ok"
	OutcomeQueued   = "queued"
	OutcomeConflict = "conflict"
	OutcomeError    = "error"
)

Sync outcomes mirrored from the store layer so callers in git don't need to import internal/store (adapter-isolation: only internal/store touches SQLite).

View Source
const (

	// SpecsSubDir is the sub-directory within the specs repo where spec
	// files are stored. All spec, triage, and archive content lives under
	// this path.
	SpecsSubDir = "specs"
)

Variables

This section is empty.

Functions

func ArchiveSpec added in v0.8.0

func ArchiveSpec(ctx context.Context, cfg *config.SpecsRepoConfig, specID, archiveDir string) error

ArchiveSpec moves a spec from specs/ to archive/ and commits the change.

func BranchExists

func BranchExists(ctx context.Context, dir, branch string) bool

BranchExists checks if a branch exists locally.

func CheckoutBranch

func CheckoutBranch(ctx context.Context, dir, branch string) error

CheckoutBranch checks out an existing branch.

func Clone

func Clone(ctx context.Context, url, dir string) error

Clone clones a repository to the given directory.

func Commit

func Commit(ctx context.Context, dir, message string) error

Commit stages all changes and creates a commit.

func CommitsBehind added in v0.12.0

func CommitsBehind(ctx context.Context, dir, remoteBranch string) (int, error)

CommitsBehind returns how many commits the local HEAD is behind the remote branch (i.e. new upstream commits not yet on HEAD). Returns 0 if the remote ref is unknown.

func CommittedFiles added in v0.7.0

func CommittedFiles(ctx context.Context, dir, ref string) ([]string, error)

CommittedFiles returns the list of files changed in the given commit.

func ConfigGet

func ConfigGet(ctx context.Context, dir, key string) (string, error)

ConfigGet returns a git config value.

func CreateBranch

func CreateBranch(ctx context.Context, dir, branch string) error

CreateBranch creates and checks out a new branch.

func CurrentBranch

func CurrentBranch(ctx context.Context, dir string) (string, error)

CurrentBranch returns the current branch name.

func DetectSpecFromBranch

func DetectSpecFromBranch(ctx context.Context, dir string) string

DetectSpecFromBranch attempts to detect the spec ID from the current branch.

func Diff

func Diff(ctx context.Context, dir, baseRef string) (string, error)

Diff returns the diff for the current branch compared to a base ref.

func DiffNameOnly added in v0.7.0

func DiffNameOnly(ctx context.Context, dir, refA, refB string) ([]string, error)

DiffNameOnly returns file paths changed between two refs.

func DiffStaged

func DiffStaged(ctx context.Context, dir string) (string, error)

DiffStaged returns the diff of staged changes.

func EnsureSpecsRepo

func EnsureSpecsRepo(ctx context.Context, cfg *config.SpecsRepoConfig) (string, error)

EnsureSpecsRepo clones the specs repo if not present, otherwise fetches the latest under a SHARED (read) lock. It is the non-destructive read path: it never runs `reset --hard` and never blocks on or discards local edits, so a working tree with in-flight changes survives a read command untouched (SPEC-013 axes 1–3). The destructive reset is reserved for the mutate path (WithSpecsRepo). A fetch is skipped entirely when one completed within the freshness TTL.

func Fetch

func Fetch(ctx context.Context, dir string) error

Fetch fetches from origin in the given repo directory.

func FlushQueue added in v0.12.0

func FlushQueue(ctx context.Context, cfg *config.SpecsRepoConfig, opts SyncOptions)

FlushQueue drains queued (offline / contention-exhausted) pushes for the specs repo. It is best-effort and non-fatal: it is invoked opportunistically by read and mutate paths and by `spec status`. Each queued entry is reconciled independently — a same-section conflict marks only that entry needs-resolution and never strands the rest (SPEC-013 §Decision 010, AC-24).

Because autoRecover already pushes any unpushed commits at the start of every committing operation, the common case is that the branch is pushable; FlushQueue resolves the queued markers once the branch lands.

func HasChanges

func HasChanges(ctx context.Context, dir string) (bool, error)

HasChanges returns true if there are uncommitted changes.

func HasUnpushedCommits added in v0.7.0

func HasUnpushedCommits(ctx context.Context, dir, remoteBranch string) (bool, error)

HasUnpushedCommits returns true if there are local commits not on the remote branch.

func IsGitRepo

func IsGitRepo(dir string) bool

IsGitRepo checks if the directory is inside a git repository.

func IsSectionConflict added in v0.12.0

func IsSectionConflict(err error) bool

IsSectionConflict reports whether err is (or wraps) a genuine same-section collision — the only push failure that must block a human (vs. a queued transient/contention failure, which is non-fatal).

func ListArchiveFiles

func ListArchiveFiles(cfg *config.SpecsRepoConfig, archiveDir string) ([]string, error)

ListArchiveFiles returns all archived spec files.

func ListSpecFiles

func ListSpecFiles(cfg *config.SpecsRepoConfig) ([]string, error)

ListSpecFiles returns all spec files in the specs/ directory of the specs repo, resolved from the fetched remote ref so the listing reflects upstream without a working-tree reset. Falls back to the working tree on error.

func ListTriageFiles

func ListTriageFiles(cfg *config.SpecsRepoConfig) ([]string, error)

ListTriageFiles returns all triage files in the specs/triage/ directory.

func Log

func Log(ctx context.Context, dir string, n int, format string) (string, error)

Log returns recent commit messages.

func Push

func Push(ctx context.Context, dir, branch string) error

Push pushes to origin for the given branch.

func PushLocalEdits

func PushLocalEdits(ctx context.Context, cfg *config.SpecsRepoConfig, commitMsg string) (bool, error)

PushLocalEdits commits any uncommitted changes in the specs repo and pushes them. Unlike WithSpecsRepo, which resets to remote state before applying a mutation, PushLocalEdits preserves existing local edits — it is the backing implementation for `spec push`. Returns true if changes were found and pushed. On a push conflict it fetches and rebases rather than hard-resetting, preserving the committed local work.

func PushLocalEditsOpts added in v0.12.0

func PushLocalEditsOpts(ctx context.Context, cfg *config.SpecsRepoConfig, commitMsg string, opts SyncOptions) (bool, error)

PushLocalEditsOpts is PushLocalEdits with surface/trigger attribution. Unlike WithSpecsRepoOpts it preserves already-committed local work on a conflict abort — it must never hard-reset away the user's pushed-intent commits (SPEC-013 §7.1 / §7.2). It shares the identical section-aware conflict check so `spec push` can no longer silently auto-merge concurrent same-section edits (closing the previously-unguarded path).

func ReadSpecFile

func ReadSpecFile(cfg *config.SpecsRepoConfig, filename string) ([]byte, error)

ReadSpecFile reads a spec file from the specs repo. It resolves content from the fetched remote ref (`git show origin/<branch>:specs/<file>`) so it reflects upstream without touching the working tree (SPEC-013 axis 2). It falls back to the on-disk working-tree copy when the ref read fails (e.g. a brand-new local file not yet committed).

func Rebase

func Rebase(ctx context.Context, dir, ref string) error

Rebase rebases the current branch onto the given ref.

func RebaseAbort added in v0.7.0

func RebaseAbort(ctx context.Context, dir string)

RebaseAbort cancels an in-progress rebase, restoring the repo to its pre-rebase state. Safe to call even if no rebase is in progress.

func ResetHard

func ResetHard(ctx context.Context, dir, ref string) error

ResetHard resets the working tree to a specific ref.

func RestoreSpec added in v0.8.0

func RestoreSpec(ctx context.Context, cfg *config.SpecsRepoConfig, specID, archiveDir string) error

RestoreSpec moves a spec from archive/ back to specs/ and commits the change.

func RevParse added in v0.7.0

func RevParse(ctx context.Context, dir, ref string) (string, error)

RevParse returns the SHA for a ref.

func Run

func Run(ctx context.Context, dir string, args ...string) (string, error)

Run executes a git command in the given directory with a timeout. If ctx has no deadline, the defaultTimeout is applied automatically.

func SetReadSurface added in v0.12.0

func SetReadSurface(surface string)

SetReadSurface sets the surface label attributed to read-path fetches.

func SetRecorder added in v0.12.0

func SetRecorder(r Recorder)

SetRecorder injects the process-wide recorder used by the read path for freshness bookkeeping. Callers that own a store inject it once at startup. Passing nil resets to a no-op. git never imports the store directly — the recorder is the only bridge (AGENTS.md adapter-isolation rules).

func SpecBranchName

func SpecBranchName(specID string, stepNumber int, slug string) string

SpecBranchName generates a branch name for a build step.

func SpecFilePath

func SpecFilePath(cfg *config.SpecsRepoConfig, filename string) string

SpecFilePath returns the absolute path to a spec file in the specs repo.

func SpecsRepoDir

func SpecsRepoDir(cfg *config.SpecsRepoConfig) string

SpecsRepoDir returns the local path for the specs repo clone.

func SpecsRepoURL

func SpecsRepoURL(cfg *config.SpecsRepoConfig) string

SpecsRepoURL returns the clone URL for the specs repo. If a token is configured, it is embedded in the URL for passwordless auth.

func Status

func Status(ctx context.Context, dir string) (string, error)

Status returns the short status output.

func TriageFilePath

func TriageFilePath(cfg *config.SpecsRepoConfig, filename string) string

TriageFilePath returns the absolute path to a triage file.

func UserEmail

func UserEmail(ctx context.Context) string

UserEmail returns the configured git user.email.

func UserName

func UserName(ctx context.Context) string

UserName returns the configured git user.name.

func WithSpecsRepo

func WithSpecsRepo(ctx context.Context, cfg *config.SpecsRepoConfig, mutate func(repoPath string) (commitMsg string, err error)) error

WithSpecsRepo is the legacy entry point: a committing operation attributed to the CLI with no audit recorder. Prefer WithSpecsRepoOpts for surface and trigger attribution.

func WithSpecsRepoOpts added in v0.12.0

func WithSpecsRepoOpts(ctx context.Context, cfg *config.SpecsRepoConfig, opts SyncOptions, mutate func(repoPath string) (commitMsg string, err error)) error

WithSpecsRepoOpts runs a committing operation through the full lifecycle: exclusive-lock the local critical section (fetch → recover → mutate → commit), release it, then push under a separate narrower push-lock with the section-aware conflict check, randomized backoff, and queue-on-exhaustion.

The exclusive lock covers only the local work, so a shared-lock reader (notably the same-host MCP agent) waits milliseconds, never the network push (SPEC-013 §Decision 008, AC-21). The commit is durable before the lock is released, so a reader that proceeds during the push sees committed state.

Cross-teammate safety is git's atomic push + the section-aware rebase-retry, NOT the lock (which is single-host only).

Types

type AuditEvent added in v0.12.0

type AuditEvent struct {
	Op      string
	Actor   string
	Surface string
	Trigger string
	SpecID  string
	Outcome string
	Detail  string
}

AuditEvent is one sync action to record. It is surface/trigger attributed so the audit log can answer "what synced, when, by whom, via which surface".

type BranchInfo

type BranchInfo struct {
	SpecNumber string // e.g., "042"
	StepNumber string // e.g., "1"
	Slug       string // e.g., "token-bucket"
}

BranchInfo represents parsed branch name information.

func ParseSpecBranch

func ParseSpecBranch(branch string) *BranchInfo

ParseSpecBranch extracts spec and step info from a branch name. Returns nil if the branch doesn't match the spec branch pattern.

type Freshness added in v0.12.0

type Freshness struct {
	LastFetch     time.Time // zero if never recorded
	CommitsBehind int       // new upstream commits since HEAD
	QueuedPushes  int       // committed-but-unpushed operations awaiting flush
}

Freshness summarizes how current the local view of the specs repo is.

func SyncFreshness added in v0.12.0

func SyncFreshness(ctx context.Context, cfg *config.SpecsRepoConfig, rec Recorder) Freshness

SyncFreshness reports the freshness/health of the specs-repo clone for the `spec status` line (AC-9). It does not fetch — it reads the cached last-fetch timestamp and counts new upstream commits against the already-fetched ref.

type QueuedItem added in v0.12.0

type QueuedItem struct {
	ID      int64
	Branch  string
	SpecID  string
	Trigger string
	Surface string
}

QueuedItem is a committed-but-unpushed operation awaiting flush, surfaced to git's flush loop without exposing the store's row type.

type Recorder added in v0.12.0

type Recorder interface {
	// Record appends one audit event. Implementations must not fail the
	// surrounding sync operation on a recording error.
	Record(ev AuditEvent)
	// Enqueue records a committed-but-unpushed operation for later flush.
	Enqueue(repoKey, branch, commitSHA string, ev AuditEvent)
	// Pending returns flushable queued items for a repo, oldest first.
	Pending(repoKey string) []QueuedItem
	// ResolveQueued removes a successfully-flushed queued item.
	ResolveQueued(id int64)
	// MarkQueued flags a queued item (e.g. needs-resolution on conflict).
	MarkQueued(id int64, status, detail string)
	// LastFetch / SetLastFetch back the freshness TTL.
	LastFetch(repoKey string) (seconds int64, ok bool)
	SetLastFetch(repoKey string, seconds int64)
}

Recorder persists sync audit events and manages the queued-push backlog. It is injected into internal/git as an interface so git never imports internal/store directly (AGENTS.md: engines depend on interfaces; only internal/store touches SQLite).

type SyncOptions added in v0.12.0

type SyncOptions struct {
	Surface  string
	Trigger  string
	SpecID   string
	Actor    string
	Recorder Recorder
}

SyncOptions carries surface/trigger attribution and an optional recorder through a committing operation. A zero value is valid: it attributes to the CLI with a no-op recorder.

Jump to

Keyboard shortcuts

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