gitutil

package
v0.13.3 Latest Latest
Warning

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

Go to latest
Published: Oct 8, 2026 License: MIT Imports: 12 Imported by: 0

Documentation

Overview

Package gitutil holds the shared, isolated git queries. It is transport-agnostic: no stdout, no os.Exit, no CLI knowledge.

Every git invocation here neutralises global and system config, so a developer's ~/.gitconfig or ~/.gitignore can never change what abcd reports about a repository. Queries fail open — when git is unavailable or the directory is not a repository, nothing is claimed rather than an error raised, so a convention check degrades to "cannot tell" instead of asserting a violation it has no evidence for.

Index

Constants

This section is empty.

Variables

View Source
var ErrNoCheckoutRoot = errors.New("no checkout root")

ErrNoCheckoutRoot is CheckoutRoot's refusal: there is no checkout whose record store the caller's working directory belongs to, so there is no store to address. A surface maps it to an exit code and its own wording; this package never prints.

View Source
var ErrShallowCheckout = errors.New("shallow checkout")

ErrShallowCheckout is RequireFullHistory's refusal: the checkout is shallow, so history past the graft is absent.

View Source
var ErrToplevelShape = errors.New("git's toplevel answer is not one absolute path containing the directory asked about")

ErrToplevelShape is Toplevel's refusal of an answer git would never give.

Functions

func CheckIgnored

func CheckIgnored(root string, candidates []string) map[string]struct{}

CheckIgnored returns the subset of repo-relative candidates that git actually ignores, via a single isolated `git check-ignore -z -v --stdin`. Batching keeps one subprocess for an arbitrary number of paths.

The index is consulted (no `--no-index`), so this mirrors git's real ignore decision: git never ignores a tracked file, even one force-added against a matching pattern — reporting such a path as ignored would invert the answer for callers asking "is this file committed-durable?" or "must this be excluded from the release bundle?".

A negation record (a pattern beginning `!`) un-ignores its path and so does not count as ignored. When git is unavailable or root is not a repository the result is empty (fail open).

func CheckoutRoot added in v0.8.0

func CheckoutRoot(cwd, store string) (string, error)

CheckoutRoot answers the question every front door onto a repository-scoped record store has to ask before it builds a request: which checkout's store does a caller standing in cwd address?

It is the ONE resolution for that question, and it exists because two front doors skipped asking it and reached the same failure independently. The capture verbs handed their working directory to the ledger core as an explicit repo root, so a verb run from a subdirectory addressed a ledger that was not there: a read reported open 0 against a populated checkout, and a write minted a second ledger under the subdirectory and reported success with a repo-relative path that looked ordinary (iss-2609090951291524). `decide` did the same to the decision store, and one directory further out: run outside every repository it exited 0 and laid a full ADR store in whatever plain directory the caller stood in (iss-2609091707224329). The resolution is store-agnostic, so it lives here rather than in either store's package, and `store` — a noun phrase naming what is being addressed, "the issue ledger", "the decision store" — is the ONLY thing that varies between callers.

Three outcomes, and only the first is a root:

  • git names a toplevel: that is the answer, whoever owns the checkout.
  • git will not answer for a repo-SHAPED tree (git absent from PATH, a corrupt .git, an ownership refusal under the isolated env, or an answer Toplevel refuses for its shape, which a core.worktree setting naming a tree that does not contain cwd produces): REFUSED, naming that git could not answer. RepoShapedRoot is read here as a CLASSIFIER and never as a root: it is a marker walk, which accepts any directory merely carrying the name and has neither the shape check nor the ownership gate the rules-root resolver grew (iss-2609090947359464), so returning its answer is the one change that would make that walk live. A store addressed by a guess is the defect this function closes, one directory further out.
  • nothing repo-shaped anywhere above: REFUSED. Laying a store in whatever directory the caller stood in is not a lenient fallback — the records would sit outside any checkout, committed by nothing and read by nothing, which is the same lost trail this resolution exists to prevent. Every store this resolves for is per-repository by definition.

func CommandLineConfig added in v0.11.1

func CommandLineConfig() []string

CommandLineConfig is the `git -c` configuration the parent environment carries — GIT_CONFIG_PARAMETERS and the GIT_CONFIG_COUNT/GIT_CONFIG_KEY_n/ GIT_CONFIG_VALUE_n form, the entries ScrubbedEnv strips — as "KEY=value" entries, in environment order. git hands exactly these to a command it runs (a hook, an alias), so a reader that must see the configuration git itself is running with appends them to ScrubbedEnv for its own command; no other caller's scrub changes.

