git

package
v1.0.0 Latest Latest
Warning

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

Go to latest
Published: Jul 12, 2026 License: MIT Imports: 10 Imported by: 0

Documentation

Overview

Package git shells out to the system git executable for ref state, reachability, patch identity, and backflow branch construction. Oiax does not implement Git object semantics itself — Git is already exceptionally good at being Git.

Security invariant: branch and ref names are passed to git as data (after `--` separators where the subcommand accepts one, and validated with `git check-ref-format`), never interpolated into a shell.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

This section is empty.

Types

type CherryPickConflict

type CherryPickConflict struct {
	// SHA is the object id of the commit that failed to apply.
	SHA string
	// Subject is the failing commit's subject line (git show -s --format=%s).
	Subject string
	// Applied is the number of commits that cherry-picked cleanly before the
	// failure (0 means the very first commit conflicted).
	Applied int
}

CherryPickConflict reports that a cherry-pick sequence stopped on a commit whose content genuinely conflicted with the target (git exit code 1). It carries enough to surface a reported divergence without any git state: the failing commit, its subject, and how many earlier commits applied cleanly before it. The worktree has been reset with `git cherry-pick --abort` by the time this error is returned. Operational failures (a killed subprocess, a cancelled context, a structural refusal such as a merge commit) are NOT CherryPickConflicts — they propagate as ordinary errors so a transient problem is not misreported as a human-actionable content conflict.

func (*CherryPickConflict) Error

func (e *CherryPickConflict) Error() string

type Commit

type Commit struct {
	SHA     string
	Subject string
}

Commit is one observed commit. It is git-local; the coordination layer maps it to the engine's own commit type.

type Runner

type Runner struct {
	// Dir is the repository working directory. Empty means the current
	// directory.
	Dir string
	// Env, when non-empty, is appended to the inherited process environment
	// for every git invocation. It exists so a cherry-pick can pin the
	// committer identity and date (making the replayed SHA a deterministic
	// function of its inputs); it is not safe for concurrent use, so set it
	// only on a Runner bound to an ephemeral worktree.
	Env []string
}

Runner executes git commands in one repository working directory.

func (*Runner) BranchExists

func (r *Runner) BranchExists(ctx context.Context, name string) (bool, error)

BranchExists reports whether a local branch ref exists. It is deliberately local-only (unlike resolveBranchRef, which also considers origin-tracking refs); it has no callers today and its strictly-local semantics are kept for the case a caller needs exactly "is this a materialized local head".

func (*Runner) CheckRefFormat

func (r *Runner) CheckRefFormat(ctx context.Context, name string) error

CheckRefFormat rejects names that are not well-formed branch names. Every configured branch name passes through here before being used in any other git invocation.

func (*Runner) CherryPick

func (r *Runner) CherryPick(ctx context.Context, shas []string) (string, error)

CherryPick replays shas onto the Runner's checked-out HEAD one at a time with `git cherry-pick -x` (each replayed commit records a "(cherry picked from commit <sha>)" provenance trailer). shas must be in application order, oldest first. It is intended to run against a Runner bound to an ephemeral Worktree, never the caller's checkout.

Each pick pins the committer identity and date to the ORIGINAL commit's, so the replayed HEAD is a deterministic function of its inputs: cherry-pick otherwise stamps the committer date to "now", giving a different HEAD SHA on every run and making the force-push that follows never a no-op (it would churn the managed branch and the open request's head on every reconcile).

`--empty=drop` skips a pick that reduces to an empty diff because its change is already present on the target (a redundant return): that is convergence, not a conflict.

On full success it returns the new HEAD object id. On the first commit whose content genuinely conflicts (git exit code 1) it runs `git cherry-pick --abort` (leaving the worktree clean) and returns a *CherryPickConflict naming that commit and the count of commits applied cleanly before it; nothing is pushed. Any other failure (exit code other than 1: a cancelled context, a killed subprocess, a structural refusal) propagates as an ordinary error rather than a *CherryPickConflict. Each sha is guarded with oidPattern before use.

