Skip to main content

Crate vcs_git

Crate vcs_git 

Source
Expand description

vcs-git — automate Git from Rust by driving the git CLI.

It shells out to the installed git binary and parses its output into typed values — so you get git’s own behaviour, config, and credential handling, not a reimplementation of the object format. Async throughout, structured errors, and mockable. Every command runs inside an OS job (via processkit) so a git subprocess tree can never be orphaned, and honours an optional per-client timeout.

§The surface

  • GitApi — the object-safe trait every operation lives on. Depend on &dyn GitApi (or generically on impl GitApi) so a test can swap the real client for a double. Methods take the working directory as the first argument and return typed results (StatusEntry, Branch, Commit, FileDiff, BlameLine, …) or a structured Error.
  • Git — the real client. Git::new uses the job-backed runner; Git::with_runner injects a fake one for tests. It is generic over the ProcessRunner seam, defaulting to the production runner.
  • GitAt — a cwd-bound view (Git::at) whose methods drop the leading dir, so git.at(dir).status() reads as git.status(dir) — handy when one client drives one checkout.
  • Builder specs for the multi-option commands — CommitPaths, MergeCommit / MergeNoCommit, GitPush, CloneSpec, WorktreeAdd, AnnotatedTag — each #[non_exhaustive], built with a constructor + chained setters, named after the flags they emit.
  • conflict — a typed conflict-marker model: parse marker soup into structured regions, re-render byte-exact, and resolve to a chosen side.
  • Git::hardened — a profile for untrusted repositories (hooks off, GIT_* scrubbed, system config skipped); see the guide::security guide.

§Recipes

Read state — depend on the trait so the same code takes a real client or a mock:

use std::path::Path;
use vcs_git::{Git, GitApi};
let git = Git::new();
let dir = Path::new(".");
let branch = git.current_branch(dir).await?;        // the checked-out branch
let dirty = !git.status(dir).await?.is_empty();     // any uncommitted change?

Mutate through the builder specs — fetch retries transient network failures:

use std::path::Path;
use vcs_git::{CommitPaths, Git, GitApi, GitPush};
let dir = Path::new(".");
git.fetch(dir).await?;
git.commit_paths(dir, CommitPaths::new(["src/a.rs"], "wip")).await?;
git.push(dir, GitPush::branch("feature").set_upstream()).await?;

§Testing

Two seams: enable the mock feature for a mockall-generated MockGitApi (stub whole methods), or inject a ScriptedRunner with Git::with_runner to exercise the real argv-building and parsing against canned output. The cross-cutting testing patterns live in vcs-testkit’s guide.

§Safety

Every caller value placed in a bare positional argv slot is refused before spawning if it is empty or starts with - (git would parse it as a flag); flag-value slots (-b <name>) are consumed verbatim and don’t need it. For eager validation at an input boundary, the RefName / RevSpec newtypes validate up front. Paths always go through -- / pathspec.

§In-depth guide

Beyond this page, this crate ships a full how-to guide — rendered on docs.rs from docs/. See the guide module (and its security / conflicts sub-guides).

Modules§

__mock_MockGitApi
__mock_MockGitApi_GitApi
blocking
Synchronous, best-effort helpers for contexts that cannot .await — chiefly a Drop guard. They shell out through std::process directly (no async, no job-containment), so reserve them for short-lived cleanup.
conflict
Typed model of git conflict markers — parse a conflicted file’s content into structured regions and write a chosen resolution back. Pure functions (no subprocess), so everything here is hermetic.
guide
vcs-git — Git CLI guide

Structs§