func DefaultRef added in v0.11.1

func DefaultRef(root string) string

DefaultRef is the full ref name of the repository's default branch as last fetched, with no network: origin/HEAD's target, then the conventional names on the remote, then the same names locally. "" when none resolves.

It is the one resolution the readers that measure against the default branch share: the peers reader judges a branch merged into it, and the reviews board counts the commits it has moved since a review's pin. Two readers of one repository asking the same question must get one answer.

func HooksPaths added in v0.13.0

func HooksPaths(root string) ([]string, error)

HooksPaths is every core.hooksPath value git reads for the repository at root, from each scope it reads (system, global, the repository's, the worktree's), in that order and path-expanded (a leading ~ is the home), as git writes them: a relative value is relative to the working tree's root.

It is read as the person's own git reads it, so it runs under ScrubbedEnv (global and system config in force) and never under the isolated environment, whose -c core.hooksPath=/dev/null would answer for itself. Reading configuration runs no hook and starts no fsmonitor. None set is an empty answer; a git that cannot answer is an error.

func IgnoredUnder added in v0.11.1

func IgnoredUnder(root, rel string) []string

IgnoredUnder lists the untracked paths git ignores beneath the repo-relative directory rel, in ONE isolated `git ls-files --others --ignored --exclude-standard --directory` call. A wholly ignored directory is reported once, as its own path with a trailing slash, rather than file by file, so a caller walking the tree can prune it without descending. Only untracked paths are listed: git never ignores a tracked file, so a committed file a pattern happens to match is not reported and stays the caller's to read. Paths are relative to root, slash-separated, and sorted.

Like CheckIgnored it neutralises core.excludesFile, so a developer's personal ignore file cannot change what abcd reads, and it fails open: when git is unavailable or root is not a repository the result is empty.

func InRepo

func InRepo(root string) bool

InRepo reports whether root is inside a git working tree. A convention rule uses it to tell "git says this path is not ignored" apart from "git cannot answer" (git absent, or not a repo) — the latter is "cannot tell", never "compliant".

func IsAncestor added in v0.6.8

func IsAncestor(root, ancestor, descendant string) (bool, error)

IsAncestor reports whether ancestor is an ancestor of (or equal to) descendant under root, via `git merge-base --is-ancestor`. git encodes the answer in the exit status — 0 is "yes", 1 is "no", and anything else (128 for a bad object, a missing repository) is a real failure — so a bare Run cannot be used: it folds the informative 1 into a generic error. A caller deriving a release's content commit from the receipts directory needs the three outcomes kept apart: "yes" selects a candidate, "no" skips it, and only a genuine git failure is fatal.

func IsFullSHA added in v0.10.0

func IsFullSHA(s string) bool

IsFullSHA reports whether s is a full object name as RootCommit returns one. The machine-scoped stores key a directory on the root commit, so the check is what keeps a value that arrived any other way from becoming a path segment.

func IsIgnored

func IsIgnored(root, path string) bool

IsIgnored reports whether a single repo-relative path is ignored by git. It is CheckIgnored for the one-path case; prefer CheckIgnored when asking about several paths, to keep it to one subprocess.

func IsNullOID added in v0.11.1

func IsNullOID(s string) bool

IsNullOID reports whether s is git's all-zeroes object name, under SHA-1 or SHA-256. A forge hands it to a range gate when a push has no predecessor to name — a branch the push created, or a force-push whose old tip it declines to cite. It is well formed and resolves to nothing.

func IsolatedEnv

func IsolatedEnv() []string

IsolatedEnv returns the child environment an isolated git command runs with: the parent environment scrubbed of every repo-selection and config-injection variable (GIT_DIR, GIT_WORK_TREE, GIT_CONFIG_*, …), plus the config-file neutralisers. A front door that must run a git command this package does not already wrap — a probe needing --stdin, say — uses this instead of os.Environ() so it inherits the same isolation as Run/RunLimited. Reaching for os.Environ() directly lets an inherited GIT_DIR/GIT_WORK_TREE silently redirect the command at a DIFFERENT repository, which for a secret-hygiene gate is a real vulnerability.

func ProveOperandDir added in v0.11.1

func ProveOperandDir(operand string) error

