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 onimpl 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 structuredError.Git— the real client.Git::newuses the job-backed runner;Git::with_runnerinjects a fake one for tests. It is generic over theProcessRunnerseam, defaulting to the production runner.GitAt— a cwd-bound view (Git::at) whose methods drop the leadingdir, sogit.at(dir).status()reads asgit.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 theguide::securityguide.
§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_ Mock GitApi - __
mock_ Mock GitApi_ GitApi - blocking
- Synchronous, best-effort helpers for contexts that cannot
.await— chiefly aDropguard. They shell out throughstd::processdirectly (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§
- Annotated
Tag - Options for
GitApi::tag_create_annotated(git tag -a). - Blame
Line - One line of
git blame --line-porcelainoutput: who last touched the line and where it came from. - Branch
- A local branch from
git branch. - Branch
Status - 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. - Cancellation
Token cancellation - A token which can be used to signal a cancellation request to one or more tasks.
- Clone
Spec - Options for
GitApi::clone_repo(git clone). - Commit
- A commit, parsed from a
\x1f-delimitedgit logline. - Commit
Paths - Options for
GitApi::commit_paths(git commit --only). - Diff
Stat - Aggregate line/file counts from a diff stat (
git diff --shortstat,jj diff --stat). - File
Diff - One file’s entry in a parsed git-format unified diff (
git difforjj diff --git). - Git
- The real Git client. Generic over the
ProcessRunnerso tests can inject a fake process executor;Git::new()uses the real job-backed runner. - GitAt
- A
Gitclient with a working directory bound, so calls drop the leadingdirargument —git.at(dir).status()isgit.status(dir). Construct one withGit::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
gitbinary supports, probed viaGitApi::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).Ordcompares numerically, so a caller can gate a feature on a minimum version;Hashlets it key a map (e.g. a per-version capability cache). - Hunk
- A single
@@ … @@hunk within aFileDiff. - Merge
Commit - Options for
GitApi::merge_commit(git mergethat commits the result). - Merge
NoCommit - Options for
GitApi::merge_no_commit(git merge --no-commit). - Mock
GitApi - The Git operations this crate exposes — the interface consumers code against and mock in tests.
- Process
Result - 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. - Status
Entry - One entry from
git status --porcelain=v1 -z(XY <path>, NUL-delimited). - Worktree
- A worktree from
git worktree list --porcelain. - Worktree
Add - Options for
GitApi::worktree_add(git worktree add).
Enums§
- Change
Kind - How a file changed in a unified diff.
- Diff
Line - 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\ris stripped along with the\n, so reconstruct exact bytes fromFileDiff::raw, not from these lines. - Diff
Spec - What a
GitApi::diff/GitApi::diff_textcall 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
HEADwhen 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_commitstopped on a merge conflict. (jj surfaces conflicts as state rather than as errors, so this only fires on git output — seevcs_core::Error::is_merge_conflict.) - is_
nothing_ to_ commit - Whether a failed
commit/commit_pathsreported 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_existslooks transient (DNS, timeout, dropped connection) and is worth retrying. - parse_
diff - Parse a git-format unified diff into one
FileDiffper file. Works ongit diffandjj diff --gitoutput alike. Public so a consumer can parse diff text it obtained by other means.
Type Aliases§
- Result
- Crate result alias.