{"id":15035885,"url":"https://github.com/everduin94/better-commits","last_synced_at":"2026-05-31T02:02:53.489Z","repository":{"id":140991694,"uuid":"611748490","full_name":"Everduin94/better-commits","owner":"Everduin94","description":"A CLI for creating better commits following the conventional commits specification","archived":false,"fork":false,"pushed_at":"2026-05-31T00:02:14.000Z","size":502,"stargazers_count":2283,"open_issues_count":8,"forks_count":80,"subscribers_count":13,"default_branch":"main","last_synced_at":"2026-05-31T00:15:50.456Z","etag":null,"topics":["clack","cli","commit-message","git","typescript","zod"],"latest_commit_sha":null,"homepage":"","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/Everduin94.png","metadata":{"files":{"readme":"readme.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2023-03-09T13:17:22.000Z","updated_at":"2026-05-30T22:50:17.000Z","dependencies_parsed_at":null,"dependency_job_id":"ce8a1ec8-f09a-4715-bfae-9e847d1320e4","html_url":"https://github.com/Everduin94/better-commits","commit_stats":null,"previous_names":[],"tags_count":55,"template":false,"template_full_name":null,"purl":"pkg:github/Everduin94/better-commits","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Everduin94%2Fbetter-commits","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Everduin94%2Fbetter-commits/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Everduin94%2Fbetter-commits/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Everduin94%2Fbetter-commits/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/Everduin94","download_url":"https://codeload.github.com/Everduin94/better-commits/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Everduin94%2Fbetter-commits/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":33716339,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-05-31T02:00:06.040Z","response_time":95,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["clack","cli","commit-message","git","typescript","zod"],"created_at":"2024-09-24T20:29:41.812Z","updated_at":"2026-05-31T02:02:53.483Z","avatar_url":"https://github.com/Everduin94.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"\u003ch3 align=\"center\"\u003e\n\n![bc-gradient](https://github.com/Everduin94/better-commits/assets/14320878/2f94e6ea-a40f-4f3e-b0b2-5cc7d83a9a7d)\n\n[![better commits is enabled](https://img.shields.io/badge/better--commits-enabled?style=for-the-badge\u0026logo=git\u0026color=a6e3a1\u0026logoColor=D9E0EE\u0026labelColor=302D41)](https://github.com/Everduin94/better-commits)\n[![downloads](https://img.shields.io/npm/dt/better-commits.svg?style=for-the-badge\u0026logo=npm\u0026color=74c7ec\u0026logoColor=D9E0EE\u0026labelColor=302D41)](https://npmx.dev/package/better-commits)\n[![discord](https://img.shields.io/badge/discord-join--discord?style=for-the-badge\u0026logo=discord\u0026color=cba6f7\u0026logoColor=D9E0EE\u0026labelColor=302D41)](https://discord.gg/grHVnZwYup)\n\n\u003c/h3\u003e\n\n\u003cp align=\"center\"\u003e\nA CLI for writing better commits, following the conventional commits specification.\n\u003c/p\u003e\n\n\u003cvideo src=\"https://github.com/Everduin94/better-commits/assets/14320878/8fb15d46-17c4-4e5d-80d9-79abe0a2a00a\"\u003e\u003c/video\u003e\n\n## ✨ Features\n\n- Generate conventional commits through a series of prompts\n- Highly configurable with sane defaults\n- Infers ticket, commit scope, and commit-type from branch for consistent \u0026 fast commits\n- Consistent branch creation with flexible workflow hooks via `better-branch`\n- Interactive git status/add on commit\n- Preview commit messages in color\n- Support for git emojis per commit-type\n- Configure globally or per repository\n- Config validation and error messaging\n- [Lightweight](https://bundlejs.com/?q=better-commits\u0026treeshake=%5B*%5D) (17kb)\n\nAs a side-effect of formatting messages\n\n- Auto populate PR title / body\n- Automate semantic releases\n- Automate changelogs\n- Automatically link \u0026 close related tickets / issues\n\n## 📦 Installation\n\n\u003e Requires Node.js 20 or newer.\n\n```sh\nnpm install -g better-commits\n```\n\n## 🚀 Usage\n\nTo run the CLI in your terminal:\n\n```sh\nbetter-commits # Create a new commit\nbetter-branch # Create a new branch\n```\n\n`better-commits` will prompt a series of questions. These prompts will build a commit message, which you can preview, before confirming the commit. - To better understand these prompts and their intention, read [Conventional Commits Summary](https://www.conventionalcommits.org/en/v1.0.0-beta.4/#summary)\n\nSome of the values in these prompts will be inferred by your branch name and auto populated. You can adjust this in your `.better-commits.jsonc` (or `.better-commits.json`) configuration file.\n\nFor documentation on passing commit values to `better-commits` via the CLI, see [CLI Flags](#cli-flags).\n\n\u003e [!TIP]\n\u003e The `--no-interactive` flag, allows automated workflows or AI agents like OpenCode and Claude Code, to use better-commits to generate consistent commit messages using less tokens.\n\u003e\n\u003e Run `better-commits --help` / `better-branch --help` for more information.\n\n## ⚙️ Configuration\n\n### Global\n\nYour first time running `better-commits`, a default config will be generated in your `$HOME` directory, named `.better-commits.jsonc` (formerly `.better-commits.json`)\n\n- This config will be used if a repository-specific config cannot be found.\n\n### Repository\n\nTo create a **repository-specific config**, navigate to the root of your project.\n\n- Run `better-commits-init`\n- This will create a default config named `.better-commits.jsonc`\n- Properties such as `confirm_with_editor` and `overrides` will prefer the global config\n\n### 💫 Properties\n\n\u003e [!NOTE]\u003cbr\u003e\n\u003e All properties are optional and can be removed from the config. They will be replaced by the default at run-time.\n\u003e\n\u003e - See `.better-commits.json` in this repository as an example\n\n```jsonc\n{\n  // Run interactive `git status` before composing a commit\n  \"check_status\": true,\n  \"check_status_autocomplete\": true,\n\n  /* COMMIT FIELDS */\n  \"commit_type\": {\n    \"enable\": true,\n\n    // Default selected type from options\n    \"initial_value\": \"feat\",\n\n    \"max_items\": 20,\n\n    // Infer type from the current branch name: user/TYPE/my-branch\n    \"infer_type_from_branch\": true,\n\n    // Include emoji in prompt label\n    \"append_emoji_to_label\": false,\n\n    // Include emoji from prompt label in commit message\n    \"append_emoji_to_commit\": false,\n\n    // \"Start\" | \"After-Colon\"\n    \"emoji_commit_position\": \"Start\",\n\n    \"autocomplete\": true,\n\n    \"options\": [\n      {\n        \"value\": \"feat\",\n        \"label\": \"feat\",\n        \"hint\": \"A new feature\",\n        \"emoji\": \"🌟\",\n        \"trailer\": \"Changelog: feature\",\n      },\n      {\n        \"value\": \"fix\",\n        \"label\": \"fix\",\n        \"hint\": \"A bug fix\",\n        \"emoji\": \"🐛\",\n        \"trailer\": \"Changelog: fix\",\n      },\n      {\n        \"value\": \"docs\",\n        \"label\": \"docs\",\n        \"hint\": \"Documentation only changes\",\n        \"emoji\": \"📚\",\n        \"trailer\": \"Changelog: documentation\",\n      },\n      {\n        \"value\": \"refactor\",\n        \"label\": \"refactor\",\n        \"hint\": \"A code change that neither fixes a bug nor adds a feature\",\n        \"emoji\": \"🔨\",\n        \"trailer\": \"Changelog: refactor\",\n      },\n      {\n        \"value\": \"perf\",\n        \"label\": \"perf\",\n        \"hint\": \"A code change that improves performance\",\n        \"emoji\": \"🚀\",\n        \"trailer\": \"Changelog: performance\",\n      },\n      {\n        \"value\": \"test\",\n        \"label\": \"test\",\n        \"hint\": \"Adding missing tests or correcting existing tests\",\n        \"emoji\": \"🚨\",\n        \"trailer\": \"Changelog: test\",\n      },\n      {\n        \"value\": \"build\",\n        \"label\": \"build\",\n        \"hint\": \"Changes that affect the build system or external dependencies\",\n        \"emoji\": \"🚧\",\n        \"trailer\": \"Changelog: build\",\n      },\n      {\n        \"value\": \"ci\",\n        \"label\": \"ci\",\n        \"hint\": \"Changes to our CI configuration files and scripts\",\n        \"emoji\": \"🤖\",\n        \"trailer\": \"Changelog: ci\",\n      },\n      {\n        \"value\": \"chore\",\n        \"label\": \"chore\",\n        \"hint\": \"Other changes that do not modify src or test files\",\n        \"emoji\": \"🧹\",\n        \"trailer\": \"Changelog: chore\",\n      },\n      {\n        \"value\": \"\",\n        \"label\": \"none\",\n      },\n    ],\n  },\n\n  \"commit_scope\": {\n    \"enable\": true,\n\n    // If true, users can type a scope not listed in options\n    \"custom_scope\": false,\n\n    // Default selected scope from options\n    \"initial_value\": \"app\",\n\n    // Infer scope from the current branch name: user/type/ticket-SCOPE-my-branch\n    \"infer_scope_from_branch\": true,\n\n    \"max_items\": 20,\n    \"autocomplete\": true,\n    \"options\": [\n      { \"value\": \"app\", \"label\": \"app\" },\n      { \"value\": \"shared\", \"label\": \"shared\" },\n      { \"value\": \"server\", \"label\": \"server\" },\n      { \"value\": \"tools\", \"label\": \"tools\" },\n      { \"value\": \"\", \"label\": \"none\" },\n    ],\n  },\n\n  \"check_ticket\": {\n    // Infer ticket / issue from the branch name - user/type/TICKET-my-branch\n    \"infer_ticket\": true,\n\n    // Prompt for confirmation / edit before using an inferred ticket\n    \"confirm_ticket\": true,\n\n    // Add the ticket to the commit title - feat(app): TICKET my commit title\n    \"add_to_title\": true,\n\n    // Deprecated, prefer `prepend_hashtag`\n    \"append_hashtag\": false,\n\n    // \"Never\" | \"Prompt\" | \"Always\" - 12345 --\u003e #12345\n    \"prepend_hashtag\": \"Never\",\n\n    // Wrap the ticket in the commit title: \"\" | \"[]\" | \"()\" | \"{}\"\n    \"surround\": \"\",\n\n    // \"start\" | \"end\" | \"before-colon\" | \"beginning\"\n    \"title_position\": \"start\",\n  },\n\n  \"commit_title\": {\n    // Includes total size of title + type + scope + ticket\n    \"max_size\": 70,\n  },\n\n  \"commit_body\": {\n    \"enable\": true,\n    \"required\": false,\n\n    // Split sentences into multiple lines automatically\n    \"split_by_period\": false,\n  },\n\n  \"commit_footer\": {\n    \"enable\": true,\n    \"initial_value\": [],\n\n    // \"closes\", \"trailer\", \"breaking-change\", \"deprecated\", \"custom\"\n    \"options\": [\"closes\", \"trailer\", \"breaking-change\", \"deprecated\", \"custom\"],\n  },\n\n  \"breaking_change\": {\n    // Adds `!` to the commit title when a breaking change is selected\n    \"add_exclamation_to_title\": true,\n  },\n\n  // Confirm / edit with $GIT_EDITOR or $EDITOR\n  \"confirm_with_editor\": false,\n\n  // Show a final confirmation prompt before running git commit\n  \"confirm_commit\": true,\n\n  // Reuse the last known value from a previous canceled or failed commit\n  \"cache_last_value\": true,\n\n  // Pretty-print the final commit preview before execution\n  \"print_commit_output\": true,\n\n  /* BRANCH FIELDS */\n  // Optional shell commands to run before / after creating branches or worktrees\n  \"branch_pre_commands\": [],\n  \"branch_post_commands\": [],\n  \"worktree_pre_commands\": [],\n  \"worktree_post_commands\": [],\n\n  \"branch_user\": {\n    \"enable\": true,\n    \"required\": false,\n\n    // \"/\" | \"-\" | \"_\" - user/feat/my-branch\n    \"separator\": \"/\",\n  },\n\n  \"branch_type\": {\n    \"enable\": true,\n    \"separator\": \"/\",\n    \"autocomplete\": true,\n  },\n\n  \"branch_scope\": {\n    \"enable\": true,\n    \"separator\": \"-\",\n    \"autocomplete\": true,\n  },\n\n  \"branch_ticket\": {\n    \"enable\": true,\n    \"required\": false,\n    \"separator\": \"-\",\n  },\n\n  \"branch_version\": {\n    \"enable\": false,\n    \"required\": false,\n    \"separator\": \"/\",\n  },\n\n  \"branch_description\": {\n    // Maximum length for the description segment of the branch name\n    \"max_length\": 70,\n\n    // Allowed values: \"\" | \"/\" | \"-\" | \"_\"\n    \"separator\": \"\",\n  },\n\n  // \"branch\" | \"worktree\"\n  \"branch_action_default\": \"branch\",\n\n  // Order of values in the final branch name\n  \"branch_order\": [\"user\", \"version\", \"type\", \"ticket\", \"scope\", \"description\"],\n\n  // Deprecated, prefer `worktrees.enable`\n  \"enable_worktrees\": true,\n\n  \"worktrees\": {\n    // If false, always create a branch instead of prompting for a worktree\n    \"enable\": true,\n\n    // Directory where worktrees are created\n    \"base_path\": \"..\",\n\n    // Available template variables include:\n    // {{repo_name}}, {{branch_description}}, {{user}}, {{type}}, {{scope}}, {{ticket}}, {{version}}\n    \"folder_template\": \"{{repo_name}}-{{ticket}}-{{branch_description}}\",\n  },\n\n  /* OTHER FIELDS */\n  \"overrides\": {\n    // Useful on Windows or for shells with different multiline behavior\n    \"shell\": \"/bin/sh\",\n  },\n}\n```\n\n### 🔎 Inference\n\n`better-commits` will attempt to infer the ticket/issue, commit-type, and commit scope from your branch name. It will auto populate the corresponding field if found.\n\n**Ticket / Issue-Number**\n\n- If a `STRING-NUMBER` or `NUMBER` are at the start of the branch name or after a `/`\n\n**Commit Type**\n\n- If a type is at the start of the branch or is followed by a `/`\n\n**Commit Scope**\n\n- If a configured scope appears as its own branch word, separated by `/`, `-`, or `_`\n- If scope appears after a ticket, the expected shape is `TICKET-SCOPE-description`\n- Empty scope values and the `custom` scope option are ignored during inference\n\n## 🌳 Better Branch\n\nBetter branch is a secondary feature that works with better commits\n\n- Supports consistent branch naming conventions\n- Uses same type-list/prompt from your config\n- Enables better-commits to infer type, scope, and ticket\n- Caches your username for speedy branching\n- Convenient worktree creation\n\nTo run the CLI in your terminal:\n\n```sh\nbetter-branch\n```\n\n### Worktree Support\n\n`better-branch` will prompt for **Branch** or **Worktree**. The Worktree flow creates a folder/worktree from your **branch description** and a git branch inside with your **full branch name**.\n\n\u003e [!NOTE]\u003cbr\u003e\n\u003e Creating a worktree named `everduin94/feat/TAC-123-add-worktrees` with the native git command would create a nested folder for each `/`. `better-branch` removes the hassle by creating 1 folder while still using the full name for the branch.\n\n\u003e [!TIP]\n\u003e By default, `better-branch` will create **worktrees** as a sibling folder. To change this, see `worktrees.base_path`.\n\n### Pre/Post Branch Checkout Hooks\n\nOptionally configure pre and post checkout commands, for example:\n\n- checkout and rebase main before branching\n- run `npm install` before branching\n- run `npm run dev` after branching\n\nSee _branch_pre_commands_ and _branch_post_commands_ in default config. (or _worktree_pre_commands_ and _worktree_post_commands_ for creating worktrees)\n\n## 💡 Tips \u0026 Tricks\n\n### Building / Versioning\n\n`better-commits` works with [Semantic Release](https://github.com/semantic-release/semantic-release)\n\n- See _package.json_ and _.github/workflows/publish.yml_ for example\n\n### Github\n\nIf you use `better-commits` to create your _first_ commit on a new branch\n\n- When you open a PR for that branch, it will properly **auto-populate the title and body**.\n- When you squash/merge, all later commits like \"addressing comments\" or \"fixing mistake\". Will be prefixed with an asterisk for easy deletion. This way, you **maintain your pretty commit even when squashing**.\n\nIf you're using Github issues to track your work, and select the `closes` footer option when writing your commit. Github will **automatically link and close** that issue when your **pr is merged**\n\n### Changelogs\n\n`better-commits` can append a commit trailer per commit type. This allows you to [automate change logs](https://docs.gitlab.com/ee/user/project/changelogs.html) with tools like Gitlab.\n\n### Git\n\n`better-commits` uses native `git` commands under the hood. So any hooks, tools, or staging should work as if it was a normal commit.\n\nSetting `confirm_with_editor=true` will allow you to edit/confirm a commit with your editor.\n\n- For example, to edit with Neovim: `git config --global core.editor \"nvim\"`\n- For VS Code, `git config --global core.editor \"code -n --wait\"`\n\nYou can pass arguments to `git` through `better-commits` like so:\n\n```sh\nbetter-commits --git-dir=\"$HOME/.config\" --work-tree=\"$HOME\"\n```\n\nA practical example of this would be managing dotfiles, as described in this [Atlassian Article](https://www.atlassian.com/git/tutorials/dotfiles)\n\n### CLI Flags\n\nUse CLI flags to pass commit values directly instead of answering prompts.\n\n- Use `--no-interactive` to skip prompts, confirmation, and editor flows. This is the recommended mode for OpenCode, Claude Code, and other coding agents.\n- Use `--dry-run` to validate the generated `git commit` command without creating a commit.\n- Supported commit field flags: `--type`, `--scope`, `--title`, `--body`, `--ticket`, `--closes`, `--deprecates`, `--breaking-title`, `--breaking-body`, `--deprecates-title`, `--deprecates-body`, `--custom-footer`, `--trailer`.\n- Supported branch field flags: `--user`, `--type`, `--scope`, `--description`, `--ticket`, `--branch-version`, `--checkout`.\n\n**Examples**\n\n```sh\nbetter-commits --no-interactive --dry-run --type feat --scope cli --title \"add parser\"\n\nbetter-branch --no-interactive --type feat --scope cli --ticket TAC-123 --description \"add parser\" --checkout worktree\n```\n\n---\n\n### 🪟 Troubleshooting Windows\n\n#### Git Bash\n\n`TTY initialization failed: uv_tty_init returned EBADF (bad file descriptor)`. This may happen because you're running something like git-bash on Windows. Try another terminal/command-prompt or `winpty` to see if its still an issue.\n\n#### Multi-line\n\nIf you are having issues with multilines for commits on windows, you can override the shell via your `.better-commits.jsonc` config.\n\nExample\n\n```json\n\"overrides\": {\n   \"shell\": \"c:\\\\Program Files\\\\Git\\\\bin\\\\bash.exe\"\n}\n```\n\n\u003ch1 align=\"center\"\u003e🌟 Sponsors\u003c/h1\u003e\n\n\u003ch3 align=\"center\"\u003e\n\n[![flotes-g-2](https://github.com/Everduin94/Everduin94/assets/14320878/b0fd0aa5-ca9d-4a2d-8579-7616140927a7)](https://flotes.app)\n\n[Markdown Notetaking - Built for Learning](https://flotes.app)\n\n\u003c/h3\u003e\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Feverduin94%2Fbetter-commits","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Feverduin94%2Fbetter-commits","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Feverduin94%2Fbetter-commits/lists"}