git

package
v0.39.2 Latest Latest
Warning

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

Go to latest
Published: Aug 18, 2026 License: AGPL-3.0 Imports: 32 Imported by: 0

Documentation

Overview

Package git is awf's one semantic git seam: every git capability the application needs is an entrypoint here, and which backend answers an entrypoint (in-process object reads, or native Git through the package runner) is an implementation detail no consumer can observe. A handle opened with Open or OpenContaining carries the read entrypoints as methods; the pure range parser and the repository-topology entrypoints stay free functions because they precede or do without an opened repository. No backend type, sentinel, or error value crosses the seam surface in either direction.

This file holds the go-git backend: the tolerant repository open and the object, tree, and ignore reads the handle's methods are implemented with.

Index

Constants

View Source
const CommandTimeout = 2 * time.Minute

CommandTimeout is the hang-prevention ceiling a command boundary puts on the git work it starts. The seam owns the VALUE while each boundary still chooses to apply it, which is what keeps one number rather than one per binary: it was three copies before this const existed, and a ceiling that drifts between binaries is a ceiling nobody can reason about. It is generous enough that no observed-normal operation approaches it, so a command that reaches it has stalled rather than merely taken a while.

internal/testsupport keeps its own copy, forced by the same zero-internal-deps rule that forces the fixture lane's isolation duplicate.

Variables

View Source
var ErrIndexBlob = errors.New("read index blob")

ErrIndexBlob reports a stage-0 regular-file entry whose content cannot be read from the object store.

View Source
var ErrIndexUnmerged = errors.New("index contains unmerged entries")

ErrIndexUnmerged reports an index that has multiple merge stages and cannot represent one deterministic pre-commit snapshot.

View Source
var ErrNotARepository = errors.New("not a git repository")

ErrNotARepository reports a path that carries no Git repository. It is the seam's own not-a-repository identity: a consumer matches it with errors.Is and never sees the backend sentinel it translates, so which backend answered the open stays an implementation detail.

Functions

func MergeHeads added in v0.30.0

func MergeHeads(projectRoot string) ([]string, error)

MergeHeads returns every worktree-private MERGE_HEAD hash in file order. Absence means no merge is in progress and returns a nil slice.

func MergeInProgress added in v0.30.0

func MergeInProgress(projectRoot string) (bool, error)

MergeInProgress reports whether the checkout containing projectRoot has a merge in progress, detected by the presence of MERGE_HEAD.

MERGE_HEAD is worktree-private, so it lives in a linked worktree's own gitdir rather than the shared common dir, and a project root may sit below the checkout root. A naive <root>/.git lookup is wrong for both, so resolution walks up to the containing checkout and reuses worktreeGitDir, which already resolves a `.git` directory or a validated `gitdir:` pointer (ADR-0182 item 4).

Detection is by repository state rather than by the shape of the staged diff. It must stay true through a conflict resolution, where the merge is committed by a later `git commit`, and false for a hand-staged commit that merely looks branch-sized. `git merge --squash` records no MERGE_HEAD and so reports false, which is correct: it produces an ordinary commit carrying no merge provenance.

func ParseRange added in v0.18.0

func ParseRange(arg string, allowBareBase bool) (base, head string, err error)

ParseRange resolves a range argument to an explicit base and head revision. An argument containing ".." is a two-sided range; otherwise it is a base and head defaults to HEAD, which callers opt into via allowBareBase (ADR-0127 Decision 5). Git forbids ".." inside a ref name, so the discrimination is unambiguous. Rejects an empty side, a three-dot range, a multi-".." input, and a "-"-prefixed side: the first three would reach git as a bogus revision and the last as an option-like argument. Dots inside a revision (v0.10.0) are legal, since git forbids "."-leading, ".."-containing, and "-"-leading refs.

func ProjectResidentRoot added in v0.30.0

func ProjectResidentRoot(ctx context.Context, invocationPath string) string

