Skip to main content

Crate vcs_git

Crate vcs_git 

Source
Expand description

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

You call typed async methods; vcs-git runs the real git, parses its output, and hands you structured values — so you get git’s own behaviour, config, and credentials, not a reimplementation of the object format. Async, structured errors, mockable. Every command runs inside an OS job (an OS-level container that kills the whole process tree if your program exits, via processkit) so a git subprocess is never orphaned, with an optional per-client timeout.

§What you can do

Status & branches · stage, commit, checkout · diff & log · merge / rebase / reset · worktrees · tags · blame · clone · config · cherry-pick / revert · parse & resolve conflict markers · a hardened (hooks-off) profile for untrusted repos. One tiny call to start:

use std::path::Path;
use vcs_git::{Git, GitApi};
let git = Git::new();
// `current_branch` is `Option` — `None` on a detached HEAD.
println!("{:?}", git.current_branch(Path::new(".")).await?); // e.g. Some("main")

§The surface (engineering reference)

§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, RefName};
let dir = Path::new(".");
git.fetch(dir).await?;
git.commit_paths(dir, CommitPaths::new(["src/a.rs"], "wip")).await?;
// Ref/revision inputs are validated newtypes — build them at the boundary.
git.push(dir, GitPush::branch(RefName::new("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 operation that takes a caller-supplied reference name or revision expression now does so through a validated newtype — RefName for branch/tag/ref names, RevSpec for revisions/ranges — so a flag-like or malformed value is rejected at construction, before it can reach an argv slot (a classifiable vcs_cli_support::is_invalid_input failure). The one context-dependent special value, git’s - “previous branch”, is modelled explicitly as CheckoutTarget::Previous rather than smuggled through a newtype. Remaining bare-positional inputs that are not refs/revisions (remote names, URLs, config keys) keep an internal reject_flag_like guard — refused before spawning if empty or starting with -. Flag-value slots (-b <name>) are consumed verbatim; 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.
BranchDelete
Options for GitApi::delete_branch (git branch -d/-D).
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.
CancellationToken
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).
Credential
A resolved credential: a Secret plus an optional username. For a forge token only the secret is used; for git HTTPS the username pairs with the secret as the password (a personal-access token).
CredentialRequest
The context of a credential request: which service, and the remote host if the backend knows it (forge calls often defer host resolution to the CLI, so host is frequently None). #[non_exhaustive]: more context may be added.
DiffStat
Aggregate line/file counts from a diff stat (git diff --shortstat, jj diff --stat).
EnvToken
A provider that reads a bare token from a named environment variable, at request time. If the variable is unset/empty it yields None (fall back to ambient auth) rather than erroring — handy for “use $MY_TOKEN if present”.
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.
JobRunner
The default runner: every run gets a fresh, private ProcessGroup owned by the run, so its tree is torn down when the run finishes (or its handle drops).
MergeCheck
A “is branch fully merged into base?” check for GitApi::is_merged.
MergeCheckPartial
Partial MergeCheck — names the branch being tested; chain into_base to name the base it must be merged into.
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.
OutputBudget
A configurable ceiling on how much output a potentially large content operation may buffer before it is refused — a diff (diff_text/diff), a file’s bytes at a revision (show_file/file_show), a forge PR/MR diff (pr_diff), and the diagnostic (error/progress) output of clone/fetch.
ProcessResult
The captured result of running a process to completion.
RefName
A validated git reference name (branch/tag/remote-tracking ref). Every GitApi operation that names a branch, tag, or ref to create, delete, rename, or look up by exact name takes a RefName (directly or inside its options struct), so a name from untrusted input (UIs, bots, agents) is validated once, at construction, and the type — not an internal guard — is the argv-injection barrier from then on. For a general commit-ish or range (checkout, reset_hard, log, diff ranges, …) use the more permissive RevSpec instead.
RetryPolicy
A bounded retry strategy: how many attempts, the (exponential) backoff between them, and whether to add full jitter. Used by ManagedClient to retry is_lock_contention failures. The Default is none (no retry) — retry is opt-in.
RevSpec
A validated revision/range expression (HEAD~2, main..feature). Every GitApi operation that resolves a general commit-ish or range takes a RevSpec, so an untrusted revision is validated once, at construction. 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 -). For a value that must be a genuine ref name (to create/delete/rename a branch or tag) use the stricter RefName. A rejected expression is an vcs_cli_support::is_invalid_input failure.
Secret
A secret value — an API token, a password — that redacts itself whenever it is formatted, so it can’t leak into a log line or an error message. Read the underlying value only at the point of use, via expose.
StashPush
Options for GitApi::stash_push (git stash push).
StaticCredential
A provider that always yields the same Credential for every request — the common “use this one token” case.
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).
WorktreeRemove
Options for GitApi::worktree_remove (git worktree remove).

Enums§

ChangeKind
How a file changed in a unified diff.
CheckoutTarget
What GitApi::checkout switches to: a validated ref/revision, or git’s - “previous branch” shortcut.
CredentialService
Which backend/tool is asking for a credential — lets a provider return different secrets per service. #[non_exhaustive]: new backends may be added.
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 diff call compares — the working tree/copy, or a specific revision/revset (or range).
Error
Errors produced when launching or running a child process.

Constants§

BINARY
Name of the underlying CLI binary this crate drives.
EMPTY_TREE_SHA1
Git’s well-known SHA-1 empty-tree object id. This value exists only in a SHA-1 repository: a repo created with extensions.objectFormat=sha256 has a different empty-tree id (and this SHA-1 one resolves to no object there), so this constant is not a universal stand-in for HEAD when diffing an unborn working tree. For the id that matches a repository’s active object format, use Git::empty_tree_oid, which asks git for it — that is what diff_text(DiffSpec::WorkingTree) uses on an unborn repo.

Traits§

CredentialProvider
Supplies a Credential for a CredentialRequest, just-in-time. Returning Ok(None) means “I have nothing for this request” — the backend then falls back to its ambient CLI auth, exactly as if no provider were configured.
GitApi
The Git operations this crate exposes — the interface consumers code against and mock in tests.
ProcessRunner
Runs a Command — to a captured result (output_string / output_bytes) or a live handle (start).

Functions§

is_lock_contention
Whether err is a whole-repository lock-contention failure — another process held git’s index.lock or jj’s working-copy / op-heads lock, so the command couldn’t even start. Such a failure is pre-execution and therefore safe to retry even on a mutating operation (the repo was never modified). Per-ref lock failures (cannot lock ref, <ref>.lock) are deliberately not classified here — they can occur mid-way through a multi-ref push/fetch, where a retry would not be idempotent. Conflict, “nothing to commit”, a real non-zero exit, a timeout, a signal, or a missing binary are also not lock contention and must not be retried this way.
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_branch/remote_branch_exists looks transient (DNS, a dropped connection, a fast network blip) 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.
provider_fn
Adapt a synchronous closure into a CredentialProvider. The closure runs at request time and returns the credential (or None to defer to ambient auth). For async sources (a network vault), implement CredentialProvider directly.

Type Aliases§

Result
Crate result alias.