On this page
Command safegit wraps git, giving each commit its own temporary index and retrying ref updates on conflict, so concurrent agents share one repository.
#safegit
#.
Command safegit wraps git, giving each commit its own temporary index and retrying ref updates on conflict, so concurrent agents share one repository.
#IntentUnset
const IntentUnset IntentKind = iotaIntentUnset is the zero value and is always an error: a rewrite that reaches Finalize without declaring what it meant to do cannot be verified, and silently skipping the verification is exactly the hole the declaration exists to close.
#IntentPerPath
const IntentPerPathIntentPerPath means the rewrite declared, per commit, which paths and which messages it changes. Every scrub carries this.
#IntentIdentityOnly
const IntentIdentityOnlyIntentIdentityOnly means the rewrite changes commit IDENTITY headers (author, committer, tagger) rather than content, so there is no per-path expectation to check -- but every tree must still come through byte-identical, and a message may change only where the walk declared it rewrote an identity-bearing trailer. author rewrite carries this.
#ScrubVerifyPatternResult
type ScrubVerifyPatternResult structScrubVerifyPatternResult is the per-pattern result for JSON output.
#ScrubVerifyResult
type ScrubVerifyResult structScrubVerifyResult is the top-level JSON output for scrub verify.
#Recipe
type Recipe structRecipe is the raw TOML schema for a scrub recipe file.
#RecipeOperation
type RecipeOperation structRecipeOperation is a single operation within a recipe.
#ParsedRecipe
type ParsedRecipe structParsedRecipe is the validated, compiled form of a Recipe.
#RefUpdatePlan
type RefUpdatePlan structRefUpdatePlan is everything a rewrite will do to refs, computed before any of it happens. Splitting the plan from its application is what lets Tier A verification run on the finished object graph while the repository still points at the old one: every object the plan needs exists once the plan is built, and not one ref has moved.
#RewriteAuthorResult
type RewriteAuthorResult structRewriteAuthorResult is what author rewrite reports -- in both modes and in both renderings. There is no separate dry-run struct: the preview's counts and the execution's counts are members of one result, each present exactly when it was measured.
#IntendedChange
type IntendedChange structIntendedChange is what a rewrite operation DECIDED to change in one commit, recorded while the decision was made rather than read back off the result: the repo-relative paths whose blob (or gitlink) the operation replaced, and whether it rewrote the commit message.
Tier A verification diffs the old and new commit and refuses the whole rewrite when the two disagree. That is the preservation property: a rewrite may change what it said it would change, and nothing else.
#IntentKind
type IntentKind intIntentKind says what KIND of expectation a rewrite carries, because the two answers a verifier can act on are different questions -- and because the zero value must be neither of them.
#RewriteIntent
type RewriteIntent structRewriteIntent is the declaration a rewrite hands to Finalize.
#RewriteMapStart
type RewriteMapStart structRewriteMapStart is the phase-"start" record.
#RewriteMapRefs
type RewriteMapRefs structRewriteMapRefs is the phase-"refs" record.
#RewriteMapComplete
type RewriteMapComplete structRewriteMapComplete is the phase-"complete" record.
#TierAFunc
type TierAFunc func(ctx context.Context, plan *RefUpdatePlan) errorTierAFunc is a command's own pre-refs verification. It runs while the rewritten commits are still unreachable objects, and it receives the ref update plan so it can inspect exactly what is about to become the repository's history -- the new commit tips and the new tag objects -- none of which any ref points at yet. A non-nil error refuses the whole rewrite.
#TierBFunc
type TierBFunc func(ctx context.Context) errorTierBFunc is a command's own post-cleanup verification. It runs after the refs have moved and the object store has been swept, so its findings cannot undo anything: a non-nil error is REPORTED and turns the command's exit code nonzero, with the rewrite standing.
#RewriteHooks
type RewriteHooks structRewriteHooks are the two verification hooks and the tag-annotation transform a rewrite hands to Finalize. Every field may be nil except where a command's own contract requires it.
#RewriteResult
type RewriteResult structRewriteResult collects the outputs of a history rewrite so that Finalize can execute the shared post-rewrite pipeline (verification, ref updates, cleanup, oplog, push hint).
#ScanResult
type ScanResult structScanResult is the JSON output for safegit scan.
#ScanMatchJSON
type ScanMatchJSON structScanMatchJSON is a single match in JSON output.
#ScrubFileResult
type ScrubFileResult structScrubFileResult is what scrub file reports -- in both modes and in both renderings. There is no separate dry-run struct: a preview and an execution answer the same questions about the same rewrite, and every figure here is the one the human summary prints. The fields only an executed rewrite can know are pointers or omitempty, so a preview omits them rather than publishing a zero that reads as a fact.
#TagBodyTransformFunc
type TagBodyTransformFunc func(refname, header, body string) (newBody string, err error)TagBodyTransformFunc transforms the body of an annotated tag. It receives the tag's refname, full header text, and body text. It returns the new body (or the same body if no change is needed) and any error.
A rewrite hands one of these to Finalize, which applies it while it plans the ref updates: the new tag objects are written before Tier A verification runs, and the refs that point at them move with every other ref afterwards.
#ScrubMatchResult
type ScrubMatchResult structScrubMatchResult is what scrub match reports -- in both modes and in both renderings. There is no separate dry-run struct: the preview's scan figures and the execution's rewrite figures are members of one result, each present exactly when it was measured.
objects_matched exists because the human preview's "in N objects" was never objects_scanned: it counts the DISTINCT objects that matched, and the two numbers used to live in disjoint branches under names close enough to read as the same thing. Both are here now, named for what they count.
#ScrubRunResult
type ScrubRunResult structScrubRunResult is what scrub run reports -- in both modes and in both renderings. There is no separate dry-run struct: the preview's per-operation match counts and the execution's rewrite figures are members of one result, each present exactly when it was measured.
#ScrubRunDiffEntry
type ScrubRunDiffEntry structScrubRunDiffEntry is a single blob diff in --diff preview output.
#MessageDiffEntry
type MessageDiffEntry structMessageDiffEntry is a commit message diff in --diff preview output.
#ScrubRunOpMatches
type ScrubRunOpMatches structScrubRunOpMatches holds one operation's match counts in a preview.
#TagRewrite
type TagRewrite structTagRewrite records how a tag ref was updated during history rewriting.
#CommitTransform
type CommitTransform structCommitTransform describes how a commit should be rewritten. Zero/empty fields mean "keep the original value."
#TransformFunc
type TransformFunc func(ctx context.Context, sha string, info git.CommitInfo, remappedParents []string, shaMap map[string]string) (CommitTransform, error)TransformFunc is called for each commit during a rewrite walk. It receives the original commit SHA, its parsed info, the already-remapped parent SHAs, and the growing old-to-new SHA map (which includes identity entries for already-walked unchanged commits; transforms must treat it as read-only — the walker owns it). It returns a CommitTransform describing what (if anything) to change.
#BuildRecipeBlobContent
func BuildRecipeBlobContent(ctx context.Context, recipe *ParsedRecipe, blobSHAs []string, blobAllowedOps map[string]map[int]bool) (map[string][]byte, error)BuildRecipeBlobContent applies a parsed recipe to a set of blobs, producing a mapping from old blob SHA to modified content bytes. It reads each blob, applies recipe operations in memory, and returns only blobs whose content changed. No objects are written to the object store -- this is purely in-memory content computation for dry-run and diff use cases.
blobAllowedOps optionally restricts which operations apply to each blob. When nil, all operations apply to all blobs. When set, only operations whose index is in blobAllowedOps[blobSHA] are applied to that blob. This is used to enforce per-operation scope filters from recipe TOML files.
#PerPathIntent
func PerPathIntent() *RewriteIntentPerPathIntent starts an empty per-path declaration for a walk to fill in.
#IdentityIntent
func IdentityIntent() *RewriteIntentIdentityIntent declares a rewrite that changes identity headers only. Its Changes map carries one thing: the commits whose MESSAGE the rewrite also changed, because an identity-bearing trailer (Signed-off-by, Co-authored-by) names the same person the headers do.
#effectsRefUpdate.Update
func (u effectsRefUpdate) Update(_ context.Context, ref, newSHA, expected string) error#remoteReadError.Error
func (e *remoteReadError) Error() string#remoteReadError.Unwrap
func (e *remoteReadError) Unwrap() error { return e.Err }#IntendedChange.Empty
func (c IntendedChange) Empty() boolEmpty reports whether this declaration says the commit's content is untouched. Such a commit may still be REWRITTEN -- a new commit object is created whenever a parent moved -- but its tree and message must come through identical.
#IntendedChange.PathList
func (c IntendedChange) PathList() stringPathList renders the declared paths in a stable order for an error message.
#RewriteIntent.Declare
func (ri *RewriteIntent) Declare(oldSHA string, paths []string, messageChanged bool)Declare records what the operation decided for one commit. Repeated calls for the same commit accumulate, so a transform that runs several steps (a blob map, then a hash remap) can declare each step as it happens.
#RewriteIntent.ChangedCommits
func (ri *RewriteIntent) ChangedCommits() []stringChangedCommits returns the OLD SHAs the operation declared a change in.
#RewriteIntent.For
func (ri *RewriteIntent) For(oldSHA string) IntendedChangeFor returns the declaration for one old commit; the zero declaration means "this commit's content is untouched".
#rewriteRefusal.Error
func (e *rewriteRefusal) Error() string { return e.msg }#RewriteResult.TierBExit
func (r *RewriteResult) TierBExit(prior int) intTierBExit returns the exit code the command should return. A Tier B finding means the rewrite stands but something after it did not complete, which is RewriteIncomplete; otherwise the caller's own code is preserved.
#RewriteResult.Finalize
func (r *RewriteResult) Finalize(ctx context.Context, flags globalFlags, cmd string, hooks RewriteHooks) errorFinalize runs the shared post-rewrite pipeline. The whole ordering exists to put every refusable check BEFORE the first irreversible act, which is the moment a ref moves:
1. Plan every ref update, writing the new tag objects the plan needs. Objects only -- nothing is reachable, nothing has moved. 2. TIER A, all hard refusals, original history untouched: a. the preservation check -- every rewritten commit against what the operation declared it would change, plus the rewrote-count tripwire; b. the command's own Tier A hook (content verification, pattern absence over the new commit set), which reads the plan; c. the cleanliness re-check under the rewrite lock -- foreign working tree or index state that appeared WHILE the rewrite ran. 3. Capture pre-rewrite remote-tracking state and persist the rewrite-map "start" record. From here on a crash is recoverable from the journal rather than invisible -- and an abort above never wrote one, so an aborted rewrite can never read as a crashed one. 4. Apply the ref update plan. THIS is the irreversible step. 5. Persist the rewrite-map "refs" record (all tag rewrites). 6. Re-check the working tree once more and either sync it to the new HEAD or SKIP the sync, printing what to do -- foreign staged state is never overwritten. 7. untrackProtectedPaths -- remove tracked-but-gitignored files from index 8. cleanupAfterRewrite -- expire tainted reflog entries, repack, prune 9. TIER B: stale-ref pointers plus the command's own hook. Findings are recorded and reported; the rewrite stands and the exit code turns nonzero via TierBExit. 10. Resolve the new HEAD and ref, persist the "complete" record, append the oplog entry, print the push hint.
Steps 1-2 are prepare; steps 3-10 are publish. The two halves are separate methods because a rewrite that spans TWO repositories -- a submodule scrub, which rewrites the submodule and then the parent gitlinks that point at it -- has to prepare BOTH before publishing EITHER. Finalize is the single-repository spelling of prepare-then-publish, and it is what every other rewrite calls.
#gitArgs.Has
func (a gitArgs) Has(names ...string) boolHas reports whether any of the named options is present. Names are matched exactly as spelled, so a caller asks for every spelling it cares about.
#gitArgs.Find
func (a gitArgs) Find(names ...string) (gitOption, bool)Find returns the first occurrence of any of the named options.