AnnotatedTag
Options for GitApi::tag_create_annotated (git tag -a).
BlameLine
One line of git blame --line-porcelain output: who last touched the line and where it came from.
Branch
A local branch from git branch.
BranchStatus
A combined branch + working-tree snapshot from git status --porcelain=v2 --branch -z: HEAD, branch, upstream tracking, ahead/behind, and change counts — everything a prompt/status-bar needs, in one process spawn.
CancellationTokencancellation
A token which can be used to signal a cancellation request to one or more tasks.
CloneSpec
Options for GitApi::clone_repo (git clone).
Commit
A commit, parsed from a \x1f-delimited git log line.
CommitPaths
Options for GitApi::commit_paths (git commit --only).
DiffStat
Aggregate line/file counts from a diff stat (git diff --shortstat, jj diff --stat).
FileDiff
One file’s entry in a parsed git-format unified diff (git diff or jj diff --git).
Git
The real Git client. Generic over the ProcessRunner so tests can inject a fake process executor; Git::new() uses the real job-backed runner.
GitAt
A Git client with a working directory bound, so calls drop the leading dir argument — git.at(dir).status() is git.status(dir). Construct one with Git::at (or, through the facade, vcs_core::Repo::git_at). Cheap to copy: it only borrows the client and the path.
GitCapabilities
What the installed git binary supports, probed via GitApi::capabilities. A value type — the client holds no state, so probe once and keep the result (callers cache it).
GitPush
Options for GitApi::push (git push).
GitVersion
A parsed CLI version (major.minor.patch). Ord compares numerically, so a caller can gate a feature on a minimum version; Hash lets it key a map (e.g. a per-version capability cache).
Hunk
A single @@ … @@ hunk within a FileDiff.
MergeCommit
Options for GitApi::merge_commit (git merge that commits the result).
MergeNoCommit
Options for GitApi::merge_no_commit (git merge --no-commit).
MockGitApi
The Git operations this crate exposes — the interface consumers code against and mock in tests.
ProcessResult
The captured result of running a process to completion.
RefName
A pre-validated git reference name (branch/tag/remote), for callers that accept names from untrusted input (UIs, bots, agents) and want to fail early with a clear error. The dir-taking methods stay &str — they apply the same flag-injection guard internally — so this type is optional up-front validation, not a required wrapper.
RevSpec
A pre-validated revision/range expression (HEAD~2, main..feature). Deliberately minimal — git’s revision grammar is too rich to validate here — it only guarantees the expression is non-empty and cannot be parsed as a flag (no leading -), matching the internal guard the dir-taking methods apply anyway. Optional up-front validation for untrusted input.
StatusEntry
One entry from git status --porcelain=v1 -z (XY <path>, NUL-delimited).
Worktree
A worktree from git worktree list --porcelain.
WorktreeAdd
Options for GitApi::worktree_add (git worktree add).

Enums§

ChangeKind
How a file changed in a unified diff.
DiffLine
One line inside a Hunk, tagged by its role. The stored text excludes the leading /+/- marker and the line terminator — a CRLF-origin diff’s trailing \r is stripped along with the \n, so reconstruct exact bytes from FileDiff::raw, not from these lines.
DiffSpec
What a GitApi::diff / GitApi::diff_text call compares.
Error
Errors produced when launching or running a child process.

Constants§

BINARY
Name of the underlying CLI binary this crate drives.
EMPTY_TREE
Git’s well-known empty-tree object id — a stable stand-in for HEAD when diffing the working tree of an unborn (no-commits-yet) repository. Public so a caller can diff/stat a pre-first-commit working tree against it directly.

Traits§

GitApi
The Git operations this crate exposes — the interface consumers code against and mock in tests.

Functions§

is_merge_conflict
Whether a failed merge/merge_commit stopped on a merge conflict. (jj surfaces conflicts as state rather than as errors, so this only fires on git output — see vcs_core::Error::is_merge_conflict.)
is_nothing_to_commit
Whether a failed commit/commit_paths reported nothing to commit (a clean tree), as opposed to a real error.
is_transient_fetch_error
Whether a failed fetch/fetch_remote_branch/remote_branch_exists looks transient (DNS, timeout, dropped connection) and is worth retrying.
parse_diff
Parse a git-format unified diff into one FileDiff per file. Works on git diff and jj diff --git output alike. Public so a consumer can parse diff text it obtained by other means.

Type Aliases§

Result
Crate result alias.