git/
Git operations for versioning workflows with secure command execution.
Overview
This module provides a complete interface for git operations needed in versioning workflows: querying commit history, managing tags, staging files, and inspecting repository status. All command arguments are validated character-by-character to prevent command injection attacks.
API
Models
| Export |
Description |
Implementation |
GitCommit |
Commit with hash, author, date, subject, body, refs |
commit.ts |
GitTag |
Tag with name, commitHash, type (lightweight/annotated) |
tag.ts |
GitTagType |
'lightweight' | 'annotated' |
tag.ts |
GitRef |
Reference with fullName, name, type, commitHash |
ref.ts |
GitRefType |
'branch' | 'tag' | 'remote' | 'head' | 'stash' |
ref.ts |
RepositoryStatus |
Full repository status with branch, staged, modified |
status.ts |
FileStatus |
'added' | 'modified' | 'deleted' | 'renamed' ... |
status.ts |
FileStatusEntry |
File path with its status |
status.ts |
FileChange |
File change with path, status, and optional oldPath |
diff.ts |
FileChangeStatus |
'added' | 'modified' | 'deleted' | 'renamed' ... |
diff.ts |
GitCommitWithFiles |
GitCommit extended with changed files |
diff.ts |
Model Factories
| Function |
Description |
Implementation |
createGitCommit(opts) |
Create a GitCommit object |
commit.ts |
createLightweightTag() |
Create a lightweight tag |
tag.ts |
createAnnotatedTag() |
Create an annotated tag |
tag.ts |
createGitRef(opts) |
Create a GitRef from full ref name |
ref.ts |
Model Utilities
| Function |
Description |
Implementation |
getShortHash(hash) |
Get 7-character abbreviated hash |
commit.ts |
isSameCommit(a, b) |
Compare commits by hash |
commit.ts |
isMergeCommit(commit) |
Check if commit has multiple parents |
commit.ts |
isRootCommit(commit) |
Check if commit has no parents |
commit.ts |
extractScope(subject) |
Extract scope from conventional commit |
commit.ts |
extractType(subject) |
Extract type from conventional commit |
commit.ts |
isAnnotatedTag(tag) |
Check if tag is annotated |
tag.ts |
isLightweightTag(tag) |
Check if tag is lightweight |
tag.ts |
extractVersionFromTag |
Extract version string from tag name |
tag.ts |
extractPackageFromTag |
Extract package name from tag name |
tag.ts |
buildTagName(pkg, ver) |
Build tag name from package and version |
tag.ts |
compareTagsByVersion |
Compare tags by extracted version (descending) |
tag.ts |
isBranchRef(ref) |
Check if ref is a branch |
ref.ts |
isTagRef(ref) |
Check if ref is a tag |
ref.ts |
isRemoteRef(ref) |
Check if ref is a remote tracking branch |
ref.ts |
isHeadRef(ref) |
Check if ref is HEAD |
ref.ts |
buildRefName(type, n) |
Build full ref name from type and short name |
ref.ts |
filterRefsByType() |
Filter refs by type |
ref.ts |
filterRefsByRemote() |
Filter refs by remote name |
ref.ts |
Git Client Factory
| Export |
Description |
Implementation |
createGitClient(config?) |
Create unified git client |
factory.ts |
GitClient |
Interface with all git operations |
factory.ts |
GitClientConfig |
Config: cwd, timeout, throwOnError |
factory.ts |
DEFAULT_GIT_CLIENT_CONFIG |
Default configuration values |
factory.ts |
Log Operations
| Function |
Description |
Implementation |
getCommitLog(opts) |
Get commit history |
log.ts |
getCommitsBetween() |
Get commits between two refs |
log.ts |
getCommitsSince() |
Get commits since a ref |
log.ts |
getCommit(hash) |
Get single commit by hash |
log.ts |
commitExists(hash) |
Check if commit exists |
log.ts |
Diff Operations
| Function |
Description |
Implementation |
getChangedFilesBetween() |
Get file paths changed between refs |
diff.ts |
getChangedFilesBetweenWithStatus() |
Get files with status (add/mod/del) |
diff.ts |
getCommitWithFiles(hash) |
Get commit with its changed files |
diff.ts |
Tag Operations
Commit Operations
| Function |
Description |
Implementation |
commit(message) |
Create a commit with message |
commit.ts |
stage(files) |
Stage files for commit |
stage.ts |
unstage(files) |
Unstage files |
stage.ts |
stageAll() |
Stage all changes |
stage.ts |
amendCommit() |
Amend the last commit |
commit.ts |
createEmptyCommit() |
Create an empty commit |
commit.ts |
getHead() |
Get HEAD commit hash |
head-info.ts |
getCurrentBranch() |
Get current branch name |
head-info.ts |
hasStagedChanges() |
Check for staged changes |
stage.ts |
hasUnstagedChanges() |
Check for unstaged changes |
stage.ts |
hasUntrackedFiles() |
Check for untracked files |
head-info.ts |
discardChanges() |
Discard uncommitted changes |
stage.ts |
discardAllChanges() |
Discard and unstage all |
stage.ts |
Status Operations
| Function |
Description |
Implementation |
getStatus() |
Get full repository status |
status.ts |
isClean() |
Check if working tree is clean |
status.ts |
isGitRepository() |
Check if path is a git repository |
status.ts |
getRepositoryRoot() |
Get repository root path |
status.ts |
getHeadHash() |
Get HEAD commit hash |
head-info.ts |
getHeadShortHash() |
Get abbreviated HEAD hash |
head-info.ts |
hasConflicts() |
Check for merge conflicts |
status.ts |
getAheadCount() |
Get commits ahead of upstream |
status.ts |
getBehindCount() |
Get commits behind upstream |
status.ts |
needsPush() |
Check if push is needed |
status.ts |
needsPull() |
Check if pull is needed |
status.ts |
getStagedFiles() |
Get list of staged files |
status.ts |
getModifiedFiles() |
Get list of modified files |
status.ts |
getUntrackedFiles() |
Get list of untracked files |
status.ts |
Operation State
| Function |
Description |
Implementation |
getOperationState() |
Detect if git is mid-operation |
operation-state.ts |
isOperationInProgress() |
Check if rebase/merge is in progress |
operation-state.ts |
GitOperationState |
Result with inProgress, reason, details |
operation-state.ts |
GitOperationStateReason |
'rebase-interactive' | 'rebase-apply' | 'merge-in-progress' |
operation-state.ts |
Security Utilities
| Function |
Description |
Implementation |
escapeGitRef(ref) |
Validate ref for safe shell use |
factory.ts |
escapeGitPath(path) |
Validate path for safe shell use |
factory.ts |
escapeGitArg(arg) |
Validate generic argument for safe shell use |
factory.ts |
escapeFilePath(path) |
Validate file path for safe shell use |
factory.ts |
escapeAuthor(author) |
Validate author string for safe shell use |
factory.ts |
escapeGitTagPattern() |
Validate tag pattern for safe shell use |
factory.ts |
escapeGitMessage() |
Escape message for safe shell use |
factory.ts |
Usage Examples
Using GitClient (Recommended)
import { createGitClient } from '@hyperfrontend/versioning'
const git = createGitClient({ cwd: '/path/to/repo' })
// Get recent commits
const commits = git.getCommitLog({ maxCount: 10 })
// Get commits since last release
const newCommits = git.getCommitsSince('v1.0.0')
// Get files changed between refs
const changedFiles = git.getChangedFilesBetween('origin/main', 'HEAD')
const changesWithStatus = git.getChangedFilesBetweenWithStatus('v1.0.0', 'v2.0.0')
// Get commit with file details
const commitWithFiles = git.getCommitWithFiles('abc1234')
if (commitWithFiles) {
for (const file of commitWithFiles.files) {
console.log(`${file.status}: ${file.path}`)
}
}
// Check repository state
if (git.isClean()) {
// Create a tag
git.createTag('v1.1.0', { message: 'Release v1.1.0' })
}
// Check for in-progress operations before committing
const state = git.getOperationState()
if (state.inProgress) {
console.warn(`Cannot proceed: git ${state.reason} in progress`)
}
Standalone Operations
import {
getCommitsBetween,
getTags,
getLatestTag,
commit,
stage,
getChangedFilesBetween,
getChangedFilesBetweenWithStatus,
getCommitWithFiles,
} from '@hyperfrontend/versioning'
// Get commits between tags
const commits = getCommitsBetween('v1.0.0', 'v2.0.0')
console.log(`${commits.length} commits between releases`)
// Get files changed since main
const changedFiles = getChangedFilesBetween('origin/main', 'HEAD')
console.log(`${changedFiles.length} files changed`)
// Get files with status information
const changes = getChangedFilesBetweenWithStatus('v1.0.0', 'v2.0.0')
const added = changes.filter((c) => c.status === 'added')
const deleted = changes.filter((c) => c.status === 'deleted')
console.log(`${added.length} added, ${deleted.length} deleted`)
// Get commit with file details for changelog attribution
const commitWithFiles = getCommitWithFiles('abc1234')
if (commitWithFiles) {
console.log(`${commitWithFiles.subject} touched ${commitWithFiles.files.length} files`)
}
// Find latest version tag
const latest = getLatestTag({ pattern: '@scope/pkg@' })
console.log(`Latest: ${latest?.name}`)
// Stage and commit
stage(['package.json', 'CHANGELOG.md'])
commit('chore: release v1.1.0')
Working with Tags
import { extractVersionFromTag, extractPackageFromTag, buildTagName, getTagsForPackage } from '@hyperfrontend/versioning'
// Parse tag names
extractVersionFromTag('v1.2.3') // '1.2.3'
extractVersionFromTag('@scope/pkg@1.0.0') // '1.0.0'
extractPackageFromTag('@scope/pkg@1.0.0') // '@scope/pkg'
extractPackageFromTag('utils@1.2.3') // 'utils'
// Build tag names
buildTagName('@scope/pkg', '2.0.0') // '@scope/pkg@2.0.0'
buildTagName('lib', '1.0.0', '${package}-v${version}') // 'lib-v1.0.0'
// Get all tags for a package
const tags = getTagsForPackage('@hyperfrontend/versioning')
Working with Commits
import { createGitCommit, isMergeCommit, extractType, extractScope } from '@hyperfrontend/versioning'
// Parse conventional commits
const subject = 'feat(lib-versioning): add git operations'
extractType(subject) // 'feat'
extractScope(subject) // 'lib-versioning'
// Check commit characteristics
if (isMergeCommit(commit)) {
console.log('Skipping merge commit')
}
Security
All user input undergoes character-by-character validation before being used in shell commands:
- No regex: Eliminates ReDoS vulnerabilities
- Allowlist validation: Only permitted characters pass through
- Length limits: Prevents memory exhaustion attacks
- No shell interpolation: Arguments are validated, not escaped-and-quoted
Allowed Characters by Function
| Function |
Allowed Characters |
escapeGitRef |
a-z A-Z 0-9 / - _ . @ ~ ^ { } |
escapeGitPath |
a-z A-Z 0-9 / - _ . (space) |
escapeFilePath |
a-z A-Z 0-9 / - _ . (space) |
escapeAuthor |
a-z A-Z 0-9 - _ . @ < > (space) |
escapeGitTagPattern |
a-z A-Z 0-9 / - _ . @ * |
Maximum Input Lengths
| Input Type |
Max Length |
| Git reference |
256 |
| File path |
4096 |
| Author string |
512 |
| Commit message |
10000 |
| Tag pattern |
256 |
See Also