Documentation
¶
Overview ¶
Package gitclient is a small exec-based Git client used by the filter, diff/merge drivers, the pre-push hook, and setup/upgrade. It never links a Git library: every call shells out to the installed `git`, runs with an explicit environment, captures stderr, and returns typed errors so callers can distinguish "git failed" from "git is missing" from "context cancelled".
The client is deliberately narrow: it exposes only the plumbing FXVCS needs and never runs a porcelain command that could prompt, page, or open an editor.
Index ¶
- Variables
- func BatchPaths(paths []string, callEmpty bool, fn func(batch []string) error) error
- func IsLockContention(err error) bool
- type Attrs
- type Client
- func (c *Client) Available() bool
- func (c *Client) CatFileBlob(ctx context.Context, name string) ([]byte, error)
- func (c *Client) CatFileBlobTo(ctx context.Context, name string, w io.Writer) error
- func (c *Client) CheckAttr(ctx context.Context, path string) (Attrs, error)
- func (c *Client) CheckAttrs(ctx context.Context, paths []string) (map[string]Attrs, error)
- func (c *Client) ConfigGet(ctx context.Context, key string) (value string, ok bool, err error)
- func (c *Client) ConfigSet(ctx context.Context, key, value string) error
- func (c *Client) ConfigUnset(ctx context.Context, key string) error
- func (c *Client) DiffTreePaths(ctx context.Context, commit string) ([]string, error)
- func (c *Client) GitCommonDir(ctx context.Context) (string, error)
- func (c *Client) GitDir(ctx context.Context) (string, error)
- func (c *Client) GitPath(ctx context.Context, name string) (string, error)
- func (c *Client) HashObject(ctx context.Context, r io.Reader, write bool) (string, error)
- func (c *Client) Locations(ctx context.Context) (top, gitDir, commonDir string, err error)
- func (c *Client) LsFilesStage(ctx context.Context, path string) ([]StageEntry, error)
- func (c *Client) RevList(ctx context.Context, args ...string) ([]string, error)
- func (c *Client) RevParse(ctx context.Context, arg string) (string, error)
- func (c *Client) Run(ctx context.Context, args ...string) ([]byte, error)
- func (c *Client) RunBatched(ctx context.Context, prefix []string, paths []string) ([]byte, error)
- func (c *Client) RunInput(ctx context.Context, stdin io.Reader, args ...string) ([]byte, error)
- func (c *Client) RunRetry(ctx context.Context, rt Retry, args ...string) ([]byte, error)
- func (c *Client) RunStreams(ctx context.Context, stdin io.Reader, stdout io.Writer, args ...string) error
- func (c *Client) RunString(ctx context.Context, args ...string) (string, error)
- func (c *Client) TopLevel(ctx context.Context) (string, error)
- func (c *Client) Version(ctx context.Context) (string, error)
- func (c *Client) WithDir(dir string) *Client
- func (c *Client) WithEnv(env []string) *Client
- type Error
- type Retry
- type StageEntry
Constants ¶
This section is empty.
Variables ¶
var ( // ErrGitNotFound is returned when the git executable cannot be located. ErrGitNotFound = errors.New("gitclient: git executable not found") // ErrNotRepository is returned when a command runs outside a Git repository. ErrNotRepository = errors.New("gitclient: not a git repository") )
Errors.
var DefaultRetry = Retry{Attempts: 5, Backoff: 100 * time.Millisecond}
DefaultRetry waits out an ordinary collision — roughly 1.5s across five attempts — without turning a genuinely stuck lock into a long stall.
var ErrLockContention = errors.New("gitclient: git index or ref lock is held by another process")
ErrLockContention is the transient class: another process held Git's index or a ref lock for the moment we asked.
FXVCS has no daemon. The CLI, the desktop application, the editor's Git integration and whatever else the operator runs all drive `git` against one worktree at the same time, so a collision on $GIT_DIR/index.lock is an ordinary event on a healthy machine rather than a failure worth reporting. The holder releases it in milliseconds; waiting is the whole remedy.
Functions ¶
func BatchPaths ¶
BatchPaths splits paths into command-line-sized batches and calls fn once per batch, in order. An empty list calls fn once with no paths only when callEmpty is set, which is what a "no pathspec means everything" command needs. The first error stops the walk.
func IsLockContention ¶
IsLockContention reports whether err is a failed invocation that could succeed on a retry because someone else held a Git lock.
It matches on Git's own message because Git offers nothing better: every one of these exits 128 with a message naming the lock file, and exit codes alone cannot tell "someone else is mid-commit" from "your pathspec is wrong". The match is deliberately narrow — a lock file by name — so that a real failure is never retried into a delay.
Types ¶
type Attrs ¶
Attrs holds the effective FXVCS-relevant attributes of one path. Each value is one of: the attribute value, "set", "unset", or "unspecified", exactly as git check-attr reports them.
type Client ¶
type Client struct {
// Dir is the working directory for every command ("" = process cwd).
Dir string
// Env is the complete environment for git. nil inherits the process
// environment. Tests pass an isolated environment (HOME, GIT_CONFIG_*).
Env []string
// Executable overrides the git binary ("" = "git" from PATH).
Executable string
}
Client runs git in a fixed directory with a fixed environment.
func (*Client) CatFileBlob ¶
CatFileBlob returns the raw bytes of a blob given any object name (oid, ":path" for the index, "<rev>:path").
func (*Client) CatFileBlobTo ¶
CatFileBlobTo streams a blob to w.
func (*Client) CheckAttr ¶
CheckAttr returns filter/diff/merge/text attributes for a repo-relative path.
func (*Client) CheckAttrs ¶
CheckAttrs is CheckAttr for many paths (one git process, -z --stdin).
func (*Client) ConfigGet ¶
ConfigGet reads a key using git's normal precedence. ok is false when unset.
func (*Client) ConfigUnset ¶
ConfigUnset removes a repository-local key (no error if absent).
func (*Client) DiffTreePaths ¶
DiffTreePaths returns the paths added or modified by commit relative to its first parent (or everything for a root commit).
func (*Client) GitCommonDir ¶
GitCommonDir returns $GIT_COMMON_DIR (absolute; equals GitDir outside linked worktrees).
func (*Client) GitPath ¶
GitPath resolves `git rev-parse --git-path <name>` (e.g. "fxvcs", "hooks", "info/exclude") to an absolute path, honoring worktrees and core.hooksPath.
func (*Client) HashObject ¶
HashObject returns the Git blob id of r; write=true also stores it.
func (*Client) Locations ¶
Locations resolves the working-tree root, $GIT_DIR and $GIT_COMMON_DIR in a single invocation.
It exists because opening a repository needed all three and asked for them one at a time. Every Git question costs a process, and on an interactive caller that opens a repository per request those three spawns are paid before any work begins — on macOS and Windows that is most of what a small query costs. rev-parse answers all three in argument order for the price of one.
func (*Client) LsFilesStage ¶
LsFilesStage returns the index entries for a path (0 = merged; 1/2/3 during a conflict). ok is false when the path is not in the index.
func (*Client) Run ¶
Run executes git with args and returns stdout. Stderr is captured into the returned *Error on failure.
func (*Client) RunBatched ¶
RunBatched runs `git <prefix...> <batch...>` once per path batch and concatenates the outputs. Use it for any command whose path list comes from the repository rather than from a fixed set.
func (*Client) RunRetry ¶
RunRetry is Run for a command that may be run again unchanged, retrying while another process holds the Git index or a ref lock.
Only idempotent commands may use it: it cannot tell a command that did nothing from one that did its work and then failed to write the index.
func (*Client) RunStreams ¶
func (c *Client) RunStreams(ctx context.Context, stdin io.Reader, stdout io.Writer, args ...string) error
RunStreams executes git streaming stdout to w (bounded memory for large blobs). Stderr is always captured.
type Error ¶
Error is a failed git invocation. Stderr is captured verbatim (trimmed) so callers can surface Git's own message.