func (*Runner) CommitExists

func (r *Runner) CommitExists(ctx context.Context, oid string) (bool, error)

CommitExists reports whether oid resolves to a commit object present in the local repository. It exists to distinguish a DEFINITIVE not-found — git's `rev-parse --verify --quiet` exit 1, meaning the object is simply not in the object database — from an operational failure (any other error), which propagates. A caller can then act on a genuinely absent commit (e.g. a backflow request whose encoded source head was history-rewritten out of existence) without mistaking a transient git failure for absence. oid is guarded with oidPattern, exactly as ResolveCommit guards it.

func (*Runner) DefaultBranchRef

func (r *Runner) DefaultBranchRef(ctx context.Context) (string, bool)

DefaultBranchRef resolves the repository's default branch to its remote-tracking ref (for example "origin/main"). It first reads origin/HEAD, the symbolic ref git records locally for the remote's default branch. When that is unset — a checkout that never ran `git remote set-head`, as under actions/checkout — it falls back to asking the remote directly with `git ls-remote --symref origin HEAD`, whose "ref: refs/heads/<name>\tHEAD" line names the default branch without depending on any local ref. The second return is false when both the local symref and the remote query fail (a remote-less repository), leaving the choice of fallback to the caller. It is also false when the remote query names a branch whose local tracking ref was never fetched: the resolved ref is only useful if `git show origin/<name>:<path>` can read it, and ls-remote confirms the remote's default without materializing refs/remotes/origin/<name> — so a single-branch checkout of a non-default branch would otherwise report a ref the sole consumer (config read) cannot open. A remote-tracking ref (not the local branch of the same name) is returned deliberately: it is the authoritative committed state of the default branch, independent of any stale local branch.

func (*Runner) Head

func (r *Runner) Head(ctx context.Context, name string) (string, error)

Head resolves a branch name to its commit SHA. The name is resolved to its local head or origin-tracking ref (resolveBranchRef), so a branch that actions/checkout left only as refs/remotes/origin/<name> still resolves.

func (*Runner) IsAncestor

func (r *Runner) IsAncestor(ctx context.Context, ancestor, descendant string) (bool, error)

IsAncestor reports whether ancestor is reachable from descendant (git merge-base --is-ancestor). Both arguments are object ids from prior git output and are guarded as such. Exit 0 ⇒ true, exit 1 ⇒ false, any other failure is an error.

func (*Runner) IsShallowRepository

func (r *Runner) IsShallowRepository(ctx context.Context) (bool, error)

IsShallowRepository reports whether the working repository is a shallow clone — the state actions/checkout produces by default (fetch-depth: 1), where only a truncated slice of history is present. A shallow clone has no merge base for branches whose fork point predates the fetch depth, so the patch-identity and baseline rungs of the equivalence ladder silently switch off and already-promoted content looks unpromoted. The coordinator surfaces a warning on this signal rather than emit spurious promotion requests. It reads `git rev-parse --is-shallow-repository`, which prints "true"/"false".

func (*Runner) MergeBase

func (r *Runner) MergeBase(ctx context.Context, a, b string) (string, error)

MergeBase returns the best common ancestor of two branches. It returns ("", nil) when the branches share no common ancestor (git exit code 1), mirroring BranchExists; any other failure is an error.

func (*Runner) PatchIDs

func (r *Runner) PatchIDs(ctx context.Context, base, tip string) (map[string]string, error)

PatchIDs returns the stable patch-id of every non-merge commit in the range base..tip, keyed by commit SHA. Merge commits contribute no entry. tip must be a branch name; base may be a branch name or an object id (e.g. a merge base). The patch-id is content-based, so it survives a rebase that rewrites commit SHAs without changing the diff.

func (*Runner) RemoteTrackingHead

func (r *Runner) RemoteTrackingHead(ctx context.Context, name string) (string, bool, error)

