std/git

Git repositories, as a Git client sees them, through the git command and the formats it has for programs (--porcelain=v2, -z).

import "std/git"

Repository repo = open_repository(".")?
GitStatus s = repo.status()?
print(s.branch, s.ahead, s.behind, len(s.entries))
repo.stage(["notes.txt"])?
print(repo.commit("Add the notes")?)
Function Result
open_repository(path), find_repository(path) the repository path is in, as an ERROR or as NONE when there is none
init_repository(path, branch, bare), clone_repository(url, path, bare) a new repository
git_available() whether the git command is installed
log_graph(commits) the GraphRow of each commit, for drawing the log as git log --graph does: its column, its parent_columns, the lanes joined into it, and how many lanes there are after it
hunk_patch(file, hunk) the patch of one hunk, for git apply

A Repository has its work tree's folder, root ("" when it is bare), and its own, git_dir.

Method
status(ignored) a GitStatus: the branch, the last commit, the upstream, how far ahead and behind it is, and the entries, each a StatusEntry with its path, what changed in the index (staged) and in the work tree (unstaged), as "M", "A", "D", "R", "C", "T", "U", ".", "?" for a file not tracked, or "!" for one ignored, its original_path when renamed, and whether it is conflicted
diff(staged, paths), diff_text(staged, paths), diff_revisions(a, b, paths) the differences, as std/diff's FilePatches or as text
stage(paths), stage_all(), unstage(paths), discard(paths) files into and out of the index; discard loses the work tree's changes
stage_hunk(file, hunk), unstage_hunk(file, hunk), discard_hunk(file, hunk) one hunk of a FilePatch from diff
commit(message, amend, allow_empty) the new commit's hash
log(limit, revision, path, all) the Commits, children before parents: hash, parents, author_name, author_email, author_time, the committer's the same, subject, and body
head(), revision(name) hashes
branches(), current_branch(), create_branch(name, start), delete_branch(name, force), rename_branch(name, new_name), switch_to(name) Branches, local then remote, with their upstream, ahead, and behind
tags(), create_tag(name, revision, message), delete_tag(name) Tags; one with a message is annotated
remotes(), add_remote(name, url), remove_remote(name), fetch(remote, prune), pull(remote, branch, rebase), push(remote, branch, set_upstream, force, tags) remotes; force is --force-with-lease
blame(path, revision) a BlameLine for each line: its commit, author, author_time, the commit's summary, its line now and original_line then, and its text
stashes(), stash(message, include_untracked), stash_pop(index), stash_apply(index), stash_drop(index) stashes; stash gives false when there was nothing to stash
merge(revision, no_fast_forward, message), abort_merge(), rebase(onto), continue_rebase(), abort_rebase() a MergeOutcome: done, or stopped at the conflicts it names
state(), conflicts() what is in progress: "merging", "rebasing", "cherry-picking", "reverting", "bisecting", or ""; and the files in conflict
file_at(revision, path) a file's bytes at a revision, or in the index with ":"
config(key), set_config(key, value), git(arguments) settings, and any other git command

Git asks for credentials through its own credential helpers, as the system has them set up; std/git sets GIT_TERMINAL_PROMPT to 0 for the programs it starts, so Git never waits for a password on the terminal. What Git says when it fails is an ERROR of kind "git", or "not_found" when Git is not installed.