Git integration
The @optique/git package provides async value parsers for validating Git references (branches, tags, commits, remotes) using isomorphic-git. These parsers validate input against an actual Git repository, ensuring that users can only specify existing references.
import { gitBranch, gitTag, gitCommit, gitRef, gitRemote, gitRemoteBranch } from "@optique/git";
import { option, argument } from "@optique/core/primitives";Installation
deno add jsr:@optique/gitnpm add @optique/gitpnpm add @optique/gityarn add @optique/gitbun add @optique/gitGetting started
Import the parsers from @optique/git and use them with Optique primitives:
import { gitBranch } from "@optique/git";
import { argument } from "@optique/core/primitives";
const parser = argument(gitBranch());
// Accepts: "main", "develop", "feature/my-feature"
// Rejects: "nonexistent-branch"gitBranch()
Validates that input matches an existing local branch name in the repository.
import { gitBranch } from "@optique/git";
import { argument } from "@optique/core/primitives";
const branchParser = argument(gitBranch());Options
import type { GitParserOptions } from "@optique/git";Example
import { gitBranch } from "@optique/git";
import { option } from "@optique/core/primitives";
// Branch argument for git checkout-like command
const checkoutParser = option("-b", "--branch", gitBranch());
// Usage: myapp checkout --branch feature/my-featuregitTag()
Validates that input matches an existing tag name in the repository.
import { gitTag } from "@optique/git";
import { option } from "@optique/core/primitives";
const tagParser = option("-t", "--tag", gitTag());
// Usage: myapp release --tag v1.0.0Example with custom options
import { gitTag } from "@optique/git";
import { option } from "@optique/core/primitives";
const versionParser = option("--release", gitTag({
metavar: "VERSION",
}));gitRemote()
Validates that input matches an existing remote name in the repository.
import { gitRemote } from "@optique/git";
import { option } from "@optique/core/primitives";
const remoteParser = option("--remote", gitRemote());
// Usage: myapp fetch --remote origingitRemoteBranch()
Validates that input matches an existing branch on a specific remote.
import { gitRemoteBranch } from "@optique/git";
import { option } from "@optique/core/primitives";
const remoteBranchParser = option("--branch", gitRemoteBranch("origin"));
// Usage: myapp pull --branch maingitCommit()
Validates that input is a valid commit SHA (full or shortened) that exists in the repository. Returns the resolved full OID.
import { gitCommit } from "@optique/git";
import { option } from "@optique/core/primitives";
const commitParser = option("--commit", gitCommit());
// Usage: myapp revert --commit abc1234SHA formats supported
The parser accepts various SHA formats:
- Full 40-character SHA:
d670460b4b4aece5915caf5c68d12f560a9fe3e4 - Shortened SHAs (4+ characters):
d670460,d670460b4b4a
const result = await parseAsync(parser, ["-c", "550e840"]);
if (result.success) {
console.log(result.value); // Full 40-char OID
}gitRef()
A flexible parser that accepts any valid Git reference: branches, tags, or commits. Returns the resolved commit OID.
import { gitRef } from "@optique/git";
import { argument } from "@optique/core/primitives";
const refParser = argument(gitRef());
// Accepts: branch names, tags, or commit SHAs
// Returns: resolved commit OIDcreateGitParsers()
A factory function for creating multiple Git parsers with shared configuration.
import { createGitParsers } from "@optique/git";
import { option } from "@optique/core/primitives";
const git = createGitParsers({
dir: "/path/to/repo",
});
const parser = option("--branch", git.branch());
const tagParser = option("--tag", git.tag());
const commitParser = option("--commit", git.commit());Example with custom options per parser
import { createGitParsers } from "@optique/git";
const git = createGitParsers({
dir: "/path/to/repo",
metavar: "REF",
});
// Override metavar for specific parser
const branchParser = git.branch({ metavar: "BRANCH_NAME" });Async mode
All Git parsers operate in async mode because they perform I/O operations to read the Git repository:
import { gitBranch } from "@optique/git";
import { argument } from "@optique/core/primitives";
const parser = argument(gitBranch());
// parser.$mode === "async"Use parseAsync() with async parsers:
const result = await parseAsync(parser, ["main"]);
if (result.success) {
console.log(result.value); // "main"
}Suggestions
Git parsers provide intelligent completion suggestions:
import { gitBranch, gitTag, gitRef } from "@optique/git";
import { argument } from "@optique/core/primitives";
// Suggests existing branches
const branchParser = argument(gitBranch());
// Completing "fe" suggests: "feature/*", "fix/*", etc.
// Suggests existing tags
const tagParser = argument(gitTag());
// Completing "v1" suggests: "v1.0.0", "v1.1.0", etc.
// Suggests both branches and tags
const refParser = argument(gitRef());
// Completing "v" suggests tags; completing "fe" suggests branchesError handling
Git parsers provide clear error messages:
$ myapp --branch nonexistent
Error: Branch nonexistent does not exist. Available branches: main, develop, feature/*.
$ myapp --tag v999.0.0
Error: Tag v999.0.0 does not exist. Available tags: v1.0.0, v2.0.0.
$ myapp --commit abc
Error: Commit abc does not exist. Provide a valid commit SHA.
$ myapp --ref nonexistent-ref
Error: Reference nonexistent-ref does not exist. Provide a valid branch, tag, or commit SHA.Custom error messages
You can customize error messages using the errors option with the Message type from @optique/core/message:
import { gitBranch } from "@optique/git";
import { message, valueSet } from "@optique/core/message";
const parser = gitBranch({
errors: {
notFound: (input, available) =>
message`Branch ${input} not found. Available: ${
available ? valueSet(available) : "none"
}`,
listFailed: (dir) =>
message`Cannot read git repository at ${dir}`,
}
});Error types
The errors option supports the following error types:
notFound(input, available?)— Called when the git reference is not found. Provides the invalid input and optionally a list of available references.listFailed(dir)— Called when listing git references fails, typically when the directory is not a valid git repository.invalidFormat(input)— Called for commit SHA validation failures when the input format is invalid (e.g., too short).
Example with gitCommit
import { gitCommit } from "@optique/git";
import { message } from "@optique/core/message";
const parser = gitCommit({
errors: {
invalidFormat: (input) =>
message`${input} must be 4-40 characters.`,
notFound: (input) =>
message`Commit ${input} not found in repository.`,
}
});Example with createGitParsers
import { createGitParsers } from "@optique/git";
import { message } from "@optique/core/message";
const git = createGitParsers({
errors: {
notFound: (input, available) =>
message`${input} is not a valid reference.`,
}
});
const branchParser = git.branch();
const tagParser = git.tag();
const commitParser = git.commit();Metavar defaults
Each parser uses an appropriate default metavar for help text:
| Parser | Default metavar |
|---|---|
gitBranch() | "BRANCH" |
gitTag() | "TAG" |
gitRemote() | "REMOTE" |
gitRemoteBranch() | "BRANCH" |
gitCommit() | "COMMIT" |
gitRef() | "REF" |
Override with the metavar option:
import { gitBranch, gitTag } from "@optique/git";
const branchParser = gitBranch({ metavar: "BRANCH_NAME" });
const tagParser = gitTag({ metavar: "RELEASE_VERSION" });Exported utilities
The package also re-exports several utilities from isomorphic-git for advanced use cases:
import { expandOid, listBranches, listTags, listRemotes, readObject, resolveRef } from "@optique/git";expandOid()— Expand short SHAs to full OIDslistBranches()— List all local brancheslistTags()— List all tagslistRemotes()— List all remotesreadObject()— Read a Git objectresolveRef()— Resolve a ref to its OID
Complete example
A Git-like CLI application using Git parsers:
const result = await parseAsync(app, ["checkout", "-b", "develop", "main"]);
if (result.success) {
console.log(result.value);
}