ProveOperandDir proves an operand directory a person named on a command line — a lifeboat, an embark target, a pack destination, an --out directory — against a symlinked ANCESTOR, which a leaf-only fsutil.IsRealDir cannot see.

The operand's declared base is the checkout it sits in: a checkout is the one place an untrusted commit can plant a link (a committed symlink beats .gitignore), so every level from that checkout's root down to the operand is proved a real directory with fsutil.ProbeRealDirAll, the read-only walk the local tier and the inbox use. A missing level ends the proof: nothing below it exists to be redirected, and a destination the verb creates starts there.

The checkout root's own entry lives in the directory above it, so it is proved by the next round rather than this one: the proof moves out to the checkout enclosing that root, if any, and proves the chain down to it the same way. That is what refuses a committed link pointing INTO another checkout, which a proof stopping at the nearest .git would take as its base.

Outside every checkout the path is the operator's own, taken as given under the trusted-worktree model: refusing there would refuse macOS's /var and /tmp links and every temporary directory, and protect nothing. The checkout is found with the .git marker walk (RepoShapedRoot) rather than git's answer: a marker read too widely only makes the proof stricter.

A refusal is an *OperandError whose Level is relative to its Checkout, which is the checkout's absolute path; a caller reporting it names the checkout by its base name, never the absolute path.

The operand is absolutised against the working directory first, whatever the caller passed: a relative path's marker walk ends at "." and never reaches the checkout above it, which would accept a link the proof exists to refuse, so the contract is held here rather than trusted to every caller (iss-2609262235543552).

func RefIsSafe added in v0.11.1

func RefIsSafe(ref string) bool

RefIsSafe reports whether a ref is safe to hand git as a POSITIONAL argument: non-empty and not option-shaped. A ref beginning with '-' parses as a flag — `--output=<path>` on a diff writes a file, `--upload-pack=<cmd>` on a fetch runs one — and no legitimate ref name starts with one, so refusing them drops only hostile or mistyped input. Every caller that interpolates a ref it did not write itself (a CI base sha, a user-named branch, a ref read out of a repository) checks it here first.

func RepoShaped added in v0.6.7

func RepoShaped(root string) bool

RepoShaped reports whether root sits anywhere inside a tree carrying a .git entry — a directory, or the file a worktree or submodule leaves. It is deliberately cruder than InRepo: its job is to tell "not a repository" apart from "a repository git would not answer for" (git absent from PATH, a corrupt .git, an ownership refusal under the isolated env). Only the first is safe to treat as "nothing is tracked here"; the others can commit, and nothing can say what git would answer.

It walks to the filesystem root, because git does: checking root alone answers "not a repository" for every SUBDIRECTORY of one.

func RepoShapedRoot added in v0.7.1

func RepoShapedRoot(root string) string

RepoShapedRoot is RepoShaped's walk with its answer kept: the nearest directory at or above root carrying a .git entry, or "" when there is none. It is the toplevel a caller can still bound work at when git itself will not name one — the ownership refusal under the isolated env, git absent from PATH, a corrupt .git — where the alternative is treating a real working tree as an unbounded directory.

It is a MARKER, not git's answer: it does not read .git, so it cannot tell a valid repository from a directory that merely holds the name, and for a submodule or linked worktree it reports the tree the .git file sits in (which is the working-tree root a config walk wants). A caller that needs git's own answer must ask git.

func RequireFullHistory added in v0.11.1

func RequireFullHistory(root string) error

RequireFullHistory refuses a shallow checkout. A gate that compares commits with their parents is blinded by one: past the graft a commit's parent is not present, so every change reads as a whole-file add and the check covers nothing. The probe is itself fail-closed — a git that cannot say whether the checkout is shallow is an error, never an assumed "full".

func ResolveCommit added in v0.11.1

func ResolveCommit(root, ref string) (string, error)

ResolveCommit resolves ref to the full object name of the commit it names, refusing an option-shaped ref before git sees it.

func ResolveRangeBase added in v0.11.1

func ResolveRangeBase(root, raw string) (string, bool, error)

ResolveRangeBase is the one derivation of the base a range-scoped gate checks from. raw is whatever the caller was handed — a CI event's base sha, or a ref a developer named — and there are three outcomes:

  • raw is empty (after trimming) or the null object name: there is no usable base for this event. It returns ("", false, nil), and the caller SAYS it skipped; it never reads the empty range as a clean one.
  • raw resolves to a commit: it returns that commit's full object name.
  • anything else — an option-shaped value, a name no commit answers to, a repository git cannot read — is an error. A base a gate cannot resolve is one it cannot judge from, and the error is the "refusing rather than reporting a vacuous pass" answer, never a quiet downgrade.

