Documentation
¶
Overview ¶
Package gitcli is the only Git subprocess and credential boundary in the engine.
Every command is built as an explicit argument vector and executed with exec.CommandContext. No command is ever composed through sh, bash, or -c, so there is no string that a ref name, path, or upstream commit message could escape into. Credentials never appear in an argument vector or a remote URL. They are supplied through the controlled process environment and seeded into a redactor before the first subprocess starts.
Index ¶
- Constants
- Variables
- func ExitCodeOf(err error) int
- func Identity(name, email string) string
- func ValidateBranchName(name string) error
- func ValidateFetchRefspec(spec string) error
- func ValidatePushRefspec(spec string) error
- func ValidatePushRemote(remote string) error
- func ValidateRawDate(date string) error
- func ValidateRefName(name string) error
- func ValidateRemote(remote string) error
- func ValidateSourceRemote(remote string) error
- type ApplyOptions
- type BlobOptions
- type Commit
- type CommitLogOptions
- type CommitOptions
- type CommitTreeOptions
- type ConfigEntry
- type DAGCommit
- type DiffOptions
- type ExecError
- type FileMode
- type GitHubTokenCredential
- type ObjectFormat
- type ObjectInfo
- type ObjectInfoOptions
- type Options
- type PartialCloneStatus
- type PushUpdate
- type Redactor
- type Ref
- type RevListOptions
- type Runner
- func (r *Runner) AddPaths(ctx context.Context, paths ...string) error
- func (r *Runner) AddWorktree(ctx context.Context, opts WorktreeOptions) error
- func (r *Runner) Anonymous() *Runner
- func (r *Runner) ApplyPatch(ctx context.Context, opts ApplyOptions) error
- func (r *Runner) ApplyThreeWayIndex(ctx context.Context, diff []byte) error
- func (r *Runner) Binary() string
- func (r *Runner) ChangedPaths(ctx context.Context, from, to string) ([]string, error)
- func (r *Runner) CheckoutDetached(ctx context.Context, revision string) error
- func (r *Runner) Clean(ctx context.Context) error
- func (r *Runner) CloneSource(ctx context.Context, opts SourceCloneOptions) error
- func (r *Runner) Commit(ctx context.Context, opts CommitOptions) error
- func (r *Runner) CommitGraph(ctx context.Context, opts RevListOptions) ([]DAGCommit, error)
- func (r *Runner) CommitInfo(ctx context.Context, revision string) (Commit, error)
- func (r *Runner) CommitLog(ctx context.Context, opts CommitLogOptions) ([]Commit, error)
- func (r *Runner) CommitParents(ctx context.Context, revision string) ([]string, error)
- func (r *Runner) ConfigEffective(ctx context.Context, key string) (value string, found bool, err error)
- func (r *Runner) ConfigKeys(ctx context.Context) ([]ConfigEntry, error)
- func (r *Runner) ConfigLocal(ctx context.Context, key string) (value string, found bool, err error)
- func (r *Runner) CreateRef(ctx context.Context, name, revision string) error
- func (r *Runner) CreateTag(ctx context.Context, opts TagOptions) error
- func (r *Runner) Diff(ctx context.Context, opts DiffOptions) (string, error)
- func (r *Runner) DiffWorkTree(ctx context.Context) (string, error)
- func (r *Runner) Dir() string
- func (r *Runner) DisableSparseCheckout(ctx context.Context) error
- func (r *Runner) EmptyTree(ctx context.Context) (string, error)
- func (r *Runner) FetchExact(ctx context.Context, remote, remoteRef, expectedOID string, hexLength int) error
- func (r *Runner) FetchSource(ctx context.Context, opts SourceFetchOptions) error
- func (r *Runner) HasHead(ctx context.Context) (bool, error)
- func (r *Runner) HasRef(ctx context.Context, name string) (bool, error)
- func (r *Runner) InitRepository(ctx context.Context, initialBranch string) error
- func (r *Runner) InitRepositoryWithFormat(ctx context.Context, initialBranch string, format ObjectFormat) error
- func (r *Runner) IsAncestor(ctx context.Context, ancestor, descendant string) (bool, error)
- func (r *Runner) IsAnonymous() bool
- func (r *Runner) IsBareRepository(ctx context.Context) (bool, error)
- func (r *Runner) IsBareRepositoryAt(ctx context.Context, dir string) (bool, error)
- func (r *Runner) IsNoLazyFetch() bool
- func (r *Runner) IsRepository(ctx context.Context) (bool, error)
- func (r *Runner) ListRefs(ctx context.Context, patterns ...string) ([]Ref, error)
- func (r *Runner) ListTree(ctx context.Context, revision string) ([]TreeEntry, error)
- func (r *Runner) ListWorktrees(ctx context.Context) ([]Worktree, error)
- func (r *Runner) MergeBase(ctx context.Context, a, b string) (string, error)
- func (r *Runner) MergeBases(ctx context.Context, a, b string) ([]string, error)
- func (r *Runner) MergeBasesOctopus(ctx context.Context, revisions ...string) ([]string, error)
- func (r *Runner) ObjectFormat(ctx context.Context) (ObjectFormat, error)
- func (r *Runner) ObjectInfoBatch(ctx context.Context, opts ObjectInfoOptions) ([]ObjectInfo, error)
- func (r *Runner) ParseTrailers(ctx context.Context, message string) ([]Trailer, error)
- func (r *Runner) PartialCloneStatusOf(ctx context.Context, revision string) (PartialCloneStatus, error)
- func (r *Runner) PruneWorktrees(ctx context.Context) error
- func (r *Runner) Push(ctx context.Context, remote string, refspecs ...string) error
- func (r *Runner) PushAtomic(ctx context.Context, remote string, updates []PushUpdate) error
- func (r *Runner) ReadBlob(ctx context.Context, opts BlobOptions) ([]byte, error)
- func (r *Runner) Redactor() *Redactor
- func (r *Runner) RemoteRefs(ctx context.Context, remote string, hexLength int) ([]Ref, error)
- func (r *Runner) RemoveWorktree(ctx context.Context, path string) error
- func (r *Runner) RepositoryRoot(ctx context.Context) (string, error)
- func (r *Runner) RequireMinimumVersion(ctx context.Context) error
- func (r *Runner) ResetHard(ctx context.Context, revision string) error
- func (r *Runner) ResolveCommit(ctx context.Context, revision string) (string, error)
- func (r *Runner) ResolveTree(ctx context.Context, revision string) (string, error)
- func (r *Runner) SetConfigLocal(ctx context.Context, key, value string) error
- func (r *Runner) SetSparseCheckout(ctx context.Context, opts SparseOptions) error
- func (r *Runner) SparseCheckoutPatterns(ctx context.Context) ([]string, error)
- func (r *Runner) Status(ctx context.Context) ([]StatusEntry, error)
- func (r *Runner) StatusPorcelainZ(ctx context.Context) (string, error)
- func (r *Runner) TagInfo(ctx context.Context, name string) (Tag, error)
- func (r *Runner) TagObjectByOID(ctx context.Context, oid string) (TagObject, error)
- func (r *Runner) UnsetConfigLocal(ctx context.Context, key string) error
- func (r *Runner) UpdateRef(ctx context.Context, name, revision, expected string) error
- func (r *Runner) Version(ctx context.Context) (Version, error)
- func (r *Runner) WithDir(dir string) (*Runner, error)
- func (r *Runner) WithNoLazyFetch() *Runner
- func (r *Runner) WriteBlob(ctx context.Context, content []byte) (string, error)
- func (r *Runner) WriteCommit(ctx context.Context, opts CommitTreeOptions) (string, error)
- func (r *Runner) WriteTagObject(ctx context.Context, opts TagObjectOptions) (string, error)
- func (r *Runner) WriteTree(ctx context.Context, entries []TreeEntry) (tree string, err error)
- type Signature
- type SourceCloneOptions
- type SourceFetchOptions
- type SparseOptions
- type StatusEntry
- type Tag
- type TagObject
- type TagObjectOptions
- type TagOptions
- type Trailer
- type TreeEntry
- type Version
- type Worktree
- type WorktreeOptions
Constants ¶
const BloblessFilter = "blob:none"
BloblessFilter is the partial clone filter the source cache uses. Commits and trees arrive eagerly because graph traversal needs them, while blobs are fetched only for the commits that are actually materialized.
const DefaultBinary = "git"
DefaultBinary is the Git executable looked up on PATH when none is given.
const DefaultBlobLimit = 64 << 20
DefaultBlobLimit bounds a read that names no limit of its own. Upstream content is untrusted input, so there is no unbounded form of this call: a caller that says nothing gets a ceiling rather than the repository's largest object in memory.
const DefaultOutputLimit = 512 << 20
DefaultOutputLimit bounds one stream of one command. An upstream repository decides how much a git command prints, so an unbounded capture would let it decide how much memory the engine spends. It is generous enough for a full history walk over a repository the size of Kubernetes and small enough that a runaway command fails instead of exhausting memory.
const Placeholder = "[redacted]"
Placeholder replaces every redacted value in captured output.
const PublishHost = "github.com"
PublishHost is the only host the engine may push to over the network.
const SourceHost = "github.com"
SourceHost is the only host the engine may fetch upstream history from over the network. Source acquisition is anonymous, so the allowlist is not protecting a credential; it stops a profile from pointing the transformation at an attacker's copy of Kubernetes.
Variables ¶
var ( // ErrObjectNotFound reports a revision or path that resolves to no object. // In a partial clone this also covers an object the repository legitimately // does not hold yet, which is why the lazy fetch decision is explicit. ErrObjectNotFound = errors.New("object does not exist") // ErrObjectAmbiguous reports a short name matching more than one object. ErrObjectAmbiguous = errors.New("object name is ambiguous") // ErrNotABlob reports a resolved object that is a tree, commit, or tag. A // caller asking for file content must not receive a tree listing instead. ErrNotABlob = errors.New("object is not a blob") // ErrBlobTooLarge reports a blob past the caller's read limit. ErrBlobTooLarge = errors.New("blob is larger than the read limit") )
Object read sentinels. Each names a verdict a caller has to act on rather than a command that failed, so they are distinguishable instead of being folded into one opaque error.
var ( // ErrTagNotFound reports a tag name that no ref resolves to. It is distinct // from ErrObjectNotFound because a missing tag is a fact about the ref // namespace, which a publisher checks before it creates one, while a missing // object is a fact about the object store. ErrTagNotFound = errors.New("tag does not exist") // ErrDuplicateTreeEntry reports two entries claiming one path. Git would // keep whichever the index happened to apply last, so the tree would be // written from an input the caller never meant to describe. ErrDuplicateTreeEntry = errors.New("tree path is claimed by more than one entry") // ErrTreePathConflict reports a path used as both a file and a directory. // // Git does not refuse this. update-index accepts both entries and write-tree // resolves the clash by dropping one, reporting success and an object name, // so a generated module carrying such a pair would publish a tree quietly // missing a file. Nothing downstream would notice: the tree is well formed, // it is simply not the one that was asked for. ErrTreePathConflict = errors.New("tree path is used as both a file and a directory") // ErrUnsupportedFileMode reports a mode a generated tree cannot record. ErrUnsupportedFileMode = errors.New("file mode is not one a generated tree records") // ErrReservedTreePath reports a path holding a component that names git's // own directory. // // Git neither records it nor refuses it. update-index prints "Ignoring path" // to standard error and exits zero, and write-tree then reports a tree that // is simply missing the entry, so this is the ErrTreePathConflict failure // again by another route. ErrReservedTreePath = errors.New("tree path names git's own directory") // ErrTreeEntryDropped reports that update-index declined an entry without // failing. It is the net under the named rules above: which paths git will // record depends on configuration this package does not own, so the only // durable evidence that every entry was staged is that git said nothing. ErrTreeEntryDropped = errors.New("git declined to stage a tree entry") )
Object write sentinels. Each names a verdict the caller has to act on rather than a command that happened to fail.
var ( // ErrForceRefspec reports a refspec that would allow a non fast forward // update. The engine publishes append only history, so there is no API that // can force a ref backwards. ErrForceRefspec = errors.New("refspec must not force a non fast forward update") // ErrDeleteRefspec reports a refspec that would delete a ref. ErrDeleteRefspec = errors.New("refspec must not delete a ref") // ErrFlagLikeArgument reports a value that git would parse as an option. ErrFlagLikeArgument = errors.New("value must not start with a dash") )
Ref validation sentinels.
var ErrAmbiguousMergeBase = errors.New("revisions have more than one best common ancestor")
ErrAmbiguousMergeBase reports revisions with more than one best common ancestor, as a criss-cross merge produces. Git picks one and says nothing, so the ambiguity is surfaced here instead: a caller that anchors published history to a merge base must not have that anchor depend on traversal order.
var ErrCredentialedRunner = errors.New("source commands require an anonymous runner")
ErrCredentialedRunner reports an attempt to reach the source host with a runner that still carries caller supplied environment entries.
var ErrFilterIgnored = errors.New("server ignored the object filter and sent a complete history")
ErrFilterIgnored reports a transfer whose object filter the server did not honour, which yields a complete history where a blobless one was asked for.
var ErrLazyFetchDisabled = errors.New("this runner refuses promisor fetches")
ErrLazyFetchDisabled reports a request for a promisor fetch on a runner that was pinned against one by WithNoLazyFetch.
var ErrNoMergeBase = errors.New("revisions have no common ancestor")
ErrNoMergeBase reports revisions that share no common ancestor. Git signals this with exit status 1, which is a verdict rather than a failure, so it is reported as a distinguishable error instead of an empty result.
var RepositoryScopes = []string{"local", "worktree"}
RepositoryScopes are the configuration scopes a repository itself owns. Global and system configuration are neutralised for every subprocess, so these two are the only ones an attacker who can write to a repository directory controls, and the second is invisible to a --local query.
Functions ¶
func ExitCodeOf ¶
ExitCodeOf reports the process exit code carried by err, or zero.
func ValidateBranchName ¶
ValidateBranchName checks a short branch name such as master or release-1.36.
func ValidateFetchRefspec ¶
ValidateFetchRefspec checks one fetch refspec. Both ends must be explicit fully qualified refs: wildcards are rejected so a run can only ever update the refs its profile named, and a leading plus is rejected so that an upstream history rewrite fails the fetch instead of silently replacing the history the engine has already published from.
func ValidatePushRefspec ¶
ValidatePushRefspec checks one push refspec. Leading plus signs, delete refspecs, and option like values are rejected because the publisher may only fast forward refs it already agreed to move.
func ValidatePushRemote ¶
ValidatePushRemote checks a push target. A push may carry credentials, so the target must be explicit: named remotes are rejected because their URL lives in configuration, and an https target must be the one host the engine publishes to. Absolute paths and file URLs remain available for local verification.
func ValidateRawDate ¶
ValidateRawDate checks git's raw date form, "<seconds> <±hhmm>".
It is exported because it is the one rule for what a replayed date may be, and a second copy of it elsewhere is how the engine ends up with two answers for the same upstream commit. An object body records the date as git stores it, so this is the one place a signature cannot accept the friendlier formats git's date parser understands.
A negative count of seconds is accepted. Dates before 1970 are rare but they are real: histories imported from CVS and Subversion carry them, git stores them, and refusing one here would make the engine unable to replay a commit that upstream published years ago.
func ValidateRefName ¶
ValidateRefName checks a fully qualified ref name against the rules that git check-ref-format enforces.
func ValidateRemote ¶
ValidateRemote checks a fetch or local push target. Credentials may never travel in a remote URL, so any embedded user information is rejected.
func ValidateSourceRemote ¶
ValidateSourceRemote checks an anonymous source target. A network target must be an https URL on the one allowlisted host and may never embed user information. Absolute paths and file URLs stay available for local mirrors and tests. A named remote is rejected because its real target would live in repository configuration instead of in the reviewed profile.
Types ¶
type ApplyOptions ¶
type ApplyOptions struct {
// Patch is the unified diff to apply. It travels through standard input so
// no temporary file has to be created and cleaned up.
Patch []byte
// ThreeWay falls back to a three way merge when a context line does not
// match, which is what lets a patch survive unrelated upstream drift. A
// conflict leaves markers in the work tree and fails the command, so the
// caller can capture them for the report.
ThreeWay bool
// Index updates the index as well as the work tree.
Index bool
// Check reports whether the patch would apply without touching anything.
Check bool
// Strip is the number of leading path components to remove. Zero means git's
// default of one, which matches diffs produced against a repository root.
Strip int
}
ApplyOptions describes one patch application.
type BlobOptions ¶
type BlobOptions struct {
// Revision names the snapshot to read from, such as a commit or a tree.
// With an empty Path it names the blob object itself.
Revision string
// Path is the repository relative path within Revision, separated by forward
// slashes. It is not a pathspec: no magic, no wildcards, and no traversal.
Path string
// Limit is the largest blob to return in bytes. Zero means DefaultBlobLimit
// and a negative value is rejected.
//
// It bounds the result in memory, not the network. Under AllowLazyFetch git
// downloads the object before it can report its size, so an oversized blob is
// refused after it has already reached the object store. A read that must not
// pull bytes over the network has to ask ObjectInfoBatch without lazy fetch
// first and decide from the size it reports.
Limit int64
// AllowLazyFetch permits a partial clone to download the blob. Leaving it
// false answers from the local object store only, so a missing blob is
// reported instead of silently reaching the network.
//
// Permitting it is permitting a fetch: the runner must be anonymous, and the
// gate that guards an explicit transfer is applied here too.
AllowLazyFetch bool
}
BlobOptions selects one blob to read.
type Commit ¶
type Commit struct {
SHA string
// Parents are the parent object names in git's order, so Parents[0] is the
// first parent and defines the mainline. A root commit has none.
Parents []string
AuthorName string
AuthorEmail string
// AuthorDate is Git's strict ISO 8601 rendering for display and comparison.
AuthorDate string
// AuthorDateRaw is Git's original "<seconds> <offset>" form for replay.
AuthorDateRaw string
CommitterName string
CommitterEmail string
// CommitterDate is Git's strict ISO 8601 rendering.
CommitterDate string
// CommitterDateRaw is Git's original raw form for deterministic replay.
CommitterDateRaw string
SignatureStatus string
SignerKey string
Signer string
Subject string
// RawMessage is the complete commit message including the subject line, so
// replaying it must not append the subject again.
RawMessage string
Trailers []Trailer
}
Commit is the metadata the engine needs about one commit.
func (Commit) AuthorIdentity ¶
AuthorIdentity renders the commit author identity.
func (Commit) CommitterIdentity ¶
CommitterIdentity renders the commit committer identity.
func (Commit) TrailerValues ¶
TrailerValues reports every value recorded under key.
type CommitLogOptions ¶
type CommitLogOptions struct {
// Include lists the revisions to walk from, such as branch tips.
Include []string
// Exclude lists the revisions whose ancestors are left out, which is how a
// walk is bounded below by an already mapped commit.
Exclude []string
// FirstParent follows only the first parent of every merge, which yields the
// mainline of a branch.
FirstParent bool
// MaxCount bounds the number of commits returned. Zero means no bound.
MaxCount int
// Signatures fills SignatureStatus, SignerKey, and Signer. They are empty
// without it, because verifying every commit in a walk is neither free nor
// reproducible across machines. Ask for one commit's signature with
// CommitInfo instead unless the whole walk genuinely needs it.
Signatures bool
}
CommitLogOptions selects the commits one batched metadata read covers.
type CommitOptions ¶
type CommitOptions struct {
Message string
Author Signature
Committer Signature
AllowEmpty bool
// Sign requests a signed commit. Generated replay commits are never signed,
// so this stays false everywhere except fixtures and bootstrap commits that
// must carry a real signature.
Sign bool
}
CommitOptions describes one commit created through the Git command line.
type CommitTreeOptions ¶
type CommitTreeOptions struct {
// Tree is the tree object the commit records.
Tree string
// Parents are the parent commits in order. The first parent defines the
// mainline, and more than one parent produces a merge.
Parents []string
// Message is the complete commit message, preserved verbatim.
Message string
// Author is the identity the change is attributed to.
Author Signature
// Committer is the identity that recorded it.
Committer Signature
}
CommitTreeOptions describes one commit object written directly from a tree.
type ConfigEntry ¶
type ConfigEntry struct {
// Scope is git's own name for the file the key came from, such as local or
// worktree.
Scope string
// Key is the fully qualified configuration key, lower cased by git except
// for a subsection name, which keeps its case.
Key string
}
ConfigEntry is one configuration key and the scope it was read from.
type DAGCommit ¶
type DAGCommit struct {
// SHA is the commit object name.
SHA string
// Parents are the parent object names in git's order, so Parents[0] is the
// first parent and defines the mainline.
Parents []string
}
DAGCommit is one node of a commit graph: an object name and the parents that define its edges. Nothing else is read, because the traversal that selects commits must not depend on message or tree contents.
type DiffOptions ¶
type DiffOptions struct {
// Revision compares against a commit instead of the index. Empty compares
// the work tree with the index, which is what a failed patch leaves behind.
Revision string
// Staged compares the index instead of the work tree.
Staged bool
// Paths limits the diff to exact repository relative paths.
Paths []string
}
DiffOptions selects the comparison a diff renders.
type ExecError ¶
ExecError reports a Git command that exited non-zero or could not run. Every field is redacted.
type FileMode ¶
type FileMode string
FileMode is the mode a tree records for one blob.
const ( // ModeRegular is a non executable file. ModeRegular FileMode = "100644" // ModeExecutable is an executable file. ModeExecutable FileMode = "100755" // ModeSymlink is a symbolic link whose blob content is the link target. ModeSymlink FileMode = "120000" )
The modes a generated tree may contain. Git's remaining modes are absent deliberately: a subtree is implied by the paths rather than named by the caller, and a gitlink would publish a submodule pointer to a commit no generated repository contains.
type GitHubTokenCredential ¶ added in v0.2.0
type GitHubTokenCredential struct {
// contains filtered or unexported fields
}
GitHubTokenCredential configures Git's HTTPS transport for one repository- scoped GITHUB_TOKEN without putting the credential in argv or a remote URL. It resets ambient credential helpers and headers, requires TLS verification, and disables proxies and redirects for the github.com credential scope.
Its fields are deliberately private. A caller can apply it to Runner options, but cannot accidentally format token-bearing configuration into a report.
func NewGitHubTokenCredential ¶ added in v0.2.0
func NewGitHubTokenCredential(token string) (*GitHubTokenCredential, error)
NewGitHubTokenCredential builds the host-scoped Basic authorization GitHub expects for x-access-token credentials.
func (*GitHubTokenCredential) Apply ¶ added in v0.2.0
func (c *GitHubTokenCredential) Apply(base Options) (Options, error)
Apply returns runner options carrying the credential. Existing environment config is refused instead of renumbered: composing two GIT_CONFIG_COUNT sets incorrectly can drop one silently, which could either lose authentication or send a credential under a caller-controlled key.
func (*GitHubTokenCredential) GoString ¶ added in v0.2.0
func (*GitHubTokenCredential) GoString() string
GoString renders the credential safely for the %#v format.
func (*GitHubTokenCredential) String ¶ added in v0.2.0
func (*GitHubTokenCredential) String() string
String renders the credential without exposing any token representation.
type ObjectFormat ¶
type ObjectFormat string
ObjectFormat is a repository's hash algorithm. It decides how long an object name is, and the two formats are not interchangeable: an object name written under one is meaningless under the other.
const ( ObjectFormatSHA1 ObjectFormat = "sha1" ObjectFormatSHA256 ObjectFormat = "sha256" )
The hash algorithms git supports.
func (ObjectFormat) HexLength ¶
func (f ObjectFormat) HexLength() int
HexLength reports how many characters an object name occupies in this format.
type ObjectInfo ¶
type ObjectInfo struct {
// Name is the object name as git resolved it, or the requested revision when
// the object could not be resolved.
Name string
// Type is the object type, empty when the object is missing.
Type string
// Size is the object size in bytes, zero when the object is missing.
Size int64
// Missing reports an object that is not present.
Missing bool
}
ObjectInfo is the type and size of one Git object.
type ObjectInfoOptions ¶
type ObjectInfoOptions struct {
// Revisions are the objects to describe.
Revisions []string
// AllowLazyFetch permits a partial clone to download the objects it is asked
// about. Leaving it false answers from the local object store only, which is
// what a "do I already have this" probe means. Setting it true is how a run
// deliberately prewarms blobs in one batch instead of one fetch per file.
AllowLazyFetch bool
}
ObjectInfoOptions configures a batched object probe.
type Options ¶
type Options struct {
// Binary is the Git executable. Empty means look up DefaultBinary on PATH.
Binary string
// Dir is the working directory for every command. Empty means the process
// working directory.
Dir string
// Inherit names the process environment variables to pass through. Empty
// means the default set. The values are read once, here, so a later change
// to the process environment cannot alter what an already built runner does.
Inherit []string
// Isolation holds KEY=VALUE entries that decide where Git looks for state
// rather than granting access to anything, such as HOME or TMPDIR. They
// carry no credential, so they survive Anonymous: a run that redirected HOME
// to keep a subprocess away from operator configuration must stay redirected
// when it talks to the source host. They are not seeded into the redactor,
// because a path is not a secret and redacting it would corrupt output.
Isolation []string
// Env holds additional KEY=VALUE entries applied after the inherited, fixed,
// and isolation entries, which is how credentials reach Git. Every non-empty
// value is seeded into the redactor, so an entry cannot leak by being
// forgotten in Secrets. A runner with any entry here is treated as possibly
// carrying a credential and is refused by the source commands until
// Anonymous strips them.
Env []string
// Secrets holds additional exact values that must never appear in captured
// output.
Secrets []string
// OutputLimit bounds the bytes one command may return on a stream. Zero
// means DefaultOutputLimit and a negative value is rejected.
OutputLimit int64
// contains filtered or unexported fields
}
Options configures a Runner.
type PartialCloneStatus ¶
type PartialCloneStatus int
PartialCloneStatus describes how completely a repository holds its blobs.
const ( // PartialCloneUnknown reports a tree with no blob in it, which proves // nothing either way. PartialCloneUnknown PartialCloneStatus = iota // PartialCloneConfirmed reports blobs that the repository does not hold, so // the filter was applied. PartialCloneConfirmed // PartialCloneFull reports that every blob is present, so the repository // holds a complete history whatever its configuration claims. PartialCloneFull )
The partial clone verdicts.
type PushUpdate ¶
type PushUpdate struct {
// Ref is the fully qualified destination ref.
Ref string
// New is the full object name the ref must end up holding.
New string
// ExpectedOld is the full object name the destination must currently hold.
ExpectedOld string
// ExpectAbsent states that the ref must not exist yet. It is separate from
// an empty ExpectedOld so that "it must not exist" cannot be spelled by
// forgetting to say anything.
ExpectAbsent bool
}
PushUpdate is one ref update in an atomic push, bound to the value the caller expects the destination to hold at the moment the push runs.
type Redactor ¶
type Redactor struct {
// contains filtered or unexported fields
}
Redactor removes exact secret values from text. Redaction is exact value based rather than pattern based so a token can never survive because it did not match a heuristic.
func NewRedactor ¶
NewRedactor seeds a redactor with exact values. Empty values are ignored and longer values are replaced first so an overlapping prefix cannot leak a suffix.
func (*Redactor) Bytes ¶
Bytes replaces every seeded value in b. The input slice is returned unchanged when nothing matches, so the common case does not copy.
func (*Redactor) Error ¶
Error removes every seeded value from an error message while keeping the original error in the chain, so errors.Is and errors.As keep working.
func (*Redactor) Writer ¶
func (r *Redactor) Writer(w io.Writer) io.WriteCloser
Writer wraps w so that seeded values are removed from streamed output. The returned writer holds back the bytes that could still complete a secret, so callers must close it to flush the tail. Without secrets the writer is transparent and buffers nothing.
type Ref ¶
type Ref struct {
// Name is the fully qualified ref name.
Name string
// Target is the object the ref points at, which is the tag object itself for
// an annotated tag.
Target string
// Type is the target's object type, such as commit or tag.
Type string
// Commit is the commit the ref ultimately resolves to. For an annotated tag
// it is the peeled commit, and for every other ref it equals Target.
Commit string
}
Ref is one reference in the local repository.
type RevListOptions ¶
type RevListOptions struct {
// Include lists the revisions to walk from, such as branch tips.
Include []string
// Exclude lists the revisions whose ancestors are left out, which is how a
// walk is bounded below by the recorded anchor.
Exclude []string
// FirstParent follows only the first parent of every merge, which yields the
// mainline of a branch.
FirstParent bool
// MaxCount bounds the number of commits returned. Zero means no bound.
MaxCount int
}
RevListOptions selects a commit range.
type Runner ¶
type Runner struct {
// contains filtered or unexported fields
}
Runner executes Git commands with a controlled environment.
func (*Runner) AddPaths ¶
AddPaths stages exact repository relative paths. Pathspec magic and wildcards are rejected, and literal pathspecs are forced for the duration of the command, so a configured path can only ever stage the file it names.
func (*Runner) AddWorktree ¶
func (r *Runner) AddWorktree(ctx context.Context, opts WorktreeOptions) error
AddWorktree registers an isolated work tree at a detached commit.
func (*Runner) Anonymous ¶
Anonymous returns a copy of the runner with every caller supplied environment entry dropped, which is how a credential that reached this runner through Options.Env is kept away from a subprocess that talks to the public source host. The redactor is preserved, because output must still be scrubbed even when this particular command cannot see the secret.
Isolation entries are kept. They decide where Git looks for state rather than granting access to anything, and a run that redirected HOME away from operator configuration must stay redirected when it reaches the network. A no lazy fetch pin is kept for the same reason: dropping credentials must not also drop a refusal to reach the network.
func (*Runner) ApplyPatch ¶
func (r *Runner) ApplyPatch(ctx context.Context, opts ApplyOptions) error
ApplyPatch applies a unified diff to the current work tree.
Paths that escape the work tree are refused by git itself because --unsafe-paths is never passed, so a hostile patch cannot write outside the materialized tree.
func (*Runner) ApplyThreeWayIndex ¶
ApplyThreeWayIndex applies one unified diff with three way and index semantics and no way to weaken either.
Both are load bearing for patch replay. A strict apply would reject a patch whose context drifted by one line and report nothing a maintainer could act on, and an apply that skipped the index would hide the patched files from the pruning and tree building that follow. Offering them as a single call means a caller cannot turn one of them off by accident.
func (*Runner) ChangedPaths ¶
ChangedPaths lists the repository relative paths that differ between two revisions. An empty from compares against the empty tree, so the result is every path the revision's tree contains, which is what a root commit introduced.
The empty tree is named explicitly rather than requested with --root. With --root git compares a root commit against nothing but compares every other commit against its parent, and for a merge it emits nothing at all, so an empty from would silently mean three different things depending on the shape of the commit it was handed.
Merges still have no single answer when a parent is meant, so the caller passes the parent it means to compare against rather than relying on a default.
func (*Runner) CheckoutDetached ¶
CheckoutDetached materializes one commit without moving any branch. It is the step that populates a work tree created with NoCheckout, and it honours the sparse pattern set installed beforehand.
func (*Runner) Clean ¶
Clean removes untracked and ignored files. Ignored files are included because a materialized work tree must contain exactly what the run put there, and an upstream .gitignore would otherwise hide leftovers from a previous pass.
func (*Runner) CloneSource ¶
func (r *Runner) CloneSource(ctx context.Context, opts SourceCloneOptions) error
CloneSource creates the anonymous partial clone that backs the source cache.
func (*Runner) Commit ¶
func (r *Runner) Commit(ctx context.Context, opts CommitOptions) error
Commit records the staged tree. Identity travels through the environment, the message is preserved verbatim, and signing is always off, because the engine only creates generated or bootstrap commits.
func (*Runner) CommitGraph ¶
CommitGraph lists commits with their parents in topological order, parents before children.
The order is git's own reverse topological order rather than a date order, because commit dates in an imported history are attacker and rebase controlled and would make the replay sequence unstable.
func (*Runner) CommitInfo ¶
CommitInfo reads metadata, signature status, and trailers for one revision.
func (*Runner) CommitLog ¶
CommitLog reads metadata, messages, and trailers for a range of commits in one subprocess.
This is the batched form of CommitInfo, and batching is the point: mapping a source history onto a published one reads tens of thousands of commits, and a process per commit would dominate every other cost in the engine.
The order is git's own reverse topological order, parents before children, which matches CommitGraph so a caller can zip the two together. It is not a date order, because commit dates in an imported history are rebase and attacker controlled.
MaxCount is applied before the reversal, exactly as git applies it: a bounded walk returns the newest commits presented oldest first, not the oldest ones.
func (*Runner) CommitParents ¶
CommitParents reports the parent object names of one commit in git's order.
func (*Runner) ConfigEffective ¶
func (r *Runner) ConfigEffective(ctx context.Context, key string) (value string, found bool, err error)
ConfigEffective reads the value git would actually use for one key.
It is deliberately not scoped. A cache audit has to know what the next command will do, and a worktree scoped key silently outranks the local one a --local read would have returned.
func (*Runner) ConfigKeys ¶
func (r *Runner) ConfigKeys(ctx context.Context) ([]ConfigEntry, error)
ConfigKeys reports every configuration key the repository itself defines, with the scope each came from, ordered by scope and then key.
The listing is what makes a provenance audit possible: reading the handful of keys a caller expects would say nothing about the keys it did not think to ask about, and a repository restored from an untrusted cache can carry any of them.
func (*Runner) ConfigLocal ¶
ConfigLocal reads one repository local configuration value. A missing key is reported through found rather than as an error.
func (*Runner) CreateRef ¶
CreateRef points a new local ref at a commit and fails when the ref already exists.
Git spells that precondition as an empty expected value, and it is the honest default for published history: a name that is already taken means something else created it, which is a fact the caller has to reconcile rather than overwrite.
func (*Runner) CreateTag ¶
func (r *Runner) CreateTag(ctx context.Context, opts TagOptions) error
CreateTag creates an annotated or lightweight tag. Replacing an existing tag is not possible here: published tags are immutable, so a name that already exists fails rather than moving.
An annotated message is preserved byte for byte. Git's default cleanup for a supplied message strips trailing whitespace, collapses trailing blank lines, and deletes every line beginning with a hash, so an upstream release note that happened to contain one would be published with that line missing and the tag would not be the one it claims to reproduce. The message also travels on standard input, which keeps a message beginning with a dash out of the argument vector.
func (*Runner) Diff ¶
Diff renders a unified diff for a failure report. Colour and external diff drivers are disabled so the captured text is the same on every machine.
func (*Runner) DiffWorkTree ¶
DiffWorkTree renders the unified diff of the work tree against the index, which is what a failed three way application leaves behind, conflict markers included. It is the narrow form of Diff that a conflict report wants.
func (*Runner) DisableSparseCheckout ¶
DisableSparseCheckout removes the pattern set and materializes every path.
func (*Runner) EmptyTree ¶
EmptyTree reports the empty tree object name for this repository's hash algorithm, which is what a comparison "against nothing" needs to name.
func (*Runner) FetchExact ¶ added in v0.2.0
func (r *Runner) FetchExact(ctx context.Context, remote, remoteRef, expectedOID string, hexLength int) error
FetchExact downloads exactly one advertised object from a remote without moving any local ref and without writing FETCH_HEAD.
The refspec fetches the remote ref into a namespaced ref under refs/soapbox/fetch/ that no consumer ref can collide with. After the fetch the temporary ref is deleted, so no persistent state remains. The object is retained in the object store.
The caller must supply the exact OID the remote advertised (from RemoteRefs). After the fetch, the downloaded object is verified to match that OID. This guarantees that the remote cannot substitute a different object than what was advertised.
The runner must carry the same credentials that were used for RemoteRefs.
func (*Runner) FetchSource ¶
func (r *Runner) FetchSource(ctx context.Context, opts SourceFetchOptions) error
FetchSource updates the source cache from the upstream repository.
The fetch is deliberately not quiet: git reports a rejected non fast forward update only in its ref summary, and that summary is the evidence that upstream rewrote history the engine may already have replayed.
func (*Runner) HasHead ¶
HasHead reports whether HEAD resolves to an existing object. A freshly initialized repository has no HEAD commit and is not an error, while a HEAD that points at a missing or unreadable object is.
show-ref is used rather than rev-parse because rev-parse --quiet reports both states with exit status 1, which would hide a corrupt repository.
func (*Runner) HasRef ¶
HasRef reports whether one fully qualified ref exists. A missing ref is a supported state rather than an error, because a profile may name a release branch that upstream has not created yet.
func (*Runner) InitRepository ¶
InitRepository creates a repository in the runner's working directory.
func (*Runner) InitRepositoryWithFormat ¶
func (r *Runner) InitRepositoryWithFormat(ctx context.Context, initialBranch string, format ObjectFormat) error
InitRepositoryWithFormat creates a repository whose objects use the named hash algorithm.
The algorithm is fixed when a repository is created and cannot be changed afterwards, so a destination repository has to choose it deliberately rather than inherit whatever the local git defaults to. InitRepository remains the call for a repository whose object names are nobody's business but its own.
func (*Runner) IsAncestor ¶
IsAncestor reports whether ancestor is reachable from descendant. A commit is its own ancestor, matching git's own definition.
func (*Runner) IsAnonymous ¶
IsAnonymous reports whether the runner carries no caller supplied environment entries. Source acquisition asserts this before it reaches the network.
func (*Runner) IsBareRepository ¶
IsBareRepository reports whether the working directory is a repository with no work tree. A directory that holds no repository at all is a supported state and reports false, while a repository that cannot be read is an error, which is what keeps a corrupt cache from being silently re-created.
Discovery is pinned to the working directory: the answer describes that exact path and never a repository above it. Without the pin, probing a directory that is not a repository would report on whatever repository contains it, and a cache directory that had been emptied would present itself as a usable cache belonging to somebody else.
func (*Runner) IsBareRepositoryAt ¶
IsBareRepositoryAt reports whether dir itself is a bare repository.
The git directory is stated rather than discovered, so a directory that is not a repository is reported as one rather than resolving to an ancestor, and the path git actually opened is compared with the one that was asked about.
func (*Runner) IsNoLazyFetch ¶
IsNoLazyFetch reports whether the runner refuses promisor fetches.
func (*Runner) IsRepository ¶
IsRepository reports whether the working directory is inside a Git work tree. A directory that is not a repository yet is a supported state; a repository that cannot be read is an error.
func (*Runner) ListRefs ¶
ListRefs reports the refs matching the given patterns, or every ref when no pattern is given. Results keep git's ref name ordering, so repeated runs observe the same sequence.
func (*Runner) ListTree ¶
ListTree lists every blob a tree holds, recursively, sorted by path.
It is the read side of WriteTree, and the pair is what lets a caller prove a tree holds exactly the files it meant to publish rather than trusting that the write did what it was asked.
Paths reach the caller exactly as git recorded them, without passing through the redactor, for the reason ReadBlob's bytes do: a path is content, and rewriting one that merely happened to match a secret would report a tree that does not exist.
func (*Runner) ListWorktrees ¶
ListWorktrees reports every work tree registered with this repository, including the repository's own entry.
func (*Runner) MergeBase ¶
MergeBase reports the best common ancestor of two revisions, and fails when there is more than one, as a criss-cross merge produces.
func (*Runner) MergeBases ¶
MergeBases reports every best common ancestor of two revisions, sorted by object name so a caller never depends on git's traversal order.
func (*Runner) MergeBasesOctopus ¶
MergeBasesOctopus reports every best common ancestor of every revision, which is how the immutable transformed anchor is derived from the initially tracked refs.
The plural matters. Without --all git prints one of the best common ancestors and gives no sign that it chose, so a criss-cross history would silently anchor published history to whichever base the traversal reached first.
func (*Runner) ObjectFormat ¶
func (r *Runner) ObjectFormat(ctx context.Context) (ObjectFormat, error)
ObjectFormat reports the repository's hash algorithm.
Replay needs it as data rather than as an assumption. The engine computes object names locally to decide what it already has, and a computation that guessed the algorithm would not fail: it would produce names that never match, so every object would look absent and be rewritten.
func (*Runner) ObjectInfoBatch ¶
func (r *Runner) ObjectInfoBatch(ctx context.Context, opts ObjectInfoOptions) ([]ObjectInfo, error)
ObjectInfoBatch describes many objects in one subprocess. Batching matters for a blobless clone, where the alternative is one round trip per object.
func (*Runner) ParseTrailers ¶
ParseTrailers reports the trailers git itself finds in a commit message.
This is git's own answer rather than an approximation of it: interpret-trailers applies the trailer block rules, folds continuation lines, and ignores a patch part. It reads no repository, so it works anywhere, and it is the reference the pure implementation in gitgraph is checked against.
func (*Runner) PartialCloneStatusOf ¶
func (r *Runner) PartialCloneStatusOf(ctx context.Context, revision string) (PartialCloneStatus, error)
PartialCloneStatusOf reports whether the repository really omits the blobs of one commit.
Configuration is not evidence here. A server that does not honour --filter makes git warn, exit zero, and record remote.origin.promisor and remote.origin.partialclonefilter anyway, so a repository that claims to be a blobless partial clone and holds every blob is exactly what a silent degradation looks like.
The blobs of the commit are enumerated with the same filter that was requested and then probed locally with lazy fetching disabled, so the answer describes what is on disk and the probe itself cannot download what it asks about.
func (*Runner) PruneWorktrees ¶
PruneWorktrees drops administrative entries whose directory is already gone.
func (*Runner) Push ¶
Push updates remote refs. There is no force variant: every refspec is checked and any forced or deleting refspec is rejected before the subprocess starts.
func (*Runner) PushAtomic ¶
PushAtomic updates remote refs in one transaction, guarding every ref with a compare and swap against the value the caller expects it to hold.
Push lets git reject anything that is not a fast forward, and a fast forward check is not the same guarantee as a compare and swap. Between reading a remote and pushing to it, another writer can advance a branch to a commit this push then fast forwards straight over. Git is satisfied, and what lands is not the update that was reviewed, because the value it was reviewed against is gone. Naming the expected value moves the comparison into the ref transaction on the far side, where nothing can race it.
The lease is a compare and swap rather than a licence to force. With a matching lease git will accept a rewind, so this is where the fast forward rule is kept instead: every update naming an expected value is proved to descend from it before the subprocess starts, and refused otherwise. The empty lease is git's own spelling of "this ref must not exist yet", which is what keeps a create from quietly becoming an update to whatever appeared in the meantime.
Deleting remains impossible. Every update names an object it moves to, and the null object name git's protocol spells a deletion with is refused.
func (*Runner) ReadBlob ¶
ReadBlob returns the exact bytes of one blob.
The object is named on standard input rather than in the argument vector, using git's batch protocol, so a hostile revision or path is data to git's object parser and never a candidate option. The response carries the size before the content, so the limit is enforced against what git promises rather than against what was already copied into memory: an oversized blob is refused on its header and the read is abandoned. What that saves is memory, not traffic. Under AllowLazyFetch the object is already local by the time its header can be read.
The bytes are returned verbatim, including null bytes and invalid UTF-8, and are not passed through the redactor. A blob is content rather than diagnostics, and rewriting bytes that merely happened to match a secret would corrupt the file the engine is about to parse or hash.
func (*Runner) RemoteRefs ¶ added in v0.2.0
RemoteRefs reads the refs a remote repository advertises without fetching any objects.
The command is git ls-remote --refs, which asks the remote for its ref advertisement and reports each ref as a tab-separated OID/name pair. No objects are downloaded, and no local state is modified.
The runner must carry a GitHubTokenCredential for an authenticated remote, or be anonymous for a public one. The package translates that credential into GIT_CONFIG_COUNT/KEY/VALUE entries with a host-scoped extraHeader; it never appears in a URL or an argument vector.
The remote is validated by ValidatePushRemote: it must be an absolute path, a file URL, or an https URL on the publish host. A named remote is refused because its target lives in configuration.
Results are deterministically sorted by ref name. Duplicate refs (same name, different OID) are refused. Peeled entries (^{}) and HEAD are excluded. Every returned name is validated by ValidateRefName and every OID is checked against the runner's expected hex length from the caller.
func (*Runner) RemoveWorktree ¶
RemoveWorktree unregisters a work tree and deletes its directory. Removing a work tree that is not registered succeeds, so cleanup after a failed run is idempotent and a deferred removal never masks the original error.
func (*Runner) RepositoryRoot ¶
RepositoryRoot reports the absolute path of the work tree root.
func (*Runner) RequireMinimumVersion ¶
RequireMinimumVersion fails when the resolved Git is older than the release every command in this package is proved against.
It is a preflight rather than a nicety. The oldest capability this package depends on, GIT_NO_LAZY_FETCH, is ignored rather than rejected by a Git that does not know it, so an old binary would turn a local object probe into a silent network fetch instead of an error.
func (*Runner) ResetHard ¶
ResetHard discards index and work tree state and moves HEAD to revision. It is only ever used on a work tree the engine created, never on an operator's.
func (*Runner) ResolveCommit ¶
ResolveCommit resolves a revision to a full commit object name.
func (*Runner) ResolveTree ¶
ResolveTree resolves the tree object of one commit, which is the cheapest way to tell whether two commits produce identical content.
func (*Runner) SetConfigLocal ¶
SetConfigLocal writes one repository local configuration value. Values that look like options are rejected because git config has no option terminator.
func (*Runner) SetSparseCheckout ¶
func (r *Runner) SetSparseCheckout(ctx context.Context, opts SparseOptions) error
SetSparseCheckout installs the pattern set that decides which paths a work tree materializes.
Patterns are passed after the option terminator and never through standard input, and no path separator is appended, because git writes the argument vector verbatim into the pattern file: an extra separator would become a pattern of its own.
func (*Runner) SparseCheckoutPatterns ¶
SparseCheckoutPatterns reports the installed pattern set, which is how a run proves the work tree it measured is the work tree it asked for.
func (*Runner) Status ¶
func (r *Runner) Status(ctx context.Context) ([]StatusEntry, error)
Status reports the work tree state. Rename detection is off so that every record is exactly one path and the parse cannot depend on a similarity score.
func (*Runner) StatusPorcelainZ ¶
StatusPorcelainZ reports the raw null separated porcelain status, for a caller that wants to record exactly what git said rather than a parsed form.
Every record is a two character code, a space, and one path. Rename detection is off, because a rename record carries two null separated paths instead of one and would desynchronise a reader that assumed one path per record.
func (*Runner) TagInfo ¶
TagInfo describes one tag.
An annotated tag is read from its object rather than through a ref format, because the message has to survive byte for byte: for-each-ref terminates each record with a newline of its own, which a message that did not end in one would silently gain.
func (*Runner) TagObjectByOID ¶ added in v0.2.0
TagObjectByOID reads an annotated tag object by its OID using cat-file.
The OID must name a tag object; a commit, tree, or blob is refused. This is the read-by-OID complement to TagInfo, which reads by ref name. It exists so a tag fetched by OID (via FetchExact) can be inspected without a local ref pointing at it.
func (*Runner) UnsetConfigLocal ¶
UnsetConfigLocal removes one repository local configuration key. Removing a key that is already absent is not an error.
func (*Runner) UpdateRef ¶
UpdateRef moves an existing local ref to a commit, failing unless the ref currently holds expected.
The comparison is the point. Without it an update is a blind write: a concurrent run, a stale in memory value, or a local rewind between reading a ref and writing it would all be applied silently, and the ref the engine publishes from would no longer be the one it reasoned about. Git performs the comparison and the update under the ref lock, so the check cannot be raced.
This writes only to the local repository. There is still no delete and no reflog rewriting, and the append only guarantees the engine publishes under live in Push, which is the only call that reaches a remote.
func (*Runner) WithDir ¶
WithDir returns a copy of the runner that operates in dir.
The directory is checked exactly as New checks one, because a runner pointed at a path that was never created would otherwise run its first command in the process working directory. The path must be absolute for the same reason.
Discovery is also pinned: a command run through the returned runner may find the repository at dir but may never ascend to one above it. Without that, a cache directory that was removed or never finished being written would hand every later command whatever repository happens to contain it.
func (*Runner) WithNoLazyFetch ¶
WithNoLazyFetch returns a copy of the runner that refuses to download objects from a promisor remote.
This is the intrinsic form of the guarantee. Passing GIT_NO_LAZY_FETCH to one command protects that command; pinning it to a runner protects every command the runner will ever issue, including the ones that reach the object store without looking like it. A checkout, a reset, or a diff in a blobless clone will each happily fetch what they are missing, and none of them takes an option that says otherwise.
The pin is a property of the runner rather than an environment entry a caller supplies, so there is no general override to reopen: it survives Anonymous, it cannot be shadowed by a later Env entry, and it is applied after everything else when the command is built. A call that explicitly asks for a lazy fetch on a pinned runner is refused rather than quietly ignored.
It requires a Git that honours the variable. See MinimumNoLazyFetchVersion.
func (*Runner) WriteBlob ¶
WriteBlob writes content to the object store and reports the blob's name.
The content travels on standard input, so it is never an argument and may hold any byte, including nulls and invalid UTF-8. Filters are disabled: a clean filter is a repository local rule about what a working tree file becomes on its way into the object store, and applying one here would make the published bytes depend on configuration rather than on the content the engine produced.
func (*Runner) WriteCommit ¶
WriteCommit writes a commit object without touching the index or the work tree, and reports its object name.
Building commits from objects rather than from a checkout is what lets replay reproduce a graph exactly: parents are stated rather than inferred from HEAD, identity travels through the environment, and nothing depends on the state of a work tree that another step may have changed.
Every input is pinned to what the commit will record. The tree and the parents must be full object names, because a revision git would resolve, HEAD or a branch or an abbreviation, makes the written commit depend on the repository's current state rather than on what the caller described. Both identities must be complete, because git fills a missing name or address in from the environment and would attribute the commit to whoever happened to run it. The reported name is checked for the reason WriteTree checks its own.
Dates use Git's raw form as well. An omitted date makes commit-tree record the wall clock, while a friendly date string asks Git to reinterpret caller input; either would make the object name depend on when or where this runs rather than only on the fields supplied here.
func (*Runner) WriteTagObject ¶
WriteTagObject writes an annotated tag object and reports its name, without creating a ref.
Separating the object from the ref is what makes a tag reproducible. The object carries the message, the tagger, and the date, so writing it is enough to learn the name a release would have, and a run can compare that name against a published tag without having created anything locally that would have to be cleaned up. CreateTag is the step that gives the object a name in the ref namespace, and it stays separate so a dry run never takes it.
func (*Runner) WriteTree ¶
WriteTree writes a complete tree and reports its object name.
The entries are staged into an index of this call's own, named through GIT_INDEX_FILE in a temporary directory, so the repository's index is neither read nor written. That matters beyond tidiness: replay runs against a repository a person may also be using, and building a tree through the shared index would make the published output depend on whatever was staged there.
Entries are sorted and framed with nulls on standard input, so two callers that describe the same tree in different orders write the same object, and a path holding a space, a tab, or a quote cannot be split into two records.
Every named object is confirmed to be a blob this repository already holds before any of them is staged, which costs one batched probe per tree. See checkTreeObjects for what that check is worth.
type Signature ¶
Signature is a Git author or committer identity with an optional date. The date uses any format git accepts, such as RFC 3339.
type SourceCloneOptions ¶
type SourceCloneOptions struct {
// Remote is the upstream repository, checked by ValidateSourceRemote.
Remote string
// Directory is the repository to create. It must be absolute so a cache
// location never depends on the process working directory.
Directory string
// Filter is the partial clone filter. Empty means BloblessFilter.
Filter string
// Bare creates a repository with no work tree, which is what the reusable
// cache wants because every materialization happens in its own worktree.
Bare bool
// NoCheckout leaves the work tree empty so a sparse pattern set can be
// installed before any file is written. It is redundant when Bare is set.
NoCheckout bool
}
SourceCloneOptions describes one anonymous clone of the upstream repository.
type SourceFetchOptions ¶
type SourceFetchOptions struct {
// Remote is the upstream repository, checked by ValidateSourceRemote.
Remote string
// Refspecs are explicit <source>:<destination> pairs. Every pair is checked
// by ValidateFetchRefspec.
Refspecs []string
// Tags additionally fetches the tags that point into the fetched history.
// Git refuses to clobber an existing tag without a force refspec, so a
// retagged upstream release fails the run rather than rewriting the cache.
Tags bool
// Filter is the partial clone filter. Empty means BloblessFilter.
Filter string
}
SourceFetchOptions describes one anonymous fetch into the source cache.
type SparseOptions ¶
type SparseOptions struct {
// Cone restricts patterns to directory prefixes, which git can match without
// consulting every path. A cone pattern always includes subdirectories, so
// package granularity needs the pattern form instead.
Cone bool
// Patterns are gitignore style patterns applied in order, later patterns
// winning. A directory that matches is included with everything below it, so
// materializing one package without its subpackages needs an explicit
// negative pattern such as !/pkg/apis/rbac/v1/*/ after /pkg/apis/rbac/v1/*.
Patterns []string
}
SparseOptions selects the files a work tree materializes.
type StatusEntry ¶
type StatusEntry struct {
// Code is the two character porcelain status code, such as " M" for a
// modified file, "??" for an untracked one, or "UU" for a conflict.
Code string
// Path is the repository relative path.
Path string
}
StatusEntry is one changed path reported by git status.
func (StatusEntry) Conflicted ¶
func (e StatusEntry) Conflicted() bool
Conflicted reports an unmerged path, which is how a three way patch application signals that it left conflict markers behind.
type Tag ¶
type Tag struct {
// Name is the short tag name.
Name string
// Object is what the ref points at directly: the tag object when the tag is
// annotated, and the commit itself when it is lightweight.
Object string
// Target is the commit the tag ultimately names, which is the value a
// caller comparing two tags means.
Target string
// Annotated reports a tag that carries its own object. A release tag always
// does, because it records a tagger and a date of its own.
Annotated bool
// Tagger is the recorded identity, with the date in git's raw form. It is
// empty for a lightweight tag, which has nowhere to record one.
Tagger Signature
// Message is the tag message exactly as stored, empty for a lightweight tag.
Message string
}
Tag is a resolved tag ref.
type TagObject ¶ added in v0.2.0
type TagObject struct {
// InternalName is the "tag" header inside the object. It must match the
// ref name the tag is published under; a mismatch means the object was
// created for a different name.
InternalName string
// TargetOID is the "object" header: the OID the tag points at.
TargetOID string
// TargetType is the "type" header, normally "commit".
TargetType string
// Tagger is the recorded identity and date.
Tagger Signature
// Message is the tag message exactly as stored.
Message string
}
TagObject is the content of one annotated tag object read by OID.
type TagObjectOptions ¶
type TagObjectOptions struct {
// Object is the full object name the tag points at.
Object string
// Type is the pointed at object's type, normally commit.
Type string
// Name is the short tag name recorded inside the object, such as v0.36.1.
Name string
// Message is the tag message, recorded verbatim.
Message string
// Tagger is the recorded identity. Date must be git's raw form,
// "<seconds> <±hhmm>", because this writes the object's bytes rather than
// asking git to format them.
Tagger Signature
}
TagObjectOptions describes one annotated tag object to write.
type TagOptions ¶
type TagOptions struct {
// Name is the short tag name, such as v0.36.1.
Name string
// Commit is the revision the tag points at.
Commit string
// Message makes the tag annotated. An empty message creates a lightweight
// tag, which release tags never are, because a release records its own
// tagger identity and date.
Message string
// Tagger is the identity and date recorded in an annotated tag. The date is
// taken from upstream so a regenerated tag is byte identical.
Tagger Signature
}
TagOptions describes one tag to create.
type TreeEntry ¶
type TreeEntry struct {
// Mode is the recorded file mode.
Mode FileMode
// Object is the full blob object name. Short names are refused because a
// tree records the resolved object, and resolving an abbreviation here would
// make the written tree depend on which other objects the repository happens
// to hold.
Object string
// Path is the repository relative path, separated by forward slashes.
// Directories are implied by it rather than listed separately.
Path string
}
TreeEntry is one blob in a tree, at one path.
type Version ¶
Version is a parsed Git or Go release version.
func MinimumNoLazyFetchVersion ¶
func MinimumNoLazyFetchVersion() Version
MinimumNoLazyFetchVersion is the oldest Git release that documents and honours GIT_NO_LAZY_FETCH.
It is exported because more than one caller has to enforce it and they must not each carry a number of their own: offline materialisation refuses to run below it, and the doctor reports it. The provenance is in the package's version comment above.
The number matters less than the behaviour, which is why TestNoLazyFetchIsHonoured exercises the variable against the git the tests actually run. An older git ignores it rather than rejecting it, so a floor that is wrong fails silently, by reaching the network, rather than loudly.
func MinimumVersion ¶
func MinimumVersion() Version
MinimumVersion reports the oldest Git release this package supports. It is exported so the preflight check and the engine's doctor report a single number rather than two that can drift apart.
The floor is set by GIT_NO_LAZY_FETCH, so it is that capability's version rather than a number of its own.
func ParseVersion ¶
ParseVersion parses a dotted numeric version, ignoring any vendor suffix.
type Worktree ¶
type Worktree struct {
// Path is the absolute work tree directory.
Path string
// Head is the checked out commit, empty for a bare repository entry.
Head string
// Branch is the checked out branch, empty when HEAD is detached.
Branch string
// Bare reports the entry that describes the repository itself.
Bare bool
// Detached reports a work tree that is not on a branch, which is what every
// materialization uses so a checkout can never move a ref.
Detached bool
}
Worktree is one registered work tree of a repository.
type WorktreeOptions ¶
type WorktreeOptions struct {
// Path is the absolute directory to create. It must not exist yet.
Path string
// Commit is the revision to check out. It is always detached, because a
// materialization must never advance a branch in the shared cache.
Commit string
// NoCheckout leaves the work tree empty so that a sparse pattern set can be
// installed before any file is written. Without it a full checkout of the
// source repository happens first and the sparse set only prunes it again,
// which for a blobless clone means downloading every blob in the tree.
NoCheckout bool
}
WorktreeOptions describes one work tree to create.