RemoteTrackingHead resolves a branch's origin-tracking ref (refs/remotes/origin/<name>) to its commit SHA, reporting ok=false when the tracking ref does not exist. Unlike resolveBranchRef it never falls back to a local head: it reports specifically the branch's last-fetched remote state. It backs the backflow push guard — before force-pushing the deterministic backflow branch, the coordinator compares the freshly replayed head against the branch's already-pushed head and skips an unchanged re-push, so a steady replay does not churn the open request. The name is validated with CheckRefFormat and only refs/remotes/origin/<validated> is constructed, preserving the no-shell and ref-format guarantees. A resolution failure that is git's clean "no such ref" (exit 1) is reported as ok=false; any other failure propagates.

func (*Runner) RequireMinVersion

func (r *Runner) RequireMinVersion(ctx context.Context) error

RequireMinVersion asserts the system git is at least the version oiax needs (see minGitMajor/minGitMinor) and returns a clear error naming both the required floor and the detected version otherwise. It is meant to run once at startup, before any git-dependent work, so an unsupported runner fails fast rather than deep inside a backflow cherry-pick.

func (*Runner) ResolveCommit

func (r *Runner) ResolveCommit(ctx context.Context, oid string) (string, error)

ResolveCommit resolves an object id (or an unambiguous abbreviation of one) to its full commit SHA. The input is guarded with oidPattern so it can only be a hex object id, never an option or a ref expression; it is used to turn the short SHA encoded in a backflow branch name back into a commit for an ancestry test. A resolution failure (unknown/ambiguous object) is returned as an error so callers can treat an unresolvable prior head conservatively.

func (*Runner) ShortSHA

func (r *Runner) ShortSHA(ctx context.Context, branch string) (string, error)

ShortSHA resolves a branch head to a fixed-length abbreviated object id (git rev-parse --short=12). Backflow branch names embed the short SHA of the downstream source head so a given head deterministically yields one branch name (the concurrency strategy); the abbreviation length is fixed so that name depends only on the head, not on local object-database state. The branch name is validated through CheckRefFormat and passed as a fully-qualified ref.

func (*Runner) ShowFile

func (r *Runner) ShowFile(ctx context.Context, ref, path string) ([]byte, error)

ShowFile returns the contents of path as committed at ref (`git show <ref>:<path>`). This is how the pinned-configuration-ref rule is implemented: configuration is read from one ref per invocation, never from the working tree of whatever triggered the run.

func (*Runner) TreeSHA

func (r *Runner) TreeSHA(ctx context.Context, branch string) (string, error)

TreeSHA returns the tree object SHA of a branch head. Equal trees on two branches mean identical content even when the commits differ (the head-tree rung, which detects a squash at the moment of merge).

func (*Runner) UniqueCommits

func (r *Runner) UniqueCommits(ctx context.Context, base, branch string) ([]Commit, error)

UniqueCommits returns commits reachable from branch but not from base (git range base..branch), newest first, with subjects. A nil slice means the range is empty — the reachability rung's "in sync" signal.

func (*Runner) Version

func (r *Runner) Version(ctx context.Context) (string, error)

Version reports the raw `git version` line ("git version 2.45.1"). RequireMinVersion parses it to assert the required floor; it is also useful for diagnostics.

func (*Runner) Worktree

func (r *Runner) Worktree(ctx context.Context, ref string) (*Runner, func(), error)

Worktree creates an ephemeral, detached working tree checked out at ref (git worktree add --detach). It exists so mutating operations — chiefly a cherry-pick sequence — never touch the caller's checked-out branch or index. It returns a Runner bound to the new tree and a cleanup func that removes the worktree registration and its directory; the caller MUST invoke cleanup on every exit path (defer it). ref accepts either a branch name (validated and fully qualified) or a bare object id, mirroring validRev, so the target head may be supplied as either.

Jump to

Keyboard shortcuts

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