Automatic semantic versioning from git history for trunk-based development
npm install @arcmantle/prospectorSemantic versioning made simple. Calculate versions automatically from your git history using trunk-based development.
Prospector is a tool that generates semantic versions (semver) for your project based on git commits. Instead of manually updating version numbers, Prospector reads your git history and commit messages to calculate the current version automatically.
Perfect for:
- Trunk-based development workflows
- Automated CI/CD pipelines
- Projects that want automatic versioning without manual intervention
- Teams that need consistent versioning across repositories
``bashInstall
pnpm add -D @arcmantle/prospector
Using in GitHub Actions
The primary way to use Prospector is in CI/CD pipelines. Add it to your workflow to automatically version your packages:
`yaml
name: Publish Packageon:
push:
branches: [main]
jobs:
publish:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0 # Required: fetch all history for version calculation
- uses: actions/setup-node@v4
with:
node-version: 24
registry-url: https://registry.npmjs.org/
# Calculate version using Prospector
- name: Calculate version
id: version
uses: arcmantle/prospector@v1
with:
dir: '.' # Optional: defaults to repository root
# Use the calculated version
- name: Set package version
run: |
echo "Setting version to ${{ steps.version.outputs.version }}"
npm version ${{ steps.version.outputs.version }} --no-git-tag-version
- name: Publish to NPM
run: npm publish
env:
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
`$3
| Input | Description | Default |
| ------- | ------------- | --------- |
|
dir | Repository directory path | '.' |
| branch | Main branch name(s) | 'main' (also recognizes 'master') |
| prefix | Version tag prefix | 'v' |
| no-commit-bumps | Disable commit message bumping | false |$3
| Output | Description |
| -------- | ------------- |
|
version | The calculated semantic version (e.g., 1.2.5) |
| branch | Current branch name |
| is-main-branch | 'true' if on main branch, 'false' otherwise |
| commits-since-tag | Number of commits since last version tag |$3
Only publish on main branch with new commits:
`yaml
- name: Calculate version
id: version
uses: arcmantle/prospector@v1- name: Publish to NPM
if: steps.version.outputs.is-main-branch == 'true' && steps.version.outputs.commits-since-tag != '0'
run: npm publish
env:
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
`Key Features
- 🚀 Smart Version Calculation: Automatically determines versions from git history
- 💬 Commit Message Bumps: Use
[major], [minor], [patch] in commit messages for explicit version control
- 🏷️ Tag-Based Releases: Create git tags for official version markers
- 🌿 Branch-Aware: Different versioning for main branch vs feature branches
- ⚡ Lightning Fast: Optimized for repositories with millions of commits
- 🔧 Flexible: CLI tool or programmatic API
- 📦 Zero Config: Works out of the box with sensible defaults
- ⚙️ GitHub Action: Use in CI/CD pipelines (see GitHub Action docs)How It Works
$3
1. On main branch: Version increments based on commits and tags
2. On feature branches: Version gets a prerelease suffix (e.g.,
1.2.3-feature.5)
3. Git tags set versions: Create tags like v1.0.0 to mark releases$3
`bash
Start: No tags, 10 commits on main
prospector → 0.0.10Tag a release
git tag v1.0.0Make 3 more commits
prospector → 1.0.3Create feature branch with 2 commits
git checkout -b feature/awesome
prospector → 1.0.1-feature-awesome.2Merge back to main
git checkout main
git merge feature/awesome
prospector → 1.0.4
`Installation
`bash
npm
npm install -D @arcmantle/prospectorpnpm
pnpm add -D @arcmantle/prospectoryarn
yarn add -D @arcmantle/prospector
`Or use as a GitHub Action - see GitHub Action docs for details.
Usage
$3
`bash
Get the current version
prospectorOutput as JSON
prospector --jsonShow detailed information
prospector --detailedSuggest next version for a release
prospector --suggest minor
prospector --suggest majorUse custom repository path
prospector --dir /path/to/repoUse custom branch name and tag prefix
prospector --branch master --prefix version-Default supports both 'main' and 'master' automatically
No need to specify --branch unless using a different name
`$3
-
-h, --help - Show help message
- -d, --dir - Git repository path (default: current directory)
- -b, --branch - Main/trunk branch name (default: both main and master are recognized)
- -p, --prefix - Version tag prefix (default: v)
- --json - Output as JSON
- --detailed - Output detailed information
- --suggest - Suggest next version (major, minor, or patch)
- --no-commit-bumps - Disable commit message based version bumping$3
`typescript
import { calculateVersion, suggestVersionBump } from '@arcmantle/prospector';// Get current version
const info = await calculateVersion({
cwd: '/path/to/repo',
tagPrefix: 'v'
});
console.log(info.version); // "1.2.5"
console.log(info.commitBumps); // { major: 0, minor: 2, patch: 1, explicitVersion: null }
// Suggest next version
const next = await suggestVersionBump('minor');
console.log(next); // "1.3.0"
`#### Configuration Options
`typescript
await calculateVersion({
// Repository path (default: current directory)
cwd: '/path/to/repo', // Main branch names (default: ['main', 'master'])
mainBranch: 'develop',
// Or multiple: mainBranch: ['main', 'master', 'trunk'],
// Tag prefix (default: 'v')
tagPrefix: 'version-',
// Enable commit message bumping (default: true)
enableCommitBumps: true,
// Custom commit patterns
commitBumpPatterns: {
major: /BREAKING|!:/i,
minor: /feature:|feat:/i,
patch: /fix:|bugfix:/i
},
// Progress callback
onProgress: (msg) => console.log(msg)
});
`Versioning Behavior
$3
On your main branch, Prospector uses commit messages to determine version bumps:
#### Commit Message Markers
Add these markers to your commit messages for explicit version control:
| Marker | Effect | Example |
|-------------------|------------------------------------|--------------------------------------------------------|
|
[major] | Bump major version (2.0.0 → 3.0.0) | git commit -m "[major] Breaking API changes" |
| [minor] | Bump minor version (1.2.0 → 1.3.0) | git commit -m "[minor] Add new feature" |
| [patch] | Bump patch version (1.2.3 → 1.2.4) | git commit -m "[patch] Fix bug" |
| [version:x.y.z] | Set exact version | git commit -m "[version:2.5.0] Release 2.5.0" |
| [v:x.y.z] | Set exact version (short) | git commit -m "[v:1.0.0] Initial release" |#### How Bumps Work
- Explicit versions (
[version:x.y.z]) take absolute precedence
- Multiple bump indicators accumulate (e.g., 3 [minor] = +3 to minor version)
- When major bumps, minor and patch reset to 0
- When minor bumps, patch resets to 0
- If no explicit bumps found, falls back to commit count#### Optimized Scanning (Default)
Prospector is extremely fast even with millions of commits. It uses git's internal indexes to find only commits with bump markers:
Why it's fast:
- Only fetches commits containing
[major], [minor], [patch], or [version:x.y.z]
- Uses git log --grep (built-in git optimization)
- Early stops when explicit version found
- Typical repositories: <1% of commits have markersPerformance examples:
- 100K commits, 50 with markers → ~0.2s, ~500KB memory
- 1M commits, 100 with markers → ~0.3s, ~1MB memory
- 10M commits, 200 with markers → ~0.5s, ~2MB memory
No configuration needed - it just works fast out of the box!
#### Legacy Scan Limit (Optional)
For edge cases or specific performance requirements, you can enable a scan limit:
`typescript
// Only if you experience performance issues
calculateVersion({ maxCommitScan: 1000 })
`When
maxCommitScan is set, Prospector falls back to the legacy scanning mode that fetches all commits up to the limit. This is generally not needed with the optimized approach.#### Tagging Best Practices
Use git tags to mark official releases:
`bash
Work with commit markers
git commit -m "[minor] Add feature A"
git commit -m "[patch] Fix bug"
git commit -m "[minor] Add feature B"Mark official release
git tag v1.5.0
git push --tagsContinue development
git commit -m "[patch] Quick fix"
prospector → 1.5.1
`Why tag?
- Tags mark stable release points
- Makes version history clear
- Allows easy rollback to specific versions
- Prevents hundreds of bump markers from accumulating
$3
Feature branches automatically get prerelease versions:
Format:
{base_version}-{branch_name}.{commit_count}Example:
`bash
On main: v1.2.0 exists
git checkout -b feature/awesome-thingMake 3 commits
prospector → 1.2.1-feature-awesome-thing.3
`How it works:
1. Find last version tag (
v1.2.0)
2. Increment patch by 1 (1.2.1)
3. Add branch name (sanitized) and commit count as prereleaseThis makes it clear the version is:
- Not an official release
- Based on version 1.2.0
- From the "feature-awesome-thing" branch
- 3 commits ahead
$3
When no git tags exist:
- Main branch:
0.0.{total_commits}
- Example: 15 commits → 0.0.15
- Feature branch: 0.0.1-{branch_name}.{total_commits}
- Example: 8 commits on feature/init → 0.0.1-feature-init.8Create your first tag when ready to release:
`bash
git tag v1.0.0
git push --tags
`Advanced Usage
$3
For maximum speed, disable commit message scanning:
`bash
CLI
prospector --no-commit-bumpsAPI
await calculateVersion({ enableCommitBumps: false })
`This uses only commit count, no message parsing. Version is simply
{tag} + {commit_count}.$3
Match your team's commit conventions:
`typescript
await calculateVersion({
commitBumpPatterns: {
major: /BREAKING CHANGE|!:/i,
minor: /^feat:/i,
patch: /^fix:/i
}
});
`Now commits like
feat: add dashboard will bump minor version.$3
If you experience issues (very rare), you can limit commit scanning:
`typescript
await calculateVersion({
maxCommitScan: 1000 // Only scan last 1000 commits
})
`Note: This is rarely needed. The default optimized mode handles millions of commits efficiently.
API Reference
$3
Calculates the current version based on git history.
Parameters:
-
options.cwd - Repository path (default: '.')
- options.mainBranch - Main/trunk branch name(s). Can be a string or array of strings (default: ['main', 'master'] - both are recognized as trunk branches)
- options.tagPrefix - Tag prefix (default: 'v')
- options.enableCommitBumps - Enable commit message bumping (default: true)
- options.maxCommitScan - Optional limit on commits to scan. Only set this if you experience performance issues. When undefined (default), uses optimized git grep scanning with no limit.
- options.commitBumpPatterns - Custom regex patterns for detecting bumpsReturns:
VersionInfo object with:-
version - The calculated version string
- branch - Current branch name
- isMainBranch - Whether on main branch
- commitsSinceTag - Number of commits since last tag
- lastTag - Last version tag info (or null)
- currentCommit - Current commit hash
- commitBumps - Object with { major, minor, patch, explicitVersion } counts from commit messages$3
Suggests the next version for a given bump type.
Parameters:
-
bumpType - 'major', 'minor', or 'patch'
- options - Same as calculateVersionReturns: Version string (e.g.,
'2.0.0')Performance
Prospector is extremely fast even with millions of commits:
$3
- Optimized git operations: Uses
git log --grep to scan only commits with bump markers
- Typical case: <1% of commits have version markers, so we only process <1%
- Early termination: Stops when explicit version found
- Smart counting: Uses git rev-list --count (O(1) operation)$3
|Repository Size|Commits with Bumps|Time |Memory|
|---------------|------------------|------|------|
|1K commits |20 |< 0.1s|< 1MB |
|10K commits |50 |< 0.2s|< 1MB |
|100K commits |100 |< 0.3s|< 2MB |
|1M commits |200 |< 0.5s|< 3MB |
|10M commits |500 |< 1s |< 5MB |
With
--no-commit-bumps: All sizes run in < 0.1s.Quick Reference
$3
`bash
Major version bump (1.0.0 → 2.0.0)
git commit -m "[major] Breaking API changes"Minor version bump (1.0.0 → 1.1.0)
git commit -m "[minor] New reporting feature"Patch version bump (1.0.0 → 1.0.1)
git commit -m "[patch] Fix bug in login"Set exact version
git commit -m "[version:2.5.0] Release version 2.5.0"
git commit -m "[v:1.3.7] Align with upstream"No explicit bump (uses commit count for patch)
git commit -m "Update README"
`See docs/COMMIT_SYNTAX.md for more details on commit message patterns.
$3
`bash
Get current version
prospectorShow detailed information including commit bumps
prospector --detailedDisable commit message bumping
prospector --no-commit-bumpsSuggest next minor release
prospector --suggest minorUse in different directory
prospector --dir /path/to/repo
``MIT