btv.git_local
btv.git_local.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_local.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_local.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_local.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_local.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_local.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_local.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_local.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_local.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_local.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.