It exists so the zero-sha and absent-commit guard lives once, in Go, rather than hand-copied into every workflow step that runs a range gate.

func RevParseAbsPath added in v0.12.0

func RevParseAbsPath(dir, flag string) (string, error)

RevParseAbsPath asks `git rev-parse --path-format=absolute <flag>` for one path (--git-dir, --git-common-dir, --show-toplevel) and refuses any answer that is not exactly one absolute line. --path-format arrived in git 2.31: an older rev-parse echoes the option it does not know to stdout and exits 0, so its answer is the flag's text and a path on two lines, which a caller that compared it would read as a path. Refusing it keeps a resolution on an old git failing closed where it compares, never on a string that only looks like an answer.

func RootCommit added in v0.6.9

func RootCommit(root string) string

RootCommit returns the repository's canonical (first) root-commit SHA, or "" when it cannot be derived — git absent, not a repository, no commits. It is total: a caller keying a store or a marker on the repository's identity gets "" rather than an error, and decides for itself what an unidentified repository means. A repository can have several root commits (an octopus of unrelated histories); the first `rev-list` reports is the canonical one, the same choice the history registry and the lifeboat probe make.

The output is bounded (one object name, so the cap is generous) rather than buffered whole: a hostile repository must not be able to make an identity probe allocate.

func RootCommitContext added in v0.13.1

func RootCommitContext(ctx context.Context, root string) (string, error)

RootCommitContext is RootCommit bound to ctx: the same answer, total in the same way, except that a context that ends before git answers is returned as its own error (wrapped) with git killed — so a caller on a deadline can tell "this repository has no root commit" from "git did not answer in time".

func Run

func Run(root string, args ...string) (string, error)

Run executes a read-only git command under root with the developer's global and system config neutralised, returning trimmed stdout. It is the shared primitive for tooling that reads git history (the lifeboat probe's Tier-0 adapters); centralising it keeps every caller on the same isolated environment rather than re-deriving the exec plumbing. An error (git absent, not a repo, a failing subcommand) is returned verbatim so the caller can decide whether "git cannot answer" degrades to empty or is fatal.

func RunCapped

func RunCapped(root string, maxBytes int, args ...string) (string, error)

RunCapped is RunLimited for callers whose answer is only correct if it is COMPLETE. It returns an error rather than a truncated string when git's output exceeds maxBytes.

The distinction is the whole reason both exist. A truncated `git log` is not a shorter history; it is a wrong one, and a caller that cannot tell the two apart will publish the wrong one with no sign that anything was dropped. RunLimited's callers (the lifeboat probe over an archived repository) would genuinely rather have a partial answer than none, and keep that behaviour.

func RunCappedBytes added in v0.11.1

func RunCappedBytes(root string, maxBytes int, args ...string) ([]byte, error)

RunCappedBytes is RunCapped without the trim: git's stdout exactly as written, or an error when it exceeds maxBytes. It is for a caller that reads FILE CONTENT through git — a blob's trailing blank lines and its last line's trailing whitespace are content, and a trimmed blob has a different line count from the committed one.

func RunLimited

func RunLimited(root string, maxBytes int, args ...string) (string, error)

RunLimited is Run with a hard cap on how much stdout is buffered. A hostile or archived repository can make a read-only command (a full `git log`) emit arbitrarily much output; the unbounded `Output()` would buffer all of it. The probe uses this so a giant history cannot exhaust memory — output past maxBytes is discarded (the last retained line may be truncated, which degrades a single probe rather than crashing it). On failure the error carries git's bounded stderr — the reason, not just the exit status.

func RunLimitedContext added in v0.13.1

func RunLimitedContext(ctx context.Context, root string, maxBytes int, args ...string) (string, error)

RunLimitedContext is RunLimited bound to ctx: when ctx ends before git answers, git is killed (isolatedGitContext) and the error wraps ctx's own, so errors.Is(err, context.DeadlineExceeded) tells a caller that git did not answer in time rather than that it said no. It is the one primitive every deadline-bound git question goes through.

func ScrubbedEnv

func ScrubbedEnv() []string