ProjectResidentRoot maps an invoking checkout to the checkout that owns the project's resident awf state. It is the one home for that resolution: the composition point in cmd/awf and the transitional project opener both call it, so the rule that resident state belongs to the primary checkout cannot drift between them.

Any failure to resolve the topology returns invocationPath unchanged, which is the only answer that keeps a non-Git tree, a fixture tree, and an unresolvable checkout usable: resident state then lives where the command was invoked. The seam already owns both steps (ResolveControlRoots and ResidentRoot), so this adds no dependency in either direction.

Types

type Action added in v0.30.0

type Action int

Action is how a file changed in a commit.

const (
	Added Action = iota
	Modified
	Deleted
)

type BlobMode added in v0.22.0

type BlobMode uint8

BlobMode is the closed set of Git blob modes preserved by snapshots.

const (
	BlobRegular BlobMode = iota
	BlobExecutable
	BlobSymlink
)

type CommandError added in v0.30.0

type CommandError struct {
	Args     []string
	ExitCode int
	Stderr   string
	Err      error
}

CommandError reports a native Git invocation that exited non-zero. It carries the exact arguments, the exit code, and the captured stderr so a caller can match the failure with errors.As and report what Git itself said, without the caller ever touching os/exec.

func (*CommandError) Error added in v0.30.0

func (e *CommandError) Error() string

func (*CommandError) Unwrap added in v0.30.0

func (e *CommandError) Unwrap() error

type Commit added in v0.30.0

type Commit struct {
	Hash     string
	Revision string
	Subject  string
	Body     string
	Message  string
	Parents  []string
	IsMerge  bool
	Changes  []FileChange
}

Commit is the semantic view of one range commit.

type CommitPolicyError added in v0.30.0

type CommitPolicyError struct {
	Kind   CommitPolicyErrorKind
	Target string
	Err    error
}

CommitPolicyError preserves one operational Git failure for project-level translation.

func (*CommitPolicyError) Error added in v0.30.0

func (e *CommitPolicyError) Error() string

func (*CommitPolicyError) Unwrap added in v0.30.0

func (e *CommitPolicyError) Unwrap() error

type CommitPolicyErrorKind added in v0.30.0

type CommitPolicyErrorKind string

CommitPolicyErrorKind identifies the Git operation that prevented policy evaluation.

const (
	CommitPolicyBaselineError CommitPolicyErrorKind = "baseline"
	CommitPolicyRevisionError CommitPolicyErrorKind = "revision-resolution"
	CommitPolicyTagPeelError  CommitPolicyErrorKind = "tag-peel"
	CommitPolicyTrustError    CommitPolicyErrorKind = "temporary-trust-file"
	CommitPolicyVerifyError   CommitPolicyErrorKind = "signature-process"
)

type ControlRoots added in v0.30.0

type ControlRoots struct {
	InvokingRoot string
	CommonDir    string
	PrimaryRoot  string
}

ControlRoots identifies the invoking checkout, repository-wide Git common directory, and primary checkout that owns resident awf state.

func ResolveControlRoots added in v0.30.0

func ResolveControlRoots(ctx context.Context, root string) (ControlRoots, error)

ResolveControlRoots derives the checkout-local and repository-wide control roots using native Git. Native Git is used only for topology discovery; OpenRepo remains the package's read-only go-git boundary.

func (ControlRoots) ResidentRoot added in v0.30.0

func (r ControlRoots) ResidentRoot(name ResidentName) (string, error)

ResidentRoot returns one closed resident root after proving that every existing component beneath PrimaryRoot is non-symlinked and current-owned.

type FileChange added in v0.30.0

type FileChange struct {
	Path             string
	OldPath          string
	Action           Action
	Added, Deleted   int
	OldText, NewText string
}

FileChange is one file touched by a commit. OldText/NewText are populated only for markdown files, empty otherwise.

type HardSafetyError added in v0.30.0

type HardSafetyError struct {
	Category string
	Path     string
	Err      error
}

