A guided conventional commit message wizard — right inside VS Code's Source Control panel.
Inspired by the better-commits CLI, this extension brings the same structured commit workflow into VS Code's native UI. No terminal needed — just Quick Picks, input boxes, and your SCM commit input.
- Guided wizard — step-by-step Quick Pick flow for composing conventional commits
- Branch-aware — auto-infers commit type and ticket/issue from your branch name
- SCM integration — composed message goes straight into the Source Control input box
- Config-compatible — uses the same
.better-commits.jsonformat as the CLI - Fully configurable — custom types, scopes, emoji, ticket formats, footers, and more
- Multi-repo support — works with VS Code multi-root workspaces
- Install the extension
- Open a Git repository in VS Code
- Click the ✏️ icon in the Source Control title bar (or run
Better Commits: Compose Commit Messagefrom the Command Palette) - Walk through the wizard
- Your message appears in the commit input box — click ✓ to commit
The wizard guides you through each part of a conventional commit:
| Step | Prompt | Details |
|---|---|---|
| 1 | Commit type | feat, fix, docs, refactor, etc. Auto-inferred from branch name |
| 2 | Commit scope | app, auth, api, or custom input |
| 3 | Ticket / issue | Auto-inferred from branch (e.g., feat/PROJ-42 → PROJ-42) |
| 4 | Title | Brief description with live character count validation |
| 5 | Body | Detailed description (optional) |
| 6 | Footers | Breaking changes, deprecations, closes, trailers, custom |
Given branch feat/PROJ-42_add-authentication:
feat(auth): #PROJ-42 add OAuth2 login flow
Added Google and GitHub OAuth2 providers.
Includes token refresh logic.
Closes: #PROJ-42
Changelog: feature
The extension reads configuration from .better-commits.json, checked in this order:
- Workspace root —
.better-commits.jsonin your repo root (highest priority) - Home directory —
~/.better-commits.json(global defaults) - Built-in defaults — sensible out-of-the-box values
Both files are deep-merged: repo config overrides global, global overrides defaults.
Tip: If you already use the
better-commitsCLI, your existing config works as-is!
Click to expand full config reference
The extension extracts ticket/issue identifiers from your branch name using these patterns:
| Branch Pattern | Extracted Ticket |
|---|---|
feat/PROJ-123 |
PROJ-123 |
PROJ-456-fix-bug |
PROJ-456 |
feat/PROJ-789_description |
PROJ-789 |
feat/42 |
42 |
123-fix-something |
123 |
| Branch Pattern | Inferred Type |
|---|---|
feat/add-login |
feat |
fix-crash-on-load |
fix |
user-chore-cleanup |
chore |
title_position |
Result |
|---|---|
"start" |
feat(auth): #PROJ-42 add login |
"end" |
feat(auth): add login #PROJ-42 |
"before-colon" |
feat(auth) #PROJ-42: add login |
"beginning" |
#PROJ-42 feat(auth): add login |
| Setting | Default | Description |
|---|---|---|
betterCommits.configFile |
.better-commits.json |
Config file name to search for in the workspace root |
| Command | Description |
|---|---|
Better Commits: Compose Commit Message |
Launch the commit wizard |
Accessible via:
- SCM title bar — the ✏️ icon (visible when a Git repo is open)
- Command Palette —
Ctrl+Shift+P→ type "Better Commits"
src/
extension.ts → Activation, command registration, Git API integration
commit-wizard.ts → Multi-step Quick Pick wizard flow
commit-builder.ts → Commit message string construction
config.ts → .better-commits.json loading and merging
git-helpers.ts → Branch detection, type/ticket inference
types.ts → TypeScript interfaces and default values
The extension uses VS Code's built-in Git extension API to:
- Detect repositories in the workspace
- Read the current branch name
- Write the composed message to the SCM input box
# Unit tests (40 tests, no VS Code needed)
npm run test:unit
# Integration tests (launches VS Code Extension Host)
npm run test:integration
# E2E verification against sample repo
node dist/test/verify-e2e.jsSee TESTING.md for detailed instructions.
This extension is designed to be a companion to the better-commits CLI. They share the same .better-commits.json config format, so teams can use either tool interchangeably:
- CLI users → run
better-commitsin the terminal - VS Code users → click the ✏️ button in Source Control
One config file. Two interfaces. Same conventional commits.
MIT — Based on better-commits by Erik Verduin.
{ // ── Commit Type ────────────────────────────────────────── "commit_type": { "enable": true, // Show type selection step "initial_value": "feat", // Pre-selected type "max_items": 20, // Max items in picker "infer_type_from_branch": true, // Auto-detect from branch name "append_emoji_to_label": false, // Show emoji in picker labels "append_emoji_to_commit": false, // Include emoji in commit message "emoji_commit_position": "Start", // "Start" or "After-Colon" "options": [ { "value": "feat", "label": "feat", "hint": "A new feature", "emoji": "🌟", "trailer": "Changelog: feature" }, { "value": "fix", "label": "fix", "hint": "A bug fix", "emoji": "🐛", "trailer": "Changelog: fix" } // ... add more types as needed ] }, // ── Commit Scope ───────────────────────────────────────── "commit_scope": { "enable": true, // Show scope selection step "custom_scope": false, // Allow freeform scope input "max_items": 20, // Max items in picker "initial_value": "app", // Pre-selected scope "options": [ { "value": "app", "label": "app" }, { "value": "shared", "label": "shared" }, { "value": "server", "label": "server" }, { "value": "tools", "label": "tools" }, { "value": "", "label": "none" } ] }, // ── Ticket / Issue ─────────────────────────────────────── "check_ticket": { "infer_ticket": true, // Auto-infer from branch name "confirm_ticket": true, // Show confirmation/edit prompt "add_to_title": true, // Include ticket in commit title "append_hashtag": false, // Add # to inferred tickets "prepend_hashtag": "Never", // "Never" | "Always" | "Prompt" "surround": "", // "" | "()" | "[]" | "{}" "title_position": "start" // "start" | "end" | "before-colon" | "beginning" }, // ── Commit Title ───────────────────────────────────────── "commit_title": { "max_size": 70 // Max total title length }, // ── Commit Body ────────────────────────────────────────── "commit_body": { "enable": true, // Show body input step "required": false, // Make body mandatory "split_by_period": false // Auto-split sentences into lines }, // ── Commit Footer ──────────────────────────────────────── "commit_footer": { "enable": true, // Show footer selection step "initial_value": [], // Pre-selected footers "options": [ // Available footer types "closes", "trailer", "breaking-change", "deprecated", "custom" ] }, // ── Breaking Change ────────────────────────────────────── "breaking_change": { "add_exclamation_to_title": true // Add ! to type for breaking changes } }