Keyboard shortcuts

Press ← or → to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

btv.git

btv.git.discover(path)

discover(path) -> promise of { root, git_dir, prefix }. path is any path inside the repo. Replaces rev-parse --show-toplevel / --absolute-git-dir / --show-prefix. Rejects (ENOREPO) when path is not inside a repository.

Defined in git.lua.

btv.git.head(path)

head(path) -> promise of { branch, detached, sha }. branch is nil on a detached HEAD (detached then true); sha is the full resolved commit oid (empty on an unborn HEAD). Replaces rev-parse --abbrev-ref HEAD.

Defined in git.lua.

btv.git.show(file, rev)

show(file, rev) -> promise of the RAW bytes of file (an absolute path) as it was at rev (e.g. "HEAD"). Replaces git show HEAD:<rel>, but you pass the plain file path — the repo-relative path is computed for you (symlink-safe). Rejects (ENOENT) when the file has no version at rev (new / untracked file).

Defined in git.lua.

btv.git.diff_file(path, file)

diff_file(path, file) -> promise of { added, changed, removed, hunks } for file’s working tree vs its HEAD blob (each hunk { old_start, old_count, new_start, new_count }). Replaces git diff -U0 -- <file> plus hunk parsing. path locates the repo (any path inside it); file is the file to diff.

Defined in git.lua.

btv.git.status(path, opts)

status(path, opts) -> promise of { dirty, entries } in git status --porcelain XY terms. Each entry is { path, index, worktree, orig_path }:

path       repo-relative path of the changed file
index      the staged (index-vs-HEAD) column, one letter
worktree   the unstaged (worktree-vs-index) column, one letter
orig_path  where the content came from, for a rename/copy; "" otherwise

A column is " " when the file is unmodified in it. There is exactly ONE entry per path: a file that is staged and then edited again arrives once with both columns set (porcelain’s MM), never as two entries carrying one column each. An untracked file is porcelain’s ?? — both columns.

Unlike git status, an unstaged rename IS detected: it reads R on the destination with orig_path set, where git prints a deletion plus an untracked file.

opts.ignored (default false) additionally reports git-ignored paths as porcelain’s !! — both columns — like git status --porcelain --ignored. It is opt-in because the default walk PRUNES ignored directories, which is what keeps a status over a repo with a large target/ fast; asked for, the walk must descend into them. A wholly-ignored directory collapses to ONE entry naming the directory (target, not its 50k files), exactly like a collapsed untracked directory — so a consumer resolves directory-ness from its own model and matches descendants by path prefix:

local st = btv.await(btv.git.status(root, { ignored = true }))
for _, e in ipairs(st.entries) do
  if e.index == "!" then ignored[e.path] = true end   -- a file OR a directory
end

A repository that is not trusted — owned by another user and not listed in safe.directory, git’s rule — has its own config ignored, so the filter drivers it defines (filter.<name>.clean and friends) do not run and files are compared unfiltered. The result then carries notice, a message naming the repository and the skipped drivers, and the first such notice per repository is also shown with btv.notify at WARN.

Defined in git.lua.

btv.git.clone(url, dir, opts)

clone(url, dir, opts) -> promise of the created dir. opts.depth makes it a shallow clone (1 = only the tip commit); opts.branch checks out a named branch or tag instead of the remote default. Replaces git clone. (git’s --filter=blob:none has no gix analog — a shallow depth supplies the same speed-up.) Rejects (EGIT) on any clone/fetch failure.

Defined in git.lua.

btv.git.checkout(dir, rev, opts)

checkout(dir, rev, opts) -> promise resolving nil. Checks out rev in the repo at dir, updating the worktree to match. Two modes:

btv.git.checkout(dir, sha, { detach = true })  -- git checkout --detach <sha>
btv.git.checkout(dir, "main")                  -- git checkout main

With opts.detach the rev is any revision (a sha, tag, or ref) and HEAD is left pointing straight at that commit — how an exact pin is applied. Without it, rev names a BRANCH and HEAD stays symbolic on it; a branch that exists only as a remote-tracking ref (the usual case for anything but the default branch of a fresh clone) is created locally from it first, as git checkout <branch> does.

Attaching is what makes a detached checkout movable again: pull fast-forwards the current branch, so it rejects outright while HEAD names a bare commit. Rejects (ENOENT) when an attach target is neither a local nor a remote-tracking branch.

Defined in git.lua.

btv.git.fetch(dir, opts)

fetch(dir, opts) -> promise resolving nil. Fetches the repo’s remote, updating the remote-tracking refs and leaving HEAD and the worktree alone — the half of pull that touches no working state. Replaces git fetch.

opts.unshallow drops a shallow clone’s boundary (git fetch --unshallow), so history a depth = 1 clone omitted becomes reachable. That is the prerequisite for checking out an arbitrary older revision in place — without it, a shallow clone simply does not contain the commit and the checkout rejects. A no-op on a repo that was never shallow.

Defined in git.lua.

btv.git.pull(dir)

pull(dir) -> promise of { updated, sha }. Fetches the repo’s remote and fast-forwards only the current branch (rejecting ENOTFF on a divergence, never merging). updated is false when already current. Replaces git pull --ff-only.

Defined in git.lua.

btv.git.submodule_update(dir, opts)

submodule_update(dir, opts) -> promise resolving nil. Clones-if-missing (opts.init) and checks out every submodule to its recorded commit, opts.recursive-ly into nested ones. Replaces git submodule update --init --recursive.

Defined in git.lua.