HardSafetyError marks a safety refusal that cannot be overridden by force.

func (*HardSafetyError) Error added in v0.30.0

func (e *HardSafetyError) Error() string

func (*HardSafetyError) Forceable added in v0.30.0

func (*HardSafetyError) Forceable() bool

Forceable reports whether the refusal may be overridden.

func (*HardSafetyError) Unwrap added in v0.30.0

func (e *HardSafetyError) Unwrap() error

type IndexBlob added in v0.18.0

type IndexBlob struct {
	Path  string
	Bytes []byte
	Mode  BlobMode
}

IndexBlob is one file's exact bytes and mode from a stage-0 index or a resolved commit tree. Symlink bytes are the inert link target.

type Repo added in v0.30.0

type Repo struct {
	// contains filtered or unexported fields
}

Repo is the seam's handle on one opened repository. It is constructed once, at a composition point that owns a validated root, and every read entrypoint hangs off it as a method taking the operation's context: no entrypoint re-opens the repository, and no backend type crosses the handle's surface.

prefix is the repository-relative slash-separated path of root, empty when root is the repository root itself. It is what lets an adopted project nested inside a containing monorepo read only its own paths.

func Open added in v0.30.0

func Open(root string) (*Repo, error)

Open opens the repository at root exactly, tolerating the layouts awf must read (a linked worktree's `gitdir:` pointer, a submodule, a stray `extensions.worktreeConfig`), and validates root once so every later operation reuses that validation. A path carrying no repository at all is reported as ErrNotARepository; a present but malformed checkout keeps its own error, because the two must never be confused by a caller deciding whether a checkout exists.

func OpenContaining added in v0.30.0

func OpenContaining(start string) (*Repo, string, error)

OpenContaining opens the repository containing start and reports start's repository-relative slash-separated prefix, empty when start is itself the repository root. The returned handle stays anchored at start, so its reads are scoped to that subtree exactly as a command invoked there expects.

func (*Repo) Ancestor added in v0.30.0

func (r *Repo) Ancestor(ctx context.Context, older, newer string) (bool, error)

Ancestor reports whether older is an ancestor of newer. Unrelated histories answer false rather than failing, which is what makes this usable as the merged-ness test before a destructive operation.

func (*Repo) BranchDelete added in v0.30.0

func (r *Repo) BranchDelete(ctx context.Context, name string) error

BranchDelete deletes the local branch name, refusing when it is unmerged. The safe form is the only one offered: a caller that wants to discard unmerged work must do it explicitly with native Git rather than through awf.

func (*Repo) BranchExists added in v0.30.0

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

BranchExists reports whether the local branch name exists. Absence is an answer, not a failure.

func (*Repo) Branches added in v0.30.0

func (r *Repo) Branches(ctx context.Context) (map[string]bool, error)

Branches returns the repository's local branch short names.

func (*Repo) ChangeCounts added in v0.30.0

func (r *Repo) ChangeCounts(ctx context.Context) (tracked, untracked int, err error)

ChangeCounts returns native Git's tracked-change and nonignored untracked-file counts for the handle's worktree. Native porcelain is the cleanliness oracle because go-git's status traversal can re-include a nested .gitignore below an ignored parent directory. It runs through the package runner, so it inherits the isolated environment and reports a failure with Git's own stderr; the isolation's stripped user and system config is restored for ignore purposes alone by replaying the effective core.excludesFile (see excludesFileArgs), so the oracle keeps real Git's ignore universe.

func (*Repo) ChangedPaths added in v0.30.0

func (r *Repo) ChangedPaths(ctx context.Context, staged bool, rangeSpec string) ([]string, error)

ChangedPaths returns the sorted, unique repo-relative paths changed either in the staged index (staged) or between the two revisions of rangeSpec ("a..b"). staged takes precedence; with neither selector the caller should not call this. A malformed range or an unresolvable revision is a clear error. It reads the repository only.

func (*Repo) CommitBlobs added in v0.30.0

func (r *Repo) CommitBlobs(ctx context.Context, rev string) ([]IndexBlob, error)

CommitBlobs returns the sorted regular and executable blobs of the tree that rev resolves to. Symlinks and gitlinks carry no regular-file content to scan and are skipped. It reads the repository only.

func (*Repo) CommitBlobsAt added in v0.30.0

func (r *Repo) CommitBlobsAt(ctx context.Context, rev string, paths []string) ([]IndexBlob, error)

CommitBlobsAt returns the sorted exact blobs selected by canonical, project-relative paths in rev. Every requested path must name a regular, executable, or symlink entry in the handle's project subtree.

func (*Repo) CommitEntries added in v0.30.0

func (r *Repo) CommitEntries(ctx context.Context, rev string) ([]TreeEntry, error)

CommitEntries returns the sorted metadata for every regular, executable, or symlink entry in rev's tree scoped to the handle's project root. It does not read blob objects; gitlinks and unsupported entries are omitted.

func (*Repo) CommitFacts added in v0.30.0

func (r *Repo) CommitFacts(ctx context.Context, id string) (commitpolicy.Commit, error)

CommitFacts loads immutable author and committer facts for one commit object.

func (*Repo) CommitMessage added in v0.30.0

func (r *Repo) CommitMessage(ctx context.Context, rev string) (string, error)

CommitMessage returns the full message recorded by rev.

func (*Repo) CommitParents added in v0.30.0

func (r *Repo) CommitParents(ctx context.Context, rev string) ([]string, error)

CommitParents returns the full parent hashes of rev in recorded order.

func (*Repo) CommitsAfter added in v0.30.0

func (r *Repo) CommitsAfter(ctx context.Context, baseline string, targets []string) ([]commitpolicy.Commit, error)

CommitsAfter expands explicit revision or range targets to unique commits after baseline.

func (*Repo) CurrentBranch added in v0.30.0

func (r *Repo) CurrentBranch(ctx context.Context) (string, error)

CurrentBranch returns the short name of the branch HEAD points at, or the empty string when HEAD is detached. A detached HEAD is a state of the repository, not a fault, so it is reported rather than raised.

func (*Repo) FileText added in v0.30.0

func (r *Repo) FileText(ctx context.Context, rev, path string) (text string, found bool, err error)

FileText reads path from rev. path is relative to the handle root. A missing path returns found false; revision and object failures remain errors.

func (*Repo) FirstParentChangedPaths added in v0.30.0

func (r *Repo) FirstParentChangedPaths(ctx context.Context, rev string) ([]string, error)

FirstParentChangedPaths returns sorted, unique paths changed by rev relative to its first parent. Roots compare against the empty tree and merges compare only against their first parent. Paths are rerooted to the handle root.

func (*Repo) FullOID added in v0.30.0

func (r *Repo) FullOID(ctx context.Context, rev string) (string, string, error)

FullOID resolves rev to its complete object ID and Git object type.

func (*Repo) GitPath added in v0.30.0

func (r *Repo) GitPath(ctx context.Context, name string) (string, error)

GitPath resolves a repository control file name (MERGE_HEAD, rebase-merge, and kin) to an absolute path. Git answers relative to the checkout for a primary worktree and absolutely for a linked one, and the worktree-private files live in the linked checkout's own Git directory rather than the common one, so resolution belongs to Git and the absolute form belongs here.

func (*Repo) HeadExists added in v0.30.0

func (r *Repo) HeadExists(ctx context.Context) (bool, error)

HeadExists reports whether the repository has a born HEAD (at least one commit). A fresh repository whose immediate symbolic HEAD target is absent reports false without error. Missing refs deeper in a symbolic chain and corrupt or cyclic chains are errors. It reads the repository only.

func (*Repo) HeadHash added in v0.30.0

func (r *Repo) HeadHash(ctx context.Context) (string, error)

HeadHash resolves the current HEAD commit hash without requiring a clean working tree. The final current-state upgrade runs in an integration worktree that carries the applied but uncommitted attestation patches, so it compares HEAD identity against the sealed PreparedHead without a cleanliness check.

func (*Repo) IndexBlobs added in v0.30.0

func (r *Repo) IndexBlobs(ctx context.Context) ([]IndexBlob, error)

IndexBlobs returns sorted stage-0 ordinary and executable blobs from the index. Symlinks and gitlinks have no regular-file content to scan and are ignored. An unmerged or unreadable regular entry makes the snapshot unsafe.

func (*Repo) IndexPaths added in v0.38.0

func (r *Repo) IndexPaths(ctx context.Context) ([]string, error)

IndexPaths returns sorted, unique stage paths from index metadata, rerooted to the handle's project subtree. It deliberately neither consults ignore rules nor reads blob objects: index membership answers tracking even when a path is now ignored or its blob cannot be read. Repeated conflict stages collapse to their one path because tracking is path membership, not content.

func (*Repo) IsNested added in v0.38.0

func (r *Repo) IsNested() bool

IsNested reports whether the handle is anchored below its containing repository root. Consumers use this composition fact to preserve output ownership boundaries without reopening the repository.

func (*Repo) MergeBase added in v0.30.0

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

MergeBase returns the merge-base revision for a and b.

func (*Repo) MergeFastForward added in v0.30.0

func (r *Repo) MergeFastForward(ctx context.Context, rev string) error

MergeFastForward advances HEAD to rev, refusing anything that would create a commit. It is the integration path for a branch that is strictly ahead.

func (*Repo) MergeNoCommit added in v0.30.0

func (r *Repo) MergeNoCommit(ctx context.Context, rev string) error

MergeNoCommit merges rev into HEAD and stops before committing, leaving the result (or the conflict) visible in the working tree. Divergent integration deliberately hands the outcome back to a person instead of committing it.

func (*Repo) PeelCommit added in v0.30.0

func (r *Repo) PeelCommit(ctx context.Context, rev string) (string, string, error)

PeelCommit recursively peels annotated tags and returns a commit or terminal target type.

func (*Repo) RangeBlobs added in v0.30.0

func (r *Repo) RangeBlobs(ctx context.Context, rev string) (before, after []IndexBlob, err error)

RangeBlobs returns the before/after regular-blob sets for the transition into the commit rev resolves to: after is that commit's tree, before is its first-parent tree, or nil for a root commit. Merges follow the first parent only, so an ADR status change committed on a branch and merged is still observed at the merge. It reads the repository only.

func (*Repo) RangeChangedPaths added in v0.30.0

func (r *Repo) RangeChangedPaths(ctx context.Context, base, head string) ([]string, error)

RangeChangedPaths returns paths changed between base and head, rerooted to the handle root, using native Git's --name-only semantics.

func (*Repo) RangeDiffText added in v0.30.0

func (r *Repo) RangeDiffText(ctx context.Context, base, head string) (string, error)

RangeDiffText returns unified diff text for base through head. The options pin the b/ destination prefix consumed by repoaudit's parser.

func (*Repo) ResolveCommit added in v0.30.0

func (r *Repo) ResolveCommit(ctx context.Context, revision string) (string, error)

ResolveCommit resolves revision to the full object ID of the commit it names, failing when revision names no commit. The response is length-checked because a caller compares the returned identity against another: a truncated or abbreviated answer would compare unequal against a full one and be read as history having moved.

func (*Repo) Root added in v0.30.0

func (r *Repo) Root() string

Root is the path the handle is anchored at: the directory whose subtree the handle's reads are scoped to, which a consumer joining repository-relative paths back onto disk needs.

func (*Repo) ValidateRefName added in v0.30.0

func (r *Repo) ValidateRefName(ctx context.Context, name string) (bool, error)

ValidateRefName reports whether name is well formed as a branch name, which is the question every caller here asks. It validates the full refs/heads/ form rather than passing --branch, and the difference is not cosmetic: the bare name form rejects a one-level name like "main" that is a perfectly valid branch, while --branch answers an invalid name with exit 128 instead of the exit 1 that means "no", so a malformed name would surface as a fault rather than a negative. Qualifying the name asks the branch question and keeps the exit-0/1 contract the probe helper depends on.

func (*Repo) VerifySSH added in v0.30.0

func (r *Repo) VerifySSH(ctx context.Context, id string, signers []commitpolicy.Signer) (verdict commitpolicy.SignatureVerdict, retErr error)

VerifySSH verifies one commit through an operation-local allowed-signers file.

func (*Repo) WalkRangeCommits added in v0.31.0

func (r *Repo) WalkRangeCommits(ctx context.Context, base, head string, visit func(Commit) error) (int, error)

WalkRangeCommits visits commits reachable from head but not from base. The range is always caller-supplied. It returns the number successfully visited; unrelated histories are errors.

func (*Repo) WorkingPaths added in v0.30.0

func (r *Repo) WorkingPaths(ctx context.Context) ([]string, error)

WorkingPaths returns tracked HEAD paths that still exist plus nonignored untracked paths, rerooted to the handle's root. A specifically unborn HEAD supplies an empty committed baseline; every other repository, reference, or object error still fails. The root may be an adopted project nested inside a containing monorepo; paths outside that project are excluded. Deleted and nested-repository files are excluded by go-git's worktree status semantics; ignored files are excluded by those semantics plus the injected global and system excludes (globalExcludePatterns).

func (*Repo) WorktreeAdd added in v0.30.0

func (r *Repo) WorktreeAdd(ctx context.Context, path, branch, base string) error

WorktreeAdd registers a new checkout at path on a newly created branch starting at base. It is the one entrypoint that creates a branch: the creation is inseparable from the registration Git performs with it.

func (*Repo) WorktreeList added in v0.30.0

func (r *Repo) WorktreeList(ctx context.Context) ([]WorktreeRegistration, error)

WorktreeList returns the repository's registrations as seen from this handle.

func (*Repo) WorktreePrune added in v0.30.0

func (r *Repo) WorktreePrune(ctx context.Context) error

WorktreePrune drops registrations whose checkout is already gone. The immediate expiry is deliberate: a caller prunes only after proving the specific path absent, so honouring a grace period would leave the proven registration behind. Git prunes an absent checkout without the flag in the shapes the contract suite builds, so the flag is a guarantee against Git's default grace period rather than something a test here distinguishes.

func (*Repo) WorktreeRemove added in v0.30.0

func (r *Repo) WorktreeRemove(ctx context.Context, path string) error

WorktreeRemove retires the registered checkout at path.

type ResidentName added in v0.30.0

type ResidentName string

ResidentName is the closed set of repository-wide awf resident roots.

const (
	ResidentEfforts       ResidentName = "efforts"
	ResidentWorktrees     ResidentName = "worktrees"
	ResidentEffortArchive ResidentName = "effort-archive"
)

type TreeEntry added in v0.30.0

type TreeEntry struct {
	Path string
	Mode BlobMode
}

TreeEntry is one committed project's path and preserved Git blob mode. It carries tree metadata only, never blob content.

type WorktreeRegistration added in v0.30.0

type WorktreeRegistration struct {
	Path     string
	HEAD     string
	Branch   string
	Detached bool
	Bare     bool
	Prunable bool
}

WorktreeRegistration is one native-Git worktree registration.

func ListWorktreeRegistrations added in v0.30.0

func ListWorktreeRegistrations(ctx context.Context, invokingRoot string) ([]WorktreeRegistration, error)

ListWorktreeRegistrations returns the repository's native-Git registrations without consulting or scanning filesystem ancestors.

Jump to

Keyboard shortcuts

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