ScrubbedEnv is IsolatedEnv without the global/system config-file neutralisers: the parent environment with every repo-selection and config-injection variable stripped (GIT_DIR, GIT_WORK_TREE, GIT_INDEX_FILE, GIT_CONFIG_COUNT/PARAMETERS/ KEY_*/VALUE_*, …) but with ~/.gitconfig and the system config still in effect. It is for a git command that MUST honour the developer's real global config — the identity probe reads user.name/user.email to redact the caller's OWN identity, and those overwhelmingly live in global config, so suppressing it (as IsolatedEnv does) would blind the probe and silently stop redacting a real identity leak. Scrubbing still defeats the two attacks that matter here: an inherited GIT_DIR redirecting the probe at a different repository, and an injected GIT_CONFIG_* forging a fake identity that displaces the real one.

func ShortRef added in v0.11.1

func ShortRef(ref string) string

ShortRef renders a full ref the way a person names it: origin/main for a remote-tracking ref, main for a local branch.

func Toplevel added in v0.11.1

func Toplevel(dir string) (string, error)

Toplevel asks git for the working-tree root that contains dir, and holds the answer to the one shape git ever gives: a single absolute line naming a directory at or above dir. Anything else (relative, several lines, empty, a directory elsewhere) is refused with ErrToplevelShape rather than handed on as a root, because every caller bounds work at the answer: it is where a ledger, a rules file or a site is read and written. It is the one call every `rev-parse --show-toplevel` in the module goes through, so the rule is kept once (iss-2608292038186663).

A git failure (not a repository, git absent, an ownership refusal under the isolated environment) is returned as git's own error; a caller that must tell "no repository" from "a repository git will not answer for" follows up with RepoShapedRoot.

func ToplevelContext added in v0.13.1

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

ToplevelContext is Toplevel bound to ctx, for a caller on a deadline (the status verb): the same question and the same shape check, with git killed when ctx ends and the context's own error returned (RunLimitedContext), so the caller can tell a slow git from "not a repository".

func ToplevelShaped added in v0.11.1

func ToplevelShaped(dir, top string) bool

ToplevelShaped reports whether top has the shape of git's toplevel answer for dir: one absolute line naming a directory that contains dir. It is Toplevel's check, for the callers that must run git themselves (a command that pins the git binary it runs, or asks for the path in another format).

func TrackedFiles

func TrackedFiles(root string) ([]string, error)

TrackedFiles returns the repo-relative paths git tracks under root, NUL-safe so a filename with a newline cannot desync the list. Outside anything repo-shaped it returns no files and no error — a scan over committed files then degrades to "nothing to scan" rather than failing. In a repo-shaped tree git cannot answer for, and inside a repo on any other ls-files failure (a corrupt index, say), it returns an error, so a caller cannot mistake "could not read the repository" for "nothing tracked" and report a scanning rule compliant after reading zero files.

Types

type ArchiveEntry added in v0.11.1

type ArchiveEntry struct {
	Path string
	Mode string
}

ArchiveEntry is one file `git archive` would write for a revision: its repo-relative path and its git mode (100644, 100755 or 120000 for a link).

func ArchiveTree added in v0.11.1

func ArchiveTree(root, rev string) ([]ArchiveEntry, error)

ArchiveTree lists the files an archive of rev would carry — the release tag's view of the tree — without running `git archive` itself. `git archive` applies the repository's filter drivers, and a checkout's own .git/config is fully trusted by git, so the listing is built from the two commands that run no configured program: `ls-tree` for the committed files, and `check-attr` for the export-ignore attribute archive honours, asked of each file and of every directory above it (an ignored directory drops everything beneath it). A directory is asked as `dir/`, the form archive itself asks: only a path that ends in a slash matches the directory-only pattern (`dir/ export-ignore`), a bare pattern (`dir export-ignore`) matches it too, and where the two forms disagree (`dir export-ignore` then `dir/ -export-ignore`) the answer for `dir/` is the one archive acts on. Asking `dir` as well would drop a directory archive keeps, and the scan would miss files the tag ships. Submodules are skipped: archive carries no submodule content.

Attributes are read from rev's own .gitattributes, the files git archive reads, so neither a working-tree edit nor a staged one changes the answer (iss-2609260933592838). Where the index holds exactly rev's .gitattributes they are asked of the index (--cached), which every git answers; where they differ they are asked of rev itself (--source, git 2.40 or later), and a git that cannot is refused by name rather than answered from the index. An error is a tree git could not list — no commit at rev, not a repository, git absent — and is never reported as an empty tree.

type OperandError added in v0.11.1

