provcat.stores.github
github://owner/repo/path?at=branch:main.The selector names a git ref with branch:, tag: or commit:. Without a
selector the store uses the default branch of the repository.
?at=ts:TIME names the commit that the default branch had at TIME, and
?at=ts:BRANCH@TIME the commit that BRANCH had. The store walks the branch’s
first parents from its head, and takes the first commit whose committer date
is at or before TIME. First parents are the commits of the branch itself, so a
commit made on another branch and merged later by a merge commit is left out.
Git records when a commit was made, not when it was pushed, so a commit made
on Monday and pushed on Wednesday counts from Monday. docs/design.md lists the
other cases where the answer differs from what the branch showed. A branch: must
be a branch and a tag: must be a tag; the store asks the git refs API, so a
tag of the same name cannot stand in for a branch.
Every fetch first pins the ref to a commit. The cache key holds the commit, so a cached file never goes stale and needs no check::
<cache>/github/<owner>/<repo>/<commit>/<path>A URI with ?at=commit:<40 hex digits> needs no network call when the cache
holds it. Pinning a branch or tag records the commit in the cache, so offline
mode can use the last commit it saw. Offline mode also serves a file inside a
folder that was fetched whole.
A single file comes from the contents API, which serves files up to 100 MB. A
folder comes from one tarball of the commit, which costs one API call however
many files it holds. The tarball unpacks only plain files and folders; links,
devices and names that climb with .. are left out. A folder that holds two
names one disk could store as one, for example Guide.md and guide.md, is
refused.
Git LFS: both the contents API and the tarball give the pointer file of a file
that Git LFS keeps, not its content. So after a download the store looks for
pointer files, which are under 1024 bytes, and asks the Git LFS batch API of
the repository for their content, 100 objects at a time. It checks the size and
the SHA-256 of each object against its pointer. The LFS server is on the web
host of GitHub, github.com for api.github.com, and the token goes there
as well. The download links that the batch API gives carry their own headers,
and the token never goes to them. A repository that names another LFS server in
.lfsconfig is not supported, and neither is a pointer that names Git LFS
extensions. A file that looks like a pointer but whose object the LFS server
does not have fails the fetch. list gives the size of the pointer of an LFS
file, because the contents API lists it so; stat gives the size of the
content.
Options:
api_url: the API root. The default ishttps://api.github.com. Set it for GitHub Enterprise.token_env: the environment variables to read a token from, in order. The default is[GITHUB_TOKEN, GH_TOKEN].use_gh_cli: when no variable is set, rungh auth tokenfor the host ofapi_url. The default is true.timeout: seconds for each request. The default is 60.
The token goes only to the host of api_url and, for Git LFS, to the web host
of the same GitHub. A redirect to another host, for example the tarball download
host, does not carry it.