@plimeor/git-kit
v0.1.3
Published
Small Git repository operations for Bun CLI tools
Downloads
32
Readme
@plimeor/git-kit
Small Git source and checkout primitives for Bun CLI tools.
@plimeor/git-kit keeps local Git process work behind a typed resource model:
normalize a remote source, create or open a local checkout, resolve refs, inspect
the worktree, and clean up temporary checkouts through one lifecycle handle.
Install
bun add @plimeor/git-kitThe package is Bun-first and shells out to the local git executable.
Core Model
There are two public resources:
Repositoryrepresents a normalized remote Git source.Checkoutrepresents a local Git worktree and owns checkout-scoped operations.
import * as Git from '@plimeor/git-kit'
const repo = Git.repository('plimeor/agent-skills')
console.log(repo.source) // https://github.com/plimeor/agent-skills.git
console.log(repo.identity) // plimeor__agent-skills
const checkout = await repo.checkout({ ref: 'main' })
try {
console.log(checkout.directory)
console.log(checkout.headSha)
} finally {
await checkout.dispose()
}Temporary Checkouts
When directory is omitted, checkout() clones into a temporary directory and
dispose() removes that temporary checkout root.
await Git.withCheckout({ source: 'plimeor/agent-skills', ref: 'main' }, async checkout => {
const files = await checkout.listWorktreeFiles()
console.log(files)
})withCheckout() is the preferred shape when the checkout is only needed inside
one async operation.
Fixed Directories
Pass directory to clone into a stable worktree path. Fixed-directory checkouts
are not removed by dispose().
const checkout = await Git.checkout({
directory: '/tmp/agent-skills',
source: 'plimeor/agent-skills',
ref: 'main',
})
await checkout.dispose() // no-op for fixed directoriesUse reuseExisting to validate and reuse an existing Git worktree at
directory.
const checkout = await Git.checkout({
directory: '/tmp/agent-skills',
reuseExisting: true,
source: 'plimeor/agent-skills',
ref: 'main',
})Reused worktrees must have the same origin fetch URL as the normalized source.
The requested ref is fetched and checked out before the checkout is returned.
Open Existing Worktrees
Use openWorktree() when the directory already contains a Git worktree and no
clone should be performed.
const checkout = await Git.openWorktree(process.cwd())
console.log(checkout.snapshot())Ref Operations
Use Repository#resolveRemoteRef() or resolveRemoteRef() when a caller only
needs to know what a remote ref points to and does not need a checkout.
const main = await Git.resolveRemoteRef({
source: 'plimeor/agent-skills',
ref: 'main',
})
const defaultBranch = await Git.repository('plimeor/agent-skills').resolveRemoteRef()
console.log(defaultBranch.ref)Remote ref resolution shells out to git ls-remote and does not clone. The
resolution order is:
- omitted ref or
HEADresolves the remote default branch. - Branch names resolve against
refs/heads/<name>. - Tag names resolve against
refs/tags/<name>, preferring peeled tag commits. - Other refs resolve against the remote ref namespace.
Checkout#fetch() resolves a remote ref without switching the worktree.
const main = await checkout.fetch('main')
console.log(main.headSha)
const defaultBranch = await checkout.fetch('HEAD')
console.log(defaultBranch.ref)Resolution order:
HEADresolves the remote default branch.- Branch names resolve against
refs/heads/<name>. - Tag names resolve against
refs/tags/<name>. - Other refs are fetched through
git fetch origin <ref>and resolved throughFETCH_HEAD. - If direct fetch fails, branches and tags are fetched broadly, then
<ref>is resolved locally as a commit-ish.
Checkout#switch() checks out a ref and refreshes the checkout snapshot.
await checkout.switch({ ref: 'release' })
await checkout.switch({ ref: checkout.headSha, detach: true })Worktree Reads
listWorktreeFiles() returns sorted repository-relative paths from:
- tracked files
- untracked files
- files not excluded by Git ignore rules
It uses git ls-files -co --exclude-standard -z.
const files = await checkout.listWorktreeFiles()collectIgnorePaths() collects positive path rules from .gitignore files
under the checkout.
const ignored = await checkout.collectIgnorePaths()This helper is for concrete path collection. It does not implement full Git ignore matching semantics: comments and negated rules are skipped, and glob patterns are returned as normalized paths rather than evaluated.
API
repository(source)
Creates a Repository.
source must be a non-empty remote source. GitHub shorthand in the form
owner/name is normalized to https://github.com/owner/name.git. Local paths
such as ../repo, ./repo, /repo, ., and .. are rejected.
checkout(request)
Clones or reuses a checkout and returns a Checkout.
type CheckoutRequest = {
directory?: string
ref?: string
reuseExisting?: boolean
source: string
}resolveRemoteRef(request)
Resolves a remote ref without cloning and returns a ResolvedRef.
type RemoteRefRequest = {
ref?: string
source: string
}
type ResolvedRef = {
headSha: string
ref: string
}ref defaults to remote HEAD. Resolution failures reject with an error.
withCheckout(request, callback)
Creates a checkout, passes it to callback, then disposes it in finally.
openWorktree(directory)
Opens an existing Git worktree and returns a Checkout.
Repository
Properties:
identitysource
Methods:
checkout(options?)resolveRemoteRef(ref?)
Checkout
Properties:
currentRefdirectoryheadShaidentitysource
Methods:
snapshot()refresh()fetch(ref?)switch({ ref, detach? })listWorktreeFiles()collectIgnorePaths(input?)dispose()
Development
bun run --filter @plimeor/git-kit lint
bun run --filter @plimeor/git-kit test