- Zig 100%
- Nix <1%
zig-git #
A library for reading git repositories from Zig 0.17 without running git,
written in Zig alone: no libgit2, no C zlib, nothing to link. It is meant to
answer the questions a history browser asks git — what a commit holds, what a
revision range means, what a diff says — with the same answers git gives,
and to grow into writing to repositories and talking to remote ones.
It is early. What works so far is the core layer, the first
parts of the revision layer — revisions, walking commits, history limited
to paths, describing commits as git log does, and naming them by refs —
and the first two parts of the diff layer, comparing two texts as git diff --no-index does, and comparing trees, the index and the working
tree as git diff, git diff-tree, git diff-index and git diff-files
do:
- object formats and object IDs, SHA-1 and SHA-256 alike, chosen per repository at run time, and hashing an object to its ID;
- object headers, read exactly as strictly as git reads them;
- commits, trees, annotated tags and their author, committer and tagger lines, read without allocating and as forgivingly as git reads them, their oddities included;
- loose objects: finding, inflating and checking them, whole, header only or streamed, refusing each corruption git refuses and in the same circumstances;
- packs and their indexes (versions 1 and 2 of the index, versions 2 and 3 of the pack, offsets past 2 GiB), with OFS_DELTA and REF_DELTA chains resolved without recursion and bounded in depth, so that a chain that loops is an error rather than a hang; reading an object's kind and size applies no delta;
- the multi-pack-index, and incremental chains of them, as a faster way of finding objects in the packs they name;
- alternates, from
objects/info/alternatesand from aGIT_ALTERNATE_OBJECT_DIRECTORIESvalue the caller passes in, nested as deep as git nests them; - abbreviated object IDs, both ways: a prefix expanded to the objects it
begins, found by binary search in every pack index and
multi-pack-index layer and by listing one fan-out directory of loose
objects, in every objects directory and alternate; an ambiguous one
told apart by kind as
core.disambiguateand^{commit}tell it, and described as git's ambiguity hint describes each candidate; and object IDs shortened to the fewest digits no other object shares, at leastcore.abbrev's, whoseautogrows with the number of packed objects as git's does; - replace refs, as git-replace(1) describes them: every object read
through the refs under
refs/replace/(orGIT_REPLACE_REF_BASE) as its replacement, commits, trees, blobs and tags alike, keeping its own object ID, chains followed four deep with git's errors for a deeper one and a missing replacement, and its warning for a name it passes over; not whencore.useReplaceRefsis false,GIT_NO_REPLACE_OBJECTSis set or--no-replace-objectsgiven; - grafts and the shallow boundary:
info/grafts(orGIT_GRAFT_FILE) read as git reads it, with its deprecation hint and its errors for bad and duplicate lines, and theshallowfile (orGIT_SHALLOW_FILE) with its fatal bad line, giving commits the parents the walk,<rev>^,<rev>~<n>,%Pandmerge-basefollow; and, as git was seen to, the commit-graph left unread when anything is replaced or grafted or the repository is shallow; - all of that as one object database, which asks its objects directories, packs and loose objects in the order git can be seen to ask them, passes over a broken copy for the next as git does, and names each corruption it meets;
- configuration: the file syntax read on bytes, every corner git accepts
and every malformed line it refuses at the line it names; the system,
global, local and worktree files,
GIT_CONFIG_COUNT,GIT_CONFIG_PARAMETERSand-c, in git's order and with every path and environment value passed in;include.pathandincludeIfwithgitdir:,gitdir/i:,onbranch:,worktree:andhasconfig:remote.*.url:, its conditions answered by the caller; booleans, integers with their units, and paths with~and%(prefix); and lookups that spell keys as git does; - wildmatch, git's glob dialect, as a module of its own for refs,
pathspecs and attributes to use, with the corners
git check-attrandgit tag -lshow; - discovering a repository as git does: walking up from a starting
directory,
.gitdirectories and.gitfiles (linked worktrees and submodules,commondirincluded), bare repositories,GIT_DIR,GIT_WORK_TREE,GIT_COMMON_DIR,GIT_OBJECT_DIRECTORY,GIT_CEILING_DIRECTORIESwith its empty-entry and symbolic link rules, filesystem boundaries andGIT_DISCOVERY_ACROSS_FILESYSTEM,core.worktreeandcore.bare,safe.directoryand ownership,safe.bareRepository, and what git requires of a git directory before it trusts one; the environment, the starting directory and the user are all passed in; - the repository format: versions 0 and 1 and every extension git 2.56
knows, refused with git's own message where git refuses them, and by
name where this library cannot read what git can
(
extensions.compatObjectFormat, arefStoragepayload); - refs: ref names checked by git-check-ref-format(1)'s rules, root refs,
pseudorefs and per-worktree refs told apart, and
main-worktree/andworktrees/<name>/followed; loose refs (symbolic refs, symbolic links, CRLF and trailing garbage read as git reads them),packed-refswith its traits and peel lines, sorted or not; reftables of both versions, SHA-1 and SHA-256, their blocks, prefix compression, ref, obj, log and index blocks and checksums, and stacks of them with their updates and deletions; reflogs from both; all of it behind one ref store that follows symbolic refs as far as git does (five refs, cycles caught), lists refs in git's order, peels tags from the storage or the object database, and shortens names as%(refname:short)does; - dates: every
--date=mode git-log(1) documents, their-localvariants,auto:, andformat:andformat-local:with strftime — flags, field widths, modifiers and the conversions glibc copies as text included — shown as git shows them;TZread as a glibc-linked git reads it, a POSIX rule as leniently as glibc reads one; and git's strict and approximate date parsers — the calendar, the time zone database, strftime and the parsers all from zig-datetime; - the index: versions 2, 3 and 4 (version 4's prefix-compressed paths
included), stat data, modes, stages, the assume-valid, skip-worktree
and intent-to-add flags, padding and the trailing checksum, all zeros
under
index.skipHash; the cache tree with its invalidated nodes, resolve-undo, the untracked cache, the fsmonitor cache, the end of index entries and the index entry offset table; the split index, its EWAH bitmaps and its shared index merged into one list of entries; the sparse index, its sparse directories expanded through their trees when asked; unknown extensions passed over or refused by git's rule, and every complaint git makes of a malformed one in git's words; Repository, the library's way in: a discovered repository opened with its configuration from every source,config.worktreeincluded, itsincludeIfconditions answered by the repository itself (onbranch:from its refs, in either storage), its object database and its ref store, and its index, fromGIT_INDEX_FILEwhen the caller passes it;- revisions, the first of the revision layer: every way gitrevisions(7)
names a single object, read into a structured form with no I/O and
then resolved — object IDs and their abbreviations, ref names by
git's ordered rules with its warnings for names that are more than one
thing,
git describeoutput,@,^<n>,~<n>, every^{...},:/<text>and^{/<text>}with POSIX extended regular expressions,<rev>:<path>with./and../,:[<n>:]<path>in the index, reflog entries by count and by date (the current time passed in),@{-<n>}, and@{upstream}and@{push}from branches, remotes andpush.defaultin every mode — each failure named and carrying git's message, and ranges and other sets of commits parsed for the walk to come and refused here; - refspecs, fetch and push, read with git's rules and mapped both ways;
- the commit-graph: its file and split chains of them, every chunk — fanout, object IDs, commit data, extra edges, corrected commit dates and their overflow, changed-path Bloom filters of both hash versions, base graphs — and git's rules for passing over a file, dropping a chunk or cutting a chain short, each found by corrupting files git wrote and said in git's words; commits read from it, with the object as the fallback, and generation numbers as corrected commit dates or topological levels;
- walking commits as
git rev-listwalks them: starting points and exclusions,--not,--alland the ref listings, the default order with git's handling of equal dates and of clocks that run backwards,--date-order,--author-date-order,--topo-order,--reverse,--max-count,--skip, the parent counts,--first-parent,--ancestry-path,--since,--until,--since-as-filter,--boundary, the sides of a symmetric difference and children — every rule found by comparing a model with git over thousands of generated histories, merges, octopus merges and criss-cross merges included; - merge bases as
git merge-basefinds them,--allin git's order for criss-cross histories,--octopus,--independent,--is-ancestorand--fork-pointfrom the reflog. - pathspecs as gitglossary(7) describes them and
git ls-filesandgit logmatch them: literal paths and directories, wildcards matched against whole paths, thetop,literal,glob,icaseandexcludemagic in their long and short forms, paths relative to the current directory with git's errors for one outside the working tree, and theGIT_LITERAL_PATHSPECS,GIT_GLOB_PATHSPECS,GIT_NOGLOB_PATHSPECSandGIT_ICASE_PATHSPECSsettings, all read with no I/O; - two trees compared in step under a pathspec, passing over every subtree
that is the same on both sides or that the pathspec cannot reach, and
yielding each file, symbolic link or gitlink added, deleted or modified,
as
git diff-tree -rlists them; - history limited to paths, simplified as git-rev-list(1)'s "History
Simplification" describes and as git was seen to do where it does not:
the default mode,
--full-history,--dense,--sparse,--simplify-merges,--show-pullsand--remove-empty, merges' parents counted only when they are relevant, parents rewritten for--parentsand--childrenwith git's reading ahead, and the commit-graph's changed-path Bloom filters asked before trees are compared, in the cases git asks them and with git's own count of what they answered; - describing commits as
git log --prettydoes, as a library that writes to anIo.Writerand nothing else: the built-in formatsoneline,short,medium,full,fuller,reference,email(with its RFC 2047 encoded words and folded headers),mboxrdandraw, andformat:,tformat:and bare%strings with every placeholder that needs no decorations, notes, signatures or reflogs — object IDs whole and shortened, identities in every date mode and through the mailmap, the subject, body and sanitized subject,%x00, colors with%C(auto), padding and truncation in all eight forms,%w(...)wrapping, the+,-and space magic, and%(trailers)with every option — down to what git does with a NUL, a control character or a placeholder it cannot answer, found by comparing with git over thousands of generated formats and commits; andpretty.<name>aliases; - trailers found as git-interpret-trailers(1) finds them, with
trailer.separators, configured trailers and the comment string; - mailmaps as gitmailmap(5) describes them, every line form, with git's
rules for repeated and conflicting lines found by experiment, read from
the work tree,
mailmap.file,mailmap.bloband a bare repository'sHEAD:.mailmap; - choosing commits by their messages and identities as
--grep,--authorand--committerdo, with--all-match,--invert-grep,-i, and glibc's basic and extended regular expressions with GNU's escapes, or fixed strings, and the mailmap applied to identities when git applies it; - decorations as
git log --decorateshows them: the refs,HEAD -> <branch>,tag:,graftedandreplaced, in git's order, short or whole, chosen by--decorate-refs,--decorate-refs-exclude,--clear-decorations,log.excludeDecorationandlog.initialDecorationSetwith git's rules for its patterns, colored bycolor.decorate.*;%d,%Dand%(decorate:...)with every option;--sourceand%S; and--simplify-by-decoration, simplified as git simplifies it; - naming commits by the nearest tag, as
git describedoes: annotated tags, lightweight ones or every ref,--matchand--exclude, git's choice among the names of one commit, and its depth, which is counted as git counts it rather than as git-describe(1) says, all found by comparing with git over every commit of generated histories; and%(describe:...)with every option; - the reachability filters
--contains,--no-contains,--merged,--no-mergedand--points-at, asgit branch,git tagandgit for-each-refanswer them; - two texts compared line by line in the edit script git chooses, not
merely a shortest one: the linear-space refinement of Myers' algorithm
as his paper gives it, with what git was seen to add — lines that occur
only in one text taken out first, lines that occur very often taken out
where the lines around them say so, the search for a middle snake given
up at git's cost limit on large, much-changed texts (and refused where
it would search further, see below), runs of changes
slid and merged as git slides them, git's indent heuristic (on by
default) placing each run by the indentation and blank lines around it,
and the common tail git sets aside for a patch without context — and
--minimal, all found by comparing a model with git over many thousands of generated texts; the whitespace options-w,-b,--ignore-space-at-eoland--ignore-cr-at-eol; hunks with-U<n>,--inter-hunk-context,--ignore-blank-linesand-I<regex>, merged and left out as git does, git's own notion of a blank line included; function names after@@by git's default rule or a diff driver's, cut as git cuts them;-W, each hunk reaching over the whole of the functions its changes are in as git's hunks were seen to reach, the lines just above a function line and git's odd ends of the text included; and the patch for a pair of files — thediff --githeader, mode lines,new file modeanddeleted file mode, theindexline in SHA-1 or SHA-256,---and+++with prefixes and quoted paths,\ No newline at end of file, and binary files told apart as git tells them; - attributes, as gitattributes(5) gives them: the system and global
files, every
.gitattributesfrom the top down to a path's directory andinfo/attributes, read lazily and in git's order, from the working tree with the index behind it, the index alone or a tree (attr.tree,GIT_ATTR_SOURCE); patterns matched as gitignore(5) reads them, macros (binarybuilt in) expanded where they are set, and git's warnings about bad lines, said as often as git says them; - diff drivers' function lines:
diff.<driver>.xfuncnameandfuncname, whichever was set last, as several patterns one to a line with!for those that rule a line out, the text git shows being the first group of the match where it took part, and git's errors for a malformed or wrongly negated pattern, said when git says them; the regular expressions match as glibc's do, the leftmost-longest match and glibc's choice of groups within it (which is not POSIX's), found by comparing with git over thousands of random patterns; and all 28 of git's built-in drivers (ada,bash,bibtex,cpp,csharp,css,dts,elixir,fortran,fountain,golang,html,ini,java,kotlin,markdown,matlab,objc,pascal,perl,php,python,r,ruby,rust,scheme,swiftandtex), as patterns of zig-git's own fitted to which lines git takes and what it shows of them, each over at least 3,000 random lines (18,000 and more for most) with no difference left; their word patterns are not done; - the index compared with a tree and with the working tree from the stat
data it holds, without refreshing or writing it: modification and
change times in whole seconds, inode, owner, group, size and mode, as
experiments showed git compares them, racily clean files hashed, and
intent-to-add, assume-unchanged, skip-worktree and unmerged entries as
git treats them; or, as
git diffdoes after refreshing, a file whose stat data alone changed taken to be unchanged by its contents; - every format git writes for a list of changed paths: the raw format
(
--abbrev,-z),--name-only,--name-status,--diff-filter,--numstat,--statwith git's layout (fitted to over a thousand of git's outputs: the widths,COLUMNS,diff.statNameWidth,diff.statGraphWidth,--stat-count, and the bars' scaling),--shortstat,--summaryand the patch, in git's order, with-R, binary files told by attributes, contents andcore.bigFileThreshold, gitlinks asSubproject commitlines, and what whitespace options and-Idrop from each format; - the pickaxe, as gitdiffcore(7) describes it and as git was seen to
count:
-S<string>(occurrences counted without overlapping, NUL bytes and binary files searched),--pickaxe-regex(matches counted as git resumes its search, the rest of the text not beginning a line, empty matches included),-G<regex>(each line a diff adds or deletes matched alone, with its newline, binary files passed over without--text),--find-object(either side; not inlog),--pickaxe-all, and-i, indiff,diff-tree,diff-index,diff-files,log(choosing the commits shown) andshow, with git's errors for patterns and for options it refuses together; matched over 2,400 random cases; - orderfiles (
-O<orderfile>,diff.orderFilefor the porcelain),--skip-toand--rotate-to(inlogandshow, from the first path at or after the one named),--relative[=<path>]anddiff.relative(the prefix matched as a string and cut off every path but--summary's; the orderfile and the rotation still match the whole paths, so--relative=dir/ --rotate-to=dir/xstarts at what is written asx, and of the pairs taking one deleted source the last in the new order is the rename),--line-prefix(before every linelogandshowwrite, the porcelain's--statnarrowed by its width) and-D(--irreversible-delete, a rewrite's hunk counting its old lines as-?,?); --check: trailing whitespace, a space before a tab in the indent, an indent of spaces (tabwidth), a tab in the indent, new blank lines at the end of a file, a last line without a newline and leftover conflict markers (conflict-marker-size), ascore.whitespaceand thewhitespaceattribute choose, each found by probing git line by line, with git's exit statuses 2 and 3; and-Bbreaking a type change between a file and a symbolic link, shown asT100;--dirstat(-X,--dirstat-by-file,--cumulative,diff.dirstatwith git's warning) in itschanges,linesandfilesmodes, the damage of each path measured as git was seen to measure it (the kept chunks rename detection counts, lines, 64-byte pieces of a binary file), directories folded and shown as git shows them; andzig-git whatchanged, with--i-still-use-thisas git 2.56 asks,logwith the raw format and commits whose diff is empty, and merges unless-masks for them, left out (paths, with which git was seen to walk otherwise, are refused).
zig-git diff --no-index compares two files, or two directories file by
file, and prints what git diff --no-index prints, with its exit status
and its errors: every option above, --diff-algorithm, -R, --quiet,
--exit-code, --output, --text, --full-index, --abbrev,
--no-prefix, --src-prefix, --dst-prefix, --default-prefix, and
diff.algorithm, diff.context, diff.interHunkContext,
diff.indentHeuristic, diff.noprefix, diff.mnemonicPrefix (1/ and
2/ without an index), diff.suppressBlankEmpty, core.quotePath,
diff.renames and diff.autoRefreshIndex (each stopping, as git
stops, at a value that is not a boolean, without naming the file);
symbolic links compare as their targets (a link against a file as a
deletion and an addition), executable files by mode, and
directories by name, a file on one side and a directory on the other
shown as git shows them. --patience, --histogram, --anchored,
colors (where git would color), --binary, --stat and the other
summaries, word diffs, rename detection, pickaxe and - for standard
input are refused there by name, and so are two directories with a file
only on each side that git could take for a rename (the same contents,
or two files at least half alike) unless diff.renames is false.
zig-git diff in a repository compares the index with the working tree,
a commit with the index (--cached, --staged) or the working tree, and
two commits or trees (A B, A..B), with pathspecs, every format and
option above, and the configuration git diff reads (diff.context,
diff.interHunkContext, diff.algorithm, diff.noprefix,
diff.mnemonicPrefix, diff.srcPrefix, diff.dstPrefix, the stat
widths, diff.renames); zig-git diff-tree compares two trees or a
commit with its parents (-r, -t, --root, -m, --always,
--no-commit-id, --stdin), zig-git diff-index a tree with the index
or the working tree (--cached, -m), and zig-git diff-files the
index with the working tree (-0, -1, -2, -3, --base, --ours,
--theirs, -q), each reading only the configuration git's plumbing
reads. Every one of them finds renames and copies as git does: -M[<n>],
-C[<n>], --find-copies-harder, -l<n> and diff.renameLimit with
git's warnings when the limit is reached, --no-renames,
--rename-empty, and diff.renames (on by default) for diff, log
and show, the pairs scored on the chunks git counts them by
(src/diff/similarity.zig) and chosen as git chooses them
(src/diff/renames.zig), and written in every format: R096 and C100
in the raw and name formats, similarity index, rename from and copy to in the patch, a/{b => c} in --stat, --numstat and
--summary. -B[<n>][/<m>] breaks rewrites into a deletion and an
addition for renames to take, and shows those nothing took as rewrites
(M100, dissimilarity index, the whole file's lines, rewrite in
--summary, B for --diff-filter). zig-git log --follow <path>
(and log.follow with one path) follows a file back through its renames
and copies, as git does: commits chosen by the pathspec they followed,
and where the path it names was added, its source looked for among every
path, unchanged ones included. zig-git log and zig-git show write each commit's diff in any
of these formats after its message (--full-diff, --first-parent,
log.showRoot), with the separators git puts there in each pretty
format, show defaulting to the patch, and show merges as -m,
--diff-merges=off|on|first-parent|separate (each merge once per parent,
with (from <parent>) on its first line), --dd, --no-diff-merges
and log.diffMerges ask, or as combined diffs (-c,
--diff-merges=combined) and dense combined diffs (--cc, --dd's
merges aside, --diff-merges=dense-combined, and git show's default
for a merge): the raw format with a colon per parent, the names with a
status per parent, and the combined patch with its column per parent
(src/diff/combined.zig), for merges of any number of parents, paths
renamed or copied against a parent compared with their source there,
its function names found as git finds them there (by the default rule
whatever the diff driver, from no further back than the hunk before, cut
short at 40 bytes and then by one more) and binary files, as attributes
and drivers decide them, said to differ. The dense form leaves out each
stretch of changes where the parents have only two versions and the
result takes one of them as it is, as git-diff-tree(1) describes it;
which changes make one stretch, and how a hunk is counted around a
change left out, were found by experiment and matched over thousands of
generated merges of two to four parents. Without context (-U0) only
the changes are written, with git's counts, even the one less it gives
a hunk reaching past the end of the file. -W and
--inter-hunk-context leave a combined patch as it is, as they do
git's, and -I stops at the first merge as git does. zig-git check-attr reports
attributes as git check-attr does (-a, --cached, --source,
--stdin, -z, builtin_objectmode).
zig-git cat-file (-t, -s, -e, -p and <kind> <object>) answers
from the library for objects named by any single revision
(cat-file -p HEAD~2:src/x.zig), wherever they are stored, printing what
git cat-file prints, its error messages, explanations of paths not
found and ambiguity hints included; like git's, it takes no range and
searches no message.
zig-git show-index and zig-git verify-pack [-v] [-s] print what git's
do, the delta chain histogram included. zig-git config reads
configuration as git config does — --get, --get-all,
--get-regexp, --list, the get and list subcommands, with
--show-origin, --show-scope, -z, --name-only, the types bool,
int, bool-or-int and path, and every file option — its output,
errors and exit statuses included. It writes nothing, and refuses by name
what it does not do: --blob, --url, the color and expiry-date
types, and GNU's regular expression extensions and back references.
zig-git rev-parse answers the questions about where a repository is —
--git-dir, --absolute-git-dir, --git-common-dir, --show-toplevel,
--show-prefix, --show-cdup, the --is-* questions,
--show-object-format, --show-ref-format, --local-env-vars and
--path-format — as git rev-parse does, and answers single revisions
with --verify, -q, --short[=<n>], --symbolic,
--symbolic-full-name, --abbrev-ref[=(strict|loose)], --default,
--end-of-options, -- and --disambiguate=<prefix>, telling revisions
from paths as git does, and lists refs with --all, --branches,
--tags, --remotes, --glob and --exclude. It prints ranges and
the other sets of commits as the revisions they stand for (A..B as B
and ^A), in each of its ways of naming them, and refuses by name the
options it does not have (--not, --sq, --revs-only and the like).
zig-git rev-list walks commits as git rev-list does, with every
option above and --parents, --children, --timestamp,
--left-right, --count, --abbrev-commit, the searches by message
and identity, and every format log has; it takes paths, after -- or, where they
are there, without it, with git's complaints about an argument that is
both a revision and a file, a later one that is neither, and an option
after a path, and simplifies the history they limit in every mode above.
It refuses by name --follow, --objects,
the patch-equivalence options (--cherry-pick, --cherry-mark and
--cherry, which need diffs), reflog walks and the rest. zig-git merge-base answers in all five of git's modes, and zig-git describe
names commits with every option above, --long, --abbrev,
--candidates, --exact-match, --first-parent and --always
included. zig-git log walks as
rev-list does, every option above included, and describes each commit
in any format above, with --oneline, --abbrev-commit, --date,
--expand-tabs, --use-mailmap, --color, the searches, decorations
and --source, and
format.pretty, pretty.<name>, log.date, log.abbrevCommit,
log.mailmap, log.decorate, color.ui, color.diff,
color.diff.commit and color.decorate.*; zig-git rev-list takes the same formats, --header and --no-commit-header, in
rev-list's framing. zig-git show -s shows commits, annotated tags, trees
and blobs as git show does, and zig-git check-mailmap maps contacts.
They refuse by name what needs what the library does not have yet:
notes (--notes, %N), signatures
(--show-signature, %G? and the rest), reflog walks and %g*,
--graph, Perl's regular expressions (-P and
grep.patternType=perl), and output in any encoding but UTF-8. Both read through the
commit-graph when git would, say what git says of a corrupt one, and walk
the history replace refs, grafts and a shallow boundary make.
zig-git check-ref-format (--normalize, --allow-onelevel,
--refspec-pattern), zig-git show-ref (--head, --branches,
--tags, -d, -s, --hash[=<n>], --abbrev[=<n>], --verify,
--exists, -q, patterns),
zig-git for-each-ref (patterns, --exclude, --sort=[-]refname,
--count, the reachability filters, and the --format atoms refname with its :short,
:lstrip and :rstrip, objectname and *objectname with their
:short[=<n>], objecttype, symref, *objecttype and HEAD) and
zig-git symbolic-ref (-q, --short, --no-recurse) read refs as
git's do, warnings about broken refs included, and refuse by name the
atoms and options they do not have. zig-git branch and zig-git tag
list branches (-a, -r, --show-current, a detached HEAD described
from its reflog) and tags, with patterns and the reachability filters;
they create, rename and delete nothing, and refuse by name every option
that would, and verbose, sorted, formatted, columned and colored output.
zig-git ls-files lists the index as git ls-files does — --cached,
--stage, --unmerged, --resolve-undo, -z, -t, -v, -f,
--debug with its stat data and flags, --deduplicate, --sparse,
--full-name, --abbrev[=<n>], and --format with the atoms objectmode,
objecttype, objectname, objectsize, stage and path — from
any directory, with pathspecs, a sparse index expanded with git's hint,
and every message git gives a corrupt index. It refuses by name what
needs the working tree (--others, --modified, --deleted,
--ignored, --killed, the exclude options, --eol), the attr
pathspec magic, --error-unmatch, --with-tree and
--recurse-submodules. Every command stops at a bad core.abbrev or
core.disambiguate as git does.
Every command finds its repository the way git does, takes -C, -c,
--git-dir, --work-tree and --no-replace-objects before its name, and says what git says
when there is none, or one it will not use. The differences are
deliberate or not yet matched:
- an object holding fewer bytes than its header says is refused, where git shows whatever its buffer held in their place;
- a REF_DELTA chain that loops is
DeltaChainTooDeep, where git never returns; - git never resolves a REF_DELTA whose base is outside its own pack, and
nor does the library unless asked to (
resolve_external_bases); - what git says on standard error of a corrupt delta, of a corrupt pack
found by
verify-pack, and of a broken pack met on the way to a copy that could be read, is not matched; the answers and exit statuses are; - a
format:string is refused where git would write it differently from strftime: where git's own pass over%s,%zand%Zpairs%signs differently (%E%s,%5%%s),%swith a flag (the C library'smktime),%zand%Zwith a flag informat:(written at UTC's offset), git's own%sand%zwhere they are not the timestamp and the offset strftime writes (a local time from 2100 on, or a recorded zone such as+0099), a local abbreviation longer than six bytes, and a field width past 255; strftime is theClocale's only; - a date whose year does not fit in 32 bits is refused in every mode that shows a calendar date, where git wraps the year;
- a
TZrule naming daylight saving time without its dates while the database has aposixrulesfile to supply them, or with a month of 0 or past 12, is refused rather than guessed at; relativeandhumanare matched for a current time before 2038, the latestGIT_TEST_DATE_NOWcan set;zig-git configexpands%(prefix)/only when given a prefix, since it is not git and has none of its own;- a repository with
extensions.compatObjectFormatis refused, where git reads it (and crashes when it names the object format itself); safe.bareRepositorywith no value is refused as a bad setting, where git crashes;- a
commondirthat begins with blank space names no repository, where git names a path part-way through resolving it; - a bad
core.useReplaceRefsstopszig-gitonly once it opens the repository, where git stops even to answerrev-parse --git-dir; GIT_REPLACE_REF_BASEnot ending in/is refused, where git stops on a bug of its own; a replace ref that is a broken or dangling symbolic ref replaces nothing, where git cannot read the object; a replaced empty tree is read as its replacement, where git'scat-file -preports a hash mismatch; and a commit replaced by an object of another kind is not matched;- the warning for a replace ref's bad name is written when the command
first reads commits or, in
cat-file, an object, which may come after other warnings git writes after it; - grafts or replacements that make a cycle are walked, where git's
--topo-orderlists nothing; zig-git name-rev, anddescribe --contains, which names commits as it does, are refused: no rule tried matched git's choice among the names that reach a commit, which sometimes prefers a name through a merge to a nearer one along first parents;zig-git describerefuses to choose among candidates of more than one kind — annotated tags, lightweight tags, other refs — where git was seen not to take the nearest, nor one kind over another; with candidates of one kind it matches git's choice and depth;--dirty,--broken,--debugand describing a blob are refused;--simplify-by-decorationis refused with paths, exclusions, a commit-graph,--sparse,--first-parent,--boundary,--show-pulls,--remove-empty,--childrenor a parent count, the combinations where--simplify-merges, whose rules it shares, was seen to differ or was not compared;- ownership and filesystem boundaries are found with
statx, so only on Linux; elsewhere a caller supplies its own answers or discovery says it cannot check; - a reftable stack git cannot read, git treats as empty without a word; the library names what is wrong, and the commands fail;
- a malformed
packed-refsis refused whole, where git's single-ref lookups in a file that says it is sorted may pass over the bad line, andshow-refprints the refs before it; - a malformed reflog line is passed over as git passes it over, but the identity and message are read as the identity line and everything after the tab, where git reads some malformed lines differently;
- an index entry or extension running past the end of the file, or a
path whose length disagrees with its flags, is refused, where git shows
whatever lies past it or crashes; so is an entry with an empty path,
which git shows as
./, and alinkextension of the object ID alone, which crashes git; - a sparse directory whose tree cannot be read is refused, where git crashes, and an fsmonitor bitmap longer than the index is dropped with a warning, where git stops on a bug of its own;
- like git, the index's checksum is not checked unless asked for;
- a revision whose search pattern uses GNU's regular expression
extensions (
\w,\band the rest) is refused, and so is@{upstream}or@{push}in a repository with remotes in the files ofremotes/orbranches/, which git still reads; @{-<n>}reads onlyHEAD'scheckout: moving fromentries, and@{push}takes no account ofremote.<name>.mirror;- among commits of one committer date, a message search answers the one put in its queue last, as git was seen to; git's order may differ in histories where that rule was not tested;
zig-git cat-filefinds nothing by a range, as git does, rather than refusing it;zig-git rev-parse --disambiguatewith a single digit is refused: git then lists some of the objects the digit begins and not others;zig-git rev-parsestops at a badcore.abbrev,core.disambiguateorpush.defaultonly when it reads objects, where git stops even to answer the discovery queries;- a tag whose tagger's timestamp is negative is refused in an ambiguity hint, where git stops with "Timestamp too large for this system";
zig-git ls-files --debugand-fare refused whencore.fsmonitoris set, since git asks the monitor before it answers them, and long options cannot be abbreviated as git allows;- with a commit-graph, git orders
--topo-order,--date-orderand--author-date-orderwalks by generation number, and with exclusions,--first-parent,--since,--untilor--since-as-filterit lists something other than the same walk without a commit-graph — in one split chain whose dates ran out of order, nothing at all for a range of dozens of commits — so those combinations are refused there; without them, and in the default order, the walk is the same either way; --ancestry-path=<commit>is refused, and so is--childrenwith--boundaryfor a symmetric difference, whose boundary commits' children depend on which commits git's merge-base search happened to read;- given a commit-graph whose parent positions are corrupt in a commit
that is only an ancestor of the merge bases, git may find the bases
without reading it, where
zig-git merge-basereads it and stops with git's own complaint; - gitformat-commit-graph(5) gives the second Bloom filter seed as 0x7e646e2; the filters git writes use 0x7e646e2c, and so does the library.
- the
attrpathspec magic is refused, where git reads attributes from the working tree, and so is the internalprefixmagic; - with paths,
zig-git rev-listrefuses what was seen to list commits git's rules did not account for:--ancestry-path;--first-parentwith--parents,--children,--boundary, an ordering or--remove-empty;--parentswith--full-historyand--reverseor--skipin a walk without exclusions or an ordering;--remove-emptywith--boundary, with--reverseand--parents, or in a repository with changed-path Bloom filters, where git was seen to list other commits with the filters than without them; and--simplify-mergeswith excluded commits,--remove-empty,--sparse,--first-parent,--boundary,--show-pulls, a parent count or a commit-graph; --followis refused across a merge (at the first one the walk reaches, after the commits before it are written) and with--reverse;- a commit whose
encodingheader names anything but UTF-8 is refused wherever its message or identities are shown, as isi18n.logOutputEncodingor--encodingnaming anything else, since messages are not re-encoded; - colors that git turns on only for a terminal (
--color=auto,color.ui=auto) stay off, aszig-gittakes its output never to be one; - a few corners of padding are not matched:
%>>(<n>)taking back spaces written before a%w(...)that changes nothing, padding followed by a color and then%%,%>>(<n>)with the space magic on a placeholder too wide for it, and padding followed by a color and a%w(...); nor is a NUL written before a%w(...)region, which git's wrapping loses; - the display widths
%<(<n>)and%w(...)count are Unicode 17.0.0's, which match git 2.56 at every code point except U+FFFE and U+FFFF (git does not take those for UTF-8 and counts a column a byte), and may differ from a git built with another Unicode version for the characters added or changed since; - a malformed
--grepor--authorpattern is refused in glibc's words, where git names it before refusing an unknown option, and a back reference is refused by name; - git's indent heuristic is matched by a model fitted to git's choices
(
src/diff/indent.zig), not derived from a description of it: its structure was pinned by probes, its weights fitted to several hundred thousand generated slides. It disagreed with git on 3 of 40,000 generated code-like comparisons, and on none of 14,050 others; where it disagrees, a run is placed a line from where git puts it.--no-indent-heuristicanddiff.indentHeuristic=falseturn it off; - a line diff whose search for a middle snake would go on past 256
steps is refused (
LineDiff.Error.LongSearchUnsupported). Only a comparison of more than 65,532 lines, once the common head and tail and the lines found in one text only are set aside, can search that long, and past that step git sometimes splits the comparison early at a run of matching lines it has found. Probes found most of the rule (from step 257, a run of at least 21 lines ending more than twice as many lines from where that search began, in each text, as the steps taken), but git was also seen to split at runs of exactly 20 lines and at runs found before step 257, by a rule not yet found. In 640 generated comparisons of 5,000 to 100,000 lines, 145 were refused and the rest matched git;--minimalnever searches that way and is not refused; --patienceand--histogramare refused, their choices not yet matched;- long options cannot be abbreviated in
zig-git diff, as git allows, and short ones cannot be bundled; --find-copies-harderagainst the working tree or the index under-Ris refused, and so is--diff-filterfor a merge inshow;- combined diffs (
-c,--cc) with--ignore-blank-lines, where git leaves changes out by another rule, or of a rewrite-Bbroke, are refused, and so arediff-tree -cand--cc,git diff-files -pwith unmerged paths (unless-1,-2or-3chooses a stage),--combined-all-paths,--remerge-diffand--diff-merges=remerge; - a function pattern with a back reference, which git takes, is refused,
and so is one whose first group lies inside a repetition that may
iterate more than once, where glibc's choice of iteration was matched
only 98 times in 100 over 3,440 random cases (against none missed in
13,660 with the group anywhere else); so is
-Wtogether with--ignore-blank-linesor-I, whose meeting has not been matched; drivers that run programs (diff.<driver>.command,textconv) anddiff.externalare refused too.--binary, colors, word diffs,--color-moved,--submodule=log|diffand--ignore-submodules(other thannone) are refused by name; - the pickaxe is refused with
--quiet, which stops at the first difference before the pickaxe has seen the rest; with-iand--find-objecttogether, where git stops on a bug; with--find-objectnaming a tree (git then lists every diff's trees), or against the working tree; with unmerged paths, a merge's non-empty combined diff and--follow; andlog --find-objectis refused, since git was seen to list the commits it chooses out of the walk's order; --relativeis refused with paths, which git matches against the shortened paths, with the working tree, and with--summary, whose paths git leaves whole;--line-prefixis refused with-z;--checkis refused where a file of blank lines alone, before or after, ends in blank lines, where git was seen to choose the line it reports by a rule not found; and so is awhitespaceattribute with bothtab-in-indentandindent-with-non-tab, and aconflict-marker-sizethat is not a number;logwith-m,--ddor--diff-merges(other thanoffandcombined) and paths is refused: git then walks as--full-historywalks, and shows a merge against its rewritten parents;- contents git would convert on their way in from the working tree are
refused:
core.autocrlf, and thetext,eol,crlf,filter,identandworking-tree-encodingattributes on a file read there; so are a checked-out submodule'sHEAD,core.fsmonitorand a sparse index; git diffrefreshes the index and writes it when it can;zig-git diffnever writes it, comparing contents where git would refresh, so that the output is the same; the device number in the stat data is not compared, nor nanoseconds, which git was seen not to compare either;zig-git diffoutside a repository without--no-index,--merge-base,A...B, blobs and more than two commits are refused;
The API documentation is generated from the doc comments and published at https://jeff.jcollie.page/zig-git/.
What it is for #
grebe, a history browser for git, reads repositories by running
git log and git show. zig-git is being written so that it can stop:
the plan is a library in layers, each depending only on the ones before it.
- Core — the object database (loose objects, packs, the multi-pack
index, alternates), the ref store (loose refs,
packed-refs, reftable, reflogs), configuration with includes, discovering a repository the way git does, and the index file. - Revision — revision arguments in git's own syntax, and walking the history they choose: ranges, path limiting, the three orderings, mailmap, replace refs, grafts.
- Diff — between two texts first, then between trees, the index and the working tree, producing patches byte-identical to git's.
- Write and transport, later: ref transactions, writing objects,
signing, and git's protocol v2 over
file://,ssh://andhttps://.
Three choices run through all of it, and the decision records in
docs/adr/ give the reasons:
- Agreeing with git is the definition of correct. The tests build their
repositories with
gitand compare answers with it, and patches are to match git's byte for byte. - What it does not support, it says so. A revision argument outside the
supported set is an error naming it, and a repository using an extension
it does not implement is refused, so a caller can fall back to
gitrather than receive an answer that is nearly right. - It is written from git's documentation and behavior, never its source, so that it can be MIT licensed.
The words used for the things in a repository — object ID, object format,
object database, ref store, git directory — are defined in
GLOSSARY.md.
Building and testing #
Everything is pinned in the Nix flake, Zig and the git the tests compare
against included:
nix develop
zig build test --summary all # every repository test runs with SHA-1 and SHA-256
zig build docs-serve # the API documentation on http://localhost:8000
CONTRIBUTING.md says more.
Where this lives #
The canonical repository is on my Forgejo instance, and Tangled carries a mirror of it:
git clone https://git.jcollie.dev/jeff/zig-git.git
- Forgejo: https://git.jcollie.dev/jeff/zig-git
- Tangled: https://tangled.org/jcollie.dev/zig-git
Report issues and send pull requests to the Tangled mirror. CI and the published documentation come from the Forgejo repository.
License #
MIT; see LICENSES/MIT.txt. The project follows REUSE.
References cited #
- Deutsch, P. and J-L. Gailly. ZLIB Compressed Data Format Specification version 3.3. RFC 1950, 1996. https://www.rfc-editor.org/info/rfc1950 — the container loose objects are stored in, and its checksum.
- Deutsch, P. DEFLATE Compressed Data Format Specification version 1.3. RFC 1951, 1996. https://www.rfc-editor.org/info/rfc1951 — the stored blocks the tests write corrupt loose objects with.
- The Git Project. gitrepository-layout(5): Git Repository Layout.
https://git-scm.com/docs/gitrepository-layout — the objects directory,
objects/info/alternates,.gitfiles,commondir, a worktree'sgitdir, the repository format versions, andinfo/graftsandshallow. - The Git Project. git(1). https://git-scm.com/docs/git —
GIT_ALTERNATE_OBJECT_DIRECTORIESand its quoting,-c, theGIT_CONFIG_*environment variables,-C,--git-dir,--work-tree,GIT_INDEX_FILE,--no-replace-objectsandGIT_NO_REPLACE_OBJECTS, and the variables discovery reads:GIT_DIR,GIT_WORK_TREE,GIT_COMMON_DIR,GIT_OBJECT_DIRECTORY,GIT_CEILING_DIRECTORIESandGIT_DISCOVERY_ACROSS_FILESYSTEM; andGIT_LITERAL_PATHSPECS,GIT_GLOB_PATHSPECS,GIT_NOGLOB_PATHSPECSandGIT_ICASE_PATHSPECS;GIT_ATTR_NOSYSTEM,GIT_ATTR_SOURCEandGIT_EXTERNAL_DIFF. - The Git Project. hash-function-transition: Transitioning Git to SHA-256.
https://git-scm.com/docs/hash-function-transition — SHA-256 object
formats alongside SHA-1, and
extensions.compatObjectFormat. - The Git Project. git-rev-parse(1).
https://git-scm.com/docs/git-rev-parse — what
zig-git rev-parseanswers,--path-format,--verify,--quiet,--short,--disambiguate,--symbolic,--symbolic-full-name,--abbrev-ref,--default,--all,--branches,--tags,--remotes,--globand--exclude. - The Git Project. git-worktree(1). https://git-scm.com/docs/git-worktree
— linked worktrees, their git directories,
extensions.worktreeConfigand thecore.bareandcore.worktreeit moves, and which refs are per-worktree and howmain-worktree/andworktrees/reach them. - The Git Project. gitsubmodules(7).
https://git-scm.com/docs/gitsubmodules — a submodule's
.gitfile and its git directory under the superproject's. - The Git Project. Upcoming breaking changes.
https://git-scm.com/docs/BreakingChanges — why
safe.bareRepositoryexists, and its default to come. - The Linux man-pages project. statx(2). https://man7.org/linux/man-pages/man2/statx.2.html — a file's owner and device, for ownership and filesystem boundaries.
- The util-linux project. unshare(1). https://man7.org/linux/man-pages/man1/unshare.1.html — the user namespace the tests run git as root in, to see a repository someone else owns.
- The Git Project. reftable. https://git-scm.com/docs/reftable — the
reftable format: header, footer, blocks, records, varints, the
tables.liststack and its layout in a repository. - The Git Project. git-check-ref-format(1).
https://git-scm.com/docs/git-check-ref-format — the rules for ref
names, and what
zig-git check-ref-formatanswers. - The Git Project. git-show-ref(1). https://git-scm.com/docs/git-show-ref
— what
zig-git show-refanswers, and its patterns. - The Git Project. git-for-each-ref(1).
https://git-scm.com/docs/git-for-each-ref — what
zig-git for-each-refanswers: patterns, field names,%(refname:short), and--contains,--no-contains,--merged,--no-mergedand--points-at. - The Git Project. git-symbolic-ref(1).
https://git-scm.com/docs/git-symbolic-ref — what
zig-git symbolic-refanswers. - The Git Project. git-pack-refs(1). https://git-scm.com/docs/git-pack-refs
—
packed-refs, and the compaction the tests run. - The Git Project. git-update-ref(1). https://git-scm.com/docs/git-update-ref — the reflog line format.
- The Git Project. git-refs(1). https://git-scm.com/docs/git-refs —
git refs migrate, which the tests convert repositories with. - The Git Project. git-reflog(1). https://git-scm.com/docs/git-reflog — the oracle for reading reflogs.
- The Git Project. gitrevisions(7). https://git-scm.com/docs/gitrevisions
— the rules short ref names are tried by, which shortening reverses;
abbreviated object IDs, and the
^{commit}and^{tree}suffixes that tell an ambiguous one apart; every form of a single revision, the ranges and sets of commits refused for now, andgit describeoutput. - The Git Project. gitcli(7). https://git-scm.com/docs/gitcli — how
git tells a revision from a path, behind
rev-parse's andrev-list's complaints about an argument that is neither, or both, and--. - The Git Project. git-fetch(1). https://git-scm.com/docs/git-fetch — the refspec format, pattern and negative refspecs, and how a remote's fetch refspecs say where its branches are tracked.
- The Git Project. git-push(1). https://git-scm.com/docs/git-push —
push refspecs,
:and deleting with an empty source. - The Git Project. git-fast-import(1). https://git-scm.com/docs/git-fast-import — the stream the tests build long histories with merges and tags from.
- The Git Project. gitdatamodel(7). https://git-scm.com/docs/gitdatamodel
— references, symbolic references and
HEAD. - The Git Project. git-cat-file(1). https://git-scm.com/docs/git-cat-file
— what
zig-git cat-fileanswers. - The Git Project. git-hash-object(1).
https://git-scm.com/docs/git-hash-object — how an object ID is
computed, and
--literally, which the tests make malformed objects with. - The Git Project. gitformat-pack(5): Git Pack Format. https://git-scm.com/docs/gitformat-pack — packs, pack indexes, the delta instruction format and the multi-pack-index.
- The Git Project. gitformat-chunk(5): Chunk-based File Formats. https://git-scm.com/docs/gitformat-chunk — the table of contents the multi-pack-index begins with.
- The Git Project. Multi-Pack-Index (MIDX) Design Notes. https://git-scm.com/docs/multi-pack-index — incremental multi-pack-index chains and their layout.
- The Git Project. git-multi-pack-index(1). https://git-scm.com/docs/git-multi-pack-index — writing one, and the incremental chains the tests make.
- The Git Project. git-show-index(1).
https://git-scm.com/docs/git-show-index — what
zig-git show-indexanswers. - The Git Project. git-verify-pack(1).
https://git-scm.com/docs/git-verify-pack — what
zig-git verify-packanswers. - The Git Project. git-index-pack(1).
https://git-scm.com/docs/git-index-pack — version 1 pack indexes and
completing thin packs with
--fix-thin. - The Git Project. git-pack-objects(1). https://git-scm.com/docs/git-pack-objects — thin packs, and the deepest delta chain git writes.
- The Git Project. git-repack(1). https://git-scm.com/docs/git-repack — the packs the tests make.
- The Git Project. git-clone(1). https://git-scm.com/docs/git-clone —
--shared, which borrows objects through alternates, and--depth,--shallow-sinceand--shallow-exclude, with which the tests make shallow clones. - The Git Project. git-config(1). https://git-scm.com/docs/git-config
— the configuration file syntax, its value types, its sources and
scopes, includes and their conditions, what
zig-git configanswers, protected configuration,core.bare,core.worktree,safe.directory,safe.bareRepository, everyextensions.*git knows, and theindex.*,core.splitIndex,core.sparseCheckout,core.fsmonitorandcore.quotePathsettings the index is read by,core.abbrev,core.warnAmbiguousRefs,advice.objectNameWarning,branch.<name>.remote,.mergeand.pushRemote,format.pretty,pretty.<name>,log.date,log.abbrevCommit,log.mailmap,log.decorate,log.excludeDecoration,log.initialDecorationSet,color.decorate.<slot>,core.useReplaceRefs,color.ui,color.diff,color.diff.commit, the "color" value type,grep.patternType,grep.extendedRegexp,core.commentChar,core.commentString,mailmap.file,mailmap.blobandi18n.logOutputEncoding,diff.algorithm,diff.context,diff.interHunkContext,core.whitespace,diff.orderFile,diff.relative,diff.dirstat,diff.indentHeuristic,diff.noprefix,diff.mnemonicPrefix,diff.suppressBlankEmpty,diff.external,diff.srcPrefix,diff.dstPrefix,diff.statNameWidth,diff.statGraphWidth,diff.renames,diff.renameLimit,diff.<driver>.binary,diff.<driver>.xfuncname,diff.<driver>.funcnameand the driver settings zig-git refuses,core.attributesFile,attr.tree,core.bigFileThreshold,core.fileMode,core.trustctime,core.checkStat,core.symlinks,core.autocrlf,log.showRoot,remote.pushDefault,remote.<name>.url,.pushurl,.fetchand.push,push.default, andcommitGraph.readChangedPathsandcommitGraph.changedPathsVersion. - The Git Project. gitignore(5): Specifies intentionally untracked files
to ignore. https://git-scm.com/docs/gitignore — the glob patterns
wildmatch implements,
**among them. - The Git Project. gitattributes(5): Defining attributes per path.
https://git-scm.com/docs/gitattributes — attribute patterns, through
which
git check-attrwas asked how globs match paths; the files, their precedence, the four states, macros andbinary; thediffattribute, diff drivers anddiff.<driver>.binary; the conversion attributes zig-git refuses; thewhitespaceandconflict-marker-sizeattributes--checkreads. - The Git Project. git-check-attr(1).
https://git-scm.com/docs/git-check-attr — the oracle for the
wildmatch tests, and what
zig-git check-attranswers. - The Git Project. git-tag(1). https://git-scm.com/docs/git-tag —
git tag -land--ignore-case, the oracle for patterns matched without the pathname rule, and whatzig-git taglists. - The Open Group. Regular Expressions. The Open Group Base
Specifications Issue 8, chapter 9, 2024.
https://pubs.opengroup.org/onlinepubs/9799919799/basedefs/V1_chap09.html
— their syntax, basic and extended, bracket expressions and character
classes, for
zig-git config, message searches,--grepand diff drivers' function patterns, and the leftmost-longest rule for where a match lies (from which glibc's groups were seen to depart). - The Open Group. strtol: convert a string to a long integer. The Open Group Base Specifications Issue 8, 2024. https://pubs.opengroup.org/onlinepubs/9799919799/functions/strtol.html — how git reads an integer value, base prefixes and all.
- Cox, Russ. Glob Matching Can Be Simple And Fast Too. 2017.
https://research.swtch.com/glob — matching globs by resuming from the
latest star, which wildmatch extends to
**to keep its work bounded. - Cox, Russ. Regular Expression Matching Can Be Simple And Fast. 2007.
https://swtch.com/~rsc/regexp/regexp1.html — running every state of
an automaton at once, as
zig-git config's regular expressions do. - The Git Project. gitglossary(7): A Git Glossary.
https://git-scm.com/docs/gitglossary — the vocabulary
GLOSSARY.mdfollows, root refs, pseudorefs and per-worktree refs, and pathspecs: their syntax, the long and short magic forms, and thetop,literal,icase,glob,attrandexcludemagic. - The Git Project. git-log(1). https://git-scm.com/docs/git-log —
the
--date=modes,auto:,format:andhuman; its "PRETTY FORMATS": the built-in formats and every placeholder; and whatzig-git loganswers:--pretty,--format,--oneline,--abbrev-commit,--expand-tabs,--use-mailmap,--grep,--author,--committer,--all-match,--invert-grep,-i,-Eand-F; and--decorate,--decorate-refs,--decorate-refs-exclude,--clear-decorations,--source, and the%d,%D,%(decorate),%Sand%(describe)placeholders; its diff options,--full-diffand--first-parent. - The Git Project. git-show(1). https://git-scm.com/docs/git-show —
what
zig-git showanswers, and how it shows tags, trees and blobs; its default patch and combined diff for merges. - The Git Project. git-log(1): Diff Formatting.
https://git-scm.com/docs/git-log#_diff_formatting —
-m,-c,--cc,--dd,--no-diff-merges,--diff-mergesand its formats,--follow, andlog.diffMergesandlog.follow. - The Git Project. git-interpret-trailers(1).
https://git-scm.com/docs/git-interpret-trailers — trailer blocks, their
keys, separators, folded values and the share of trailers a block needs,
and
trailer.separatorsandtrailer.<key-alias>.key. - The Git Project. gitmailmap(5). https://git-scm.com/docs/gitmailmap — the mailmap's line forms and matching.
- The Git Project. git-check-mailmap(1).
https://git-scm.com/docs/git-check-mailmap — what
zig-git check-mailmapanswers. - Moore, K. MIME (Multipurpose Internet Mail Extensions) Part Three:
Message Header Extensions for Non-ASCII Text. RFC 2047, 1996.
https://www.rfc-editor.org/info/rfc2047 — the encoded words the
emailformat writes a header past ASCII in. - Resnick, P., Ed. Internet Message Format. RFC 5322, 2008.
https://www.rfc-editor.org/info/rfc5322 — the specials that make the
emailformat quote a name. - The Unicode Consortium. Unicode Standard Annex #11: East Asian Width. https://www.unicode.org/reports/tr11/ — which characters take two columns when padding and wrapping.
- The Unicode Consortium. Unicode Character Database, version 17.0.0.
https://www.unicode.org/Public/17.0.0/ucd/ —
DerivedEastAsianWidth.txtandDerivedGeneralCategory.txt, from whichtools/gen_width.ziggenerates the tables of characters taking no columns and two. - The Unicode Consortium. Unicode Standard Annex #44: Unicode Character
Database, revision 36 (Unicode 17.0.0).
https://www.unicode.org/reports/tr44/tr44-36.html — the format of the
UCD's data files, and the
@missinglines that give the default East Asian width of unassigned code points. - The Git Project. git-rev-list(1). https://git-scm.com/docs/git-rev-list
—
--sinceand--until, through which the approximate parser was checked; and whatzig-git rev-listanswers: commit limiting, the orderings,--boundary,--ancestry-path,--parents,--children,--left-rightand--count; and its "History Simplification": TREESAME,--simplify-by-decoration, the default mode,--full-historywith and without parent rewriting,--dense,--sparse,--simplify-merges,--show-pullsand--remove-empty, and its two example histories, which the tests build. - The Git Project. git-diff-tree(1). https://git-scm.com/docs/git-diff-tree
—
-rand its raw output, the oracle for comparing trees;-t,--root,-m,--always,--no-commit-id,--stdinand the raw output format, whatzig-git diff-treeanswers;--cc, whose description of the uninteresting hunks it leaves out is the rule dense combined diffs were matched from, and the raw format for merges. - The Git Project. git-diff-index(1). https://git-scm.com/docs/git-diff-index
—
--cached,-m, and comparing a tree with the index or the working tree, whatzig-git diff-indexanswers. - The Git Project. git-diff-files(1). https://git-scm.com/docs/git-diff-files
— the stages of unmerged paths,
-q, whatzig-git diff-filesanswers. - The Git Project. git-mktree(1). https://git-scm.com/docs/git-mktree — trees with gitlinks and with a file and a directory of one name, made for the experiments.
- The Git Project. api-trace2: Trace2 API.
https://git-scm.com/docs/api-trace2 —
GIT_TRACE2_PERF, through whosebloomstatistics the tests see when git asks its changed-path filters. - The Git Project. gitformat-commit-graph(5): Git commit-graph format. https://git-scm.com/docs/gitformat-commit-graph — the commit-graph file, its chunks, generation numbers, the changed-path Bloom filters and the base graphs of a chain.
- The Git Project. commit-graph: Git Commit-Graph Design Notes. https://git-scm.com/docs/commit-graph — corrected commit dates and topological levels, split chains and their file layout, mixed generation chains, and chains across alternates.
- The Git Project. git-commit-graph(1).
https://git-scm.com/docs/git-commit-graph — writing commit-graphs and
split chains for the tests, and
commitGraph.generationVersionandcommitGraph.changedPathsVersion. - The Git Project. git-merge-base(1).
https://git-scm.com/docs/git-merge-base — what
zig-git merge-baseanswers: merge bases,--octopus,--independent,--is-ancestorand--fork-point. - The Git Project. git-replace(1). https://git-scm.com/docs/git-replace
— replace refs, what they replace and how they are turned off, and
--graft, with which the tests make them. - The Git Project. git-describe(1).
https://git-scm.com/docs/git-describe — what
zig-git describeanswers, and its "Search Strategy". - The Git Project. git-name-rev(1).
https://git-scm.com/docs/git-name-rev — the naming the experiments
could not match, for which
name-revis refused. - The Git Project. git-branch(1). https://git-scm.com/docs/git-branch
— what
zig-git branchlists,--show-currentand the reachability filters. - The Git Project. git-commit(1). https://git-scm.com/docs/git-commit
— its "Date formats" section, the forms
GIT_COMMITTER_DATEaccepts. - The Git Project. git-var(1). https://git-scm.com/docs/git-var —
GIT_COMMITTER_IDENT, through which the strict parser was checked. - The Open Group. strftime: convert date and time to a string. The Open
Group Base Specifications Issue 8, 2024.
https://pubs.opengroup.org/onlinepubs/9799919799/functions/strftime.html
— the conversions, and the
EandOmodifiers. - The Git Project. gitformat-index(5): Git index format. https://git-scm.com/docs/gitformat-index — the index file: its header, entries, versions, padding, checksum and every extension; the stat data compared with the working tree.
- The Git Project. bitmap-format: GIT bitmap v1 format. https://git-scm.com/docs/bitmap-format — its appendix on the serialization of an EWAH bitmap, as the split index, untracked cache and fsmonitor extensions hold them.
- The Git Project. sparse-index: Git Sparse-Index Design Document.
https://git-scm.com/docs/sparse-index — sparse directories, the
sdirextension, and expanding a sparse index to a full one. - The Git Project. git-ls-files(1). https://git-scm.com/docs/git-ls-files
— what
zig-git ls-filesanswers: its options, tags and field names. - The Git Project. git-update-index(1). https://git-scm.com/docs/git-update-index — index versions, the split index, the untracked cache, skip-worktree, assume-unchanged and the fsmonitor bits, through which the tests make their indexes; "Using index info" and racy git, which the working tree comparison follows.
- The Git Project. git-sparse-checkout(1). https://git-scm.com/docs/git-sparse-checkout — cone mode and the sparse index, and the settings that allow it.
- The Git Project. git-status(1). https://git-scm.com/docs/git-status — the oracle for what the untracked cache holds.
- Myers, Eugene W. An O(ND) Difference Algorithm and Its Variations. Algorithmica 1, 251–266, 1986. https://doi.org/10.1007/BF01840446 — the greedy algorithm, the middle snake and the linear-space refinement the line diff follows.
- The Git Project. git-diff(1). https://git-scm.com/docs/git-diff —
--no-index, the patch format, the combined diff format and itsdiff --ccheader, the combined options,--minimal, the whitespace options,--ignore-blank-lines,-I,--inter-hunk-context,-W(--function-context), the prefixes,--outputand the exit status. - The Git Project. diff-options, as included in git-diff(1),
git-diff-files(1), git-diff-index(1) and git-diff-tree(1) —
--indent-heuristic,--diff-algorithm,--full-index,--abbrevand--text; the output formats,--statand its widths,--diff-filter,-R,--exit-code, and the raw output format;-M,-C,--find-copies-harder,-l,--no-renamesand--rename-empty, and the rename and copy lines of the patch and--summary;-S,-G,--find-object,--pickaxe-all,--pickaxe-regex,-O,--skip-to,--rotate-to,--relative,--line-prefix,-D,--checkand--dirstatwith its parameters. - The Git Project. git-whatchanged(1).
https://git-scm.com/docs/git-whatchanged —
whatchangedaslogwith the raw format and without merges. - The Git Project. gitdiffcore(7): Tweaking diff output.
https://git-scm.com/docs/gitdiffcore — the order of the diffcore
stages, rename and copy detection as "the amount of material kept",
the sources
-Cand--find-copies-harderadd, the preliminary step that pairs files of the same name, and-B's breaking of rewrites and putting them back together; the pickaxe (-S,-G,--pickaxe-all), the orderfile and the rotation, and where each comes in the chain. - The Git Project. Git 2.11 Release Notes.
https://github.com/git/git/blob/master/Documentation/RelNotes/2.11.0.adoc
— the indent heuristic's introduction, as
--indent-heuristicanddiff.indentHeuristic, chosen by the lines before and after a change. - The Git Project. gitattributes(5): Defining a custom hunk-header.
https://git-scm.com/docs/gitattributes#_defining_a_custom_hunk_header
— git's default rule for the function name after
@@,diff.<driver>.xfuncnameand the list of built-in drivers; the rest of what git does with a pattern (several to a value,!,funcname, the group shown) was found by experiment. - The Open Group. diff: compare two files. The Open Group Base
Specifications Issue 8, 2024.
https://pubs.opengroup.org/onlinepubs/9799919799/utilities/diff.html
— the unified format:
---and+++,@@ranges and the line marks. - Ollie, Jeffrey C. zig-datetime: dates, times and time zones for Zig.
2026. https://git.jcollie.dev/jeff/zig-datetime — the calendar, the
time zone database, glibc's lenient reading of
TZ, strftime with format strings read at run time, and git's two date parsers. - Ollie, Jeffrey C. grebe: a history browser for git. 2026. https://git.jcollie.dev/jeff/grebe — the first consumer, and the source of the test fixture helper.