Everduin94 / better-commits

A CLI for creating better commits following the conventional commits specification
MIT License
1.88k stars 69 forks source link
clack cli commit-message git typescript zod

![bc-gradient](https://github.com/Everduin94/better-commits/assets/14320878/2f94e6ea-a40f-4f3e-b0b2-5cc7d83a9a7d) [![better commits is enabled](https://img.shields.io/badge/better--commits-enabled?style=for-the-badge&logo=git&color=a6e3a1&logoColor=D9E0EE&labelColor=302D41)](https://github.com/Everduin94/better-commits) [![downloads](https://img.shields.io/npm/dt/better-commits.svg?style=for-the-badge&logo=npm&color=74c7ec&logoColor=D9E0EE&labelColor=302D41)](https://www.npmjs.com/package/better-commits) [![discord](https://img.shields.io/badge/discord-join--discord?style=for-the-badge&logo=discord&color=cba6f7&logoColor=D9E0EE&labelColor=302D41)](https://discord.gg/grHVnZwYup)

A CLI for writing better commits, following the conventional commits specification.

https://github.com/Everduin94/better-commits/assets/14320878/8fb15d46-17c4-4e5d-80d9-79abe0a2a00a

โœจ Features

As a side-effect of formatting messages

๐Ÿ“ฆ Installation

npm install -g better-commits

๐Ÿš€ Usage

When you're ready to commit. To run the CLI in your terminal:

better-commits
# or
npx better-commits

It will prompt a series of questions. These prompts will build a commit message, which you can preview, before confirming the commit. Some of the values in these prompts will be infered by your branch name and auto populated. You can adjust this in your .better-commits.json configuration file.

To better understand these prompts and their intention, read Conventional Commits Summary

โš™๏ธ Configuration

Global

Your first time running better-commits, a default config will be generated in your $HOME directory, named .better-commits.json

Repository

To create a repository-specific config, navigate to the root of your project.

Options

Better-commits (& better-branch) are highly flexible with sane defaults. These options allow you specify whats best for your workflow.

[!NOTE]
All properties are optional and can be removed from the config. It will be replaced by the default at run-time.

  • See .better-commits.json in this repository as an example

๐Ÿ’ซ Default JSON Config

Expand / Collapse ```json { "check_status": true, "commit_type": { "enable": true, "initial_value": "feat", "max_items": Infinity, "infer_type_from_branch": true, "append_emoji_to_label": false, "append_emoji_to_commit": false, "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" }, { "value": "docs", "label": "docs", "hint": "Documentation only changes", "emoji": "๐Ÿ“š", "trailer": "Changelog: documentation" }, { "value": "refactor", "label": "refactor", "hint": "A code change that neither fixes a bug nor adds a feature", "emoji": "๐Ÿ”จ", "trailer": "Changelog: refactor" }, { "value": "perf", "label": "perf", "hint": "A code change that improves performance", "emoji": "๐Ÿš€", "trailer": "Changelog: performance" }, { "value": "test", "label": "test", "hint": "Adding missing tests or correcting existing tests", "emoji": "๐Ÿšจ", "trailer": "Changelog: test" }, { "value": "build", "label": "build", "hint": "Changes that affect the build system or external dependencies", "emoji": "๐Ÿšง", "trailer": "Changelog: build" }, { "value": "ci", "label": "ci", "hint": "Changes to our CI configuration files and scripts", "emoji": "๐Ÿค–", "trailer": "Changelog: ci" }, { "value": "chore", "label": "chore", "hint": "Other changes that do not modify src or test files", "emoji": "๐Ÿงน", "trailer": "Changelog: chore" }, { "value": "", "label": "none" } ] }, "commit_scope": { "enable": true, "custom_scope": false, "initial_value": "app", "max_items": Infinity "options": [ { "value": "app", "label": "app" }, { "value": "shared", "label": "shared" }, { "value": "server", "label": "server" }, { "value": "tools", "label": "tools" }, { "value": "", "label": "none" } ] }, "check_ticket": { "infer_ticket": true, "confirm_ticket": true, "add_to_title": true, "append_hashtag": false, "prepend_hashtag": "Never", "surround": "", "title_position": "start" }, "commit_title": { "max_size": 70 }, "commit_body": { "enable": true, "required": false }, "commit_footer": { "enable": true, "initial_value": [], "options": ["closes", "trailer", "breaking-change", "deprecated", "custom"] }, "breaking_change": { "add_exclamation_to_title": true }, "confirm_commit": true, "confirm_with_editor": false, "print_commit_output": true, "branch_pre_commands": [], "branch_post_commands": [], "worktree_pre_commands": [], "worktree_post_commands": [], "branch_user": { "enable": true, "required": false, "separator": "/" }, "branch_type": { "enable": true, "separator": "/" }, "branch_version": { "enable": false, "required": false, "separator": "/" }, "branch_ticket": { "enable": true, "required": false, "separator": "-" }, "branch_description": { "max_length": 70, "separator": "" }, "branch_action_default": "branch", "branch_order": ["user", "version", "type", "ticket", "description"], "enable_worktrees": true, "overrides": { "shell": "/bin/sh" } } ```

[!NOTE]
Some properties allow a set of specifc string values

  • See config file explanations for possible values

๐Ÿ”ญ Config File Explanations

Expand to see explanations and possible values

Expand / Collapse `.` refers to nesting. i.e. if a property is `commit_type.enable` then expect in the config for it to be: ```json "commit_type": { "enable": true } ``` | Property | Description | | ------------------------------------------ | --------------------------------------------------------------------------------------------------- | | `check_status` | If true run interactive `git status` | | `commit_type.enable` | If true include commit type | | `commit_type.initial_value` | Initial selection of commit type | | `commit_type.max_items` | Maximum number of type displayed on the screen | | `commit_type.infer_type_from_branch` | If true infer type from branch name | | `commit_type.append_emoji_to_label` | If true append emoji to prompt | | `commit_type.append_emoji_to_commit` | If true append emoji to commit | | `commit_type.options.value` | Commit type prompt value | | `commit_type.options.label` | Commit type prompt label | | `commit_type.options.hint` | Commit type inline hint (like this) | | `commit_type.options.emoji` | Commit type emoji | | `commit_type.options.trailer` | Commit type trailer | | `commit_scope.enable` | If true include commit scope | | `commit_scope.custom_scope` | If true allow custom scope at run-time | | `commit_scope.initial_value` | Default commit scope selected | | `commit_scope.max_items` | Maximum number of scope displayed on the screen | | `commit_scope.options.value` | Commit scope value | | `commit_scope.options.label` | Commit scope label | | `check_ticket.infer_ticket` | If true infer ticket from branch name | | `check_ticket.confirm_ticket` | If true manually confirm inference | | `check_ticket.add_to_title` | If true add ticket to title | | `check_ticket.append_hashtag` | **Deprecated**: see prepend_hashtag | | `check_ticket.prepend_hashtag` | "Never" (default), "Prompt", or "Always" | | `check_ticket.title_position` | "start" (of description) (default), "end", "before-colon", "beginning" (of the entire commit title) | | `check_ticket.surround` | "" (default), "[]", "()", "{}" - Wraps ticket in title | | `commit_title.max_size` | Max size of title including scope, type, etc... | | `commit_body.enable` | If true include body | | `commit_body.required` | If true body is required | | `commit_footer.enable` | If true include footer | | `commit_footer.initial_value` | Initial values selected in footer | | `commit_footer.options` | Footer options | | `breaking_change.add_exclamation_to_title` | If true adds exclamation mark to title for breaking changes | | `confirm_commit` | If true manually confirm commit at end | | `confirm_with_editor` | Confirm / Edit commit with $GIT_EDITOR / $EDITOR | | `print_commit_output` | If true pretty print commit preview | | `overrides.shell` | Override default shell, useful for windows users | Branch configuration (same config file, split for readability) | Property | Description | | ------------------------------- | --------------------------------------------------------- | | `branch_pre_commands` | Array of shell commands to run before branching | | `branch_post_commands` | Array of shell commands to run after branching | | `worktree_pre_commands` | Array of shell commands to run before creating worktree | | `worktree_post_commands` | Array of shell commands to run after creating worktree | | `branch_user.enable` | If enabled include user name | | `branch_user.required` | If enabled require user name | | `branch_user.separator` | Branch delimeter - "/" (default), "-", "\_" | | `branch_type.enable` | If enabled include type | | `branch_type.separator` | Branch delimeter - "/" (default), "-", "\_" | | `branch_ticket.enable` | If enabled include ticket | | `branch_ticket.required` | If enabled require ticket | | `branch_ticket.separator` | Branch delimeter - "/", "-" (default), "\_" | | `branch_description.max_length` | Max length branch name | | `branch_description.separator` | Branch delimeter - "" (default), "/", "-", "\_" | | `branch_version.enable` | If enabled include version | | `branch_version.required` | If enabled require version | | `branch_version.separator` | Branch delimeter - "", "/" (default), "-", "\_" | | `branch_order` | Order of branch name values (doesn't effect prompt order) | | `branch_action_default` | "branch" or "worktree" | | `enable_worktrees` | If false, always default to branch action |

๐Ÿ”Ž Inference

better-commits will attempt to infer the ticket/issue and the commit-type from your branch name. It will auto populate the corresponding field if found.

Ticket / Issue-Number

Commit Type

๐ŸŒณ Better Branch

[!NOTE]
Using better-branch with better-commits can supercharge your git workflow. Make sure to try it out!

Better branch is a secondary feature that works with better commits

To run the CLI in your terminal:

better-branch

Worktree Support

better-branch will prompt for Branch or Worktree. Creating a Worktree with better-branch is a great way to create worktrees while maintaining consistent branch naming conventions.

The worktree flow creates a folder/worktree with your branch description and a git branch inside with your full branch name.

[!NOTE]
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.

Pre/Post Branch Checkout Hooks

Optionally configure pre and post checkout commands, for example:

See _branch_precommands and _branch_postcommands in default config. (or _worktree_precommands and _worktree_postcommands for creating worktrees)

๐ŸŒŒ Mildly Interesting

Building / Versioning

better-commits works with Semantic Release

Github

If you use better-commits to create your first commit on a new branch

If 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

Changelogs

better-commits can append a commit trailer per commit type. This allows you to automate change logs with tools like Gitlab.

Fun Facts

better-commits uses native git commands under the hood. So any hooks, tools, or staging should work as if it was a normal commit.

Setting confirm_with_editor=true will allow you to edit/confirm a commit with your editor.

[!NOTE]
Enjoy learning, open source technology, and note-taking? Join our Discord!

You can add this badge to your repository to display that you're using a better-commits repository config

Markdown Result
[![better commits is enabled](https://img.shields.io/badge/better--commits-enabled?style=for-the-badge&logo=git&color=a6e3a1&logoColor=D9E0EE&labelColor=302D41)](https://github.com/Everduin94/better-commits) better commits is enabled

๐ŸชŸ Troubleshooting Windows

Git Bash

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.

Multi-line

If your are having issues with multilines for commits on windows, you can override the shell via your .better-commits.json config.

Example

"overrides": {
   "shell": "c:\\Program Files\\Git\\bin\\bash.exe"
}

๐ŸŒŸ Sponsors

[![flotes-g-2](https://github.com/Everduin94/Everduin94/assets/14320878/b0fd0aa5-ca9d-4a2d-8579-7616140927a7)](https://flotes.app) [Markdown Notetaking - Built for Learning](https://flotes.app)