type OperandError struct {
	Checkout string
	Level    string
	Err      error
}

OperandError is ProveOperandDir's refusal: Level, a directory inside the checkout rooted at Checkout and named relative to it, could not be proved a real directory. Err is the cause with no path in it (fsutil.ErrNotRealDir for a symlink or a non-directory), so a caller tests the class with errors.Is and phrases the message itself; Checkout is absolute and is for the caller to shorten, never to print whole.

func (*OperandError) Error added in v0.11.1

func (e *OperandError) Error() string

func (*OperandError) Unwrap added in v0.11.1

func (e *OperandError) Unwrap() error

type StatusEntry added in v0.13.0

type StatusEntry struct {
	// XY is the entry's two status columns as git writes them: "??" an
	// untracked path, "!!" an ignored one, otherwise the index column and the
	// working-tree column.
	XY string
	// Path is the path as git reports it, relative to the repository's root
	// and verbatim (the -z form never quotes or escapes it). A path git
	// reports whole as a directory ends in "/": an ignored directory under
	// StatusOptions.Ignored, or an untracked nested repository.
	Path string
	// Orig is a rename's or a copy's source path, and empty for every other
	// entry.
	Orig string
}

StatusEntry is one entry of git's NUL-separated status listing (`git status --porcelain=v1 -z`).

func ParseStatus added in v0.13.0

func ParseStatus(out []byte) []StatusEntry

ParseStatus parses git's NUL-separated status listing.

The -z form is what makes it parseable: each entry is NUL-terminated and its path is never quoted or escaped, so a filename holding a space, a quote or a newline arrives verbatim and core.quotePath cannot change the format under the parser. A rename's or a copy's source follows its entry as a record of its own, and either column can declare one (`R ` a staged rename, ` R` a working-tree one); it is carried as Orig, never read as an entry.

func Status added in v0.13.0

func Status(root string, maxBytes int, opt StatusOptions) ([]StatusEntry, error)

Status is the working tree's status under root, as git lists it: `git --no-optional-locks status --porcelain=v1 -z --untracked-files=all`, run through the isolated environment and refused, never truncated, past maxBytes. It is the one reader of that listing; a caller that needs a variant adds it to StatusOptions.

--untracked-files=all is fixed: under git's default an untracked directory collapses to one entry, and a file inside a new directory is never named. --no-optional-locks keeps the read from refreshing the index, which the isolated environment's GIT_OPTIONAL_LOCKS=0 already does; it is stated on the command so the read stays read-only whatever environment runs it.

type StatusOptions added in v0.13.0

type StatusOptions struct {
	// Ignored lists ignored paths too (--ignored=matching): a file that
	// matches an ignore pattern by itself, and a directory that matches one
	// as the directory alone, never what is inside it.
	Ignored bool
	// Pathspecs, when any, narrows the listing to them.
	Pathspecs []string
}

StatusOptions are the variants of the status listing Status runs.

type Worktree added in v0.10.0

type Worktree struct {
	Path   string
	Head   string // the object name HEAD points at; "" for a bare entry
	Branch string // the full ref ("refs/heads/…"); "" when detached or bare
	Bare   bool
}

Worktree is one record of `git worktree list --porcelain`: a working tree this repository knows about, as git names it.

func ListWorktrees added in v0.10.0

func ListWorktrees(root string, maxBytes int) ([]Worktree, error)

ListWorktrees lists every working tree of the repository at root, the main one first (git documents that order), with its output capped at maxBytes as RunCapped caps it.

It asks for the NUL-separated form first, which is the only one that carries a path holding a newline intact, and falls back to the newline-separated form when git refuses it: `-z` arrived in git 2.36, and a git older than that (the 2.34 an LTS distribution still ships) answers "unknown switch" and exit 129. Falling back on any refusal rather than on that exact message keeps the fallback independent of how a given git words it; a failure the older form shares (not a repository, the cap exceeded) fails there too and is returned. The newline form is exact for every path without a newline in it, which is the only limit it carries.

func ParseWorktreeList added in v0.10.0

func ParseWorktreeList(out, sep string) []Worktree

ParseWorktreeList parses the porcelain output of `git worktree list`, whose attributes are separated by sep: "\x00" for the -z form, "\n" otherwise. A record opens at its `worktree <path>` attribute; an attribute before the first record, and one this reader does not use (locked, prunable, detached), is ignored.

Jump to

Keyboard shortcuts

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