npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

better-commits

v1.19.1

Published

A CLI for creating better commits following the conventional commits specification

Readme

bc-gradient

better commits is enabled downloads discord

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

✨ Features

  • Generate conventional commits through a series of prompts
  • Highly configurable with sane defaults
  • Infers ticket and commit-type from branch for consistent & fast commits
  • Consistent branch creation with flexible workflow hooks via better-branch
  • Interactive git status/add on commit
  • Preview commit messages in color
  • Support for git emojis per commit-type
  • Configure globally or per repository
  • Config validation and error messaging
  • Lightweight (17kb)

As a side-effect of formatting messages

  • Auto populate PR title / body
  • Automate semantic releases
  • Automate changelogs
  • Automatically link & close related tickets / issues

📦 Installation

npm install -g better-commits

🚀 Usage

To run the CLI in your terminal:

better-commits # Create a new commit
better-branch # Create a new branch

better-commits 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 inferred 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

  • This config will be used if a repository-specific config cannot be found.

Repository

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

  • Run better-commits-init
  • This will create a default config named .better-commits.json
  • Properties such as confirm_with_editor and overrides will prefer the global config

Options

[!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

{
  "check_status": true,
  "commit_type": {
    "enable": true,
    "initial_value": "feat",
    "max_items": 20,
    "infer_type_from_branch": true,
    "append_emoji_to_label": false,
    "append_emoji_to_commit": false,
    "emoji_commit_position": "Start",
    "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": 20,
    "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,
    "split_by_period": false
  },
  "commit_footer": {
    "enable": true,
    "initial_value": [],
    "options": ["closes", "trailer", "breaking-change", "deprecated", "custom"]
  },
  "breaking_change": {
    "add_exclamation_to_title": true
  },
  "confirm_commit": true,
  "cache_last_value": 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"],
  "worktrees": {
    "enable": true,
    "base_path": "..",
    "folder_template": "{{repo_name}}-{{ticket}}-{{branch_description}}"
  },
  "overrides": {
    "shell": "/bin/sh"
  }
}

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

  • See config file explanations for possible values

🔭 Config File Explanations

Expand to see explanations and possible values

. refers to nesting. i.e. if a property is commit_type.enable then expect in the config for it to be:

"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.emoji_commit_position | Emoji position, "Start" (default) or "After-Colon" | | 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_body.split_by_period | Automatically split sentences into new lines | | 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 | | cache_last_value | Reuse last prompt value after cancel | | 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 affect prompt order) | | branch_action_default | "branch" or "worktree" | | enable_worktrees | Deprecated see worktrees.enable | | worktrees.enable | If false, always default to branch action | | worktrees.base_path | Directory where worktrees are created (default: "..") | | worktrees.folder_template | Template for worktree folder names with variables like {{repo_name}}, {{branch_description}}, {{user}}, {{type}}, {{ticket}}, {{version}} |

🔎 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

  • If a STRING-NUMBER or NUMBER are at the start of the branch name or after a /

Commit Type

  • If a type is at the start of the branch or is followed by a /

🌳 Better Branch

Better branch is a secondary feature that works with better commits

  • Supports consistent branch naming conventions
  • Uses same type-list/prompt from your config
  • Enables better-commits to infer type & ticket
  • Caches your username for speedy branching
  • Convenient worktree creation

To run the CLI in your terminal:

better-branch

Worktree Support

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.

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

[!TIP] By default, better-branch will create worktrees as a sibling folder. To change this, see worktrees.base_path.

Pre/Post Branch Checkout Hooks

Optionally configure pre and post checkout commands, for example:

  • checkout and rebase main before branching
  • run npm install before branching
  • run npm run dev after branching

See branch_pre_commands and branch_post_commands in default config. (or worktree_pre_commands and worktree_post_commands for creating worktrees)

🌌 Mildly Interesting

Building / Versioning

better-commits works with Semantic Release

  • See package.json and .github/workflows/publish.yml for example

Github

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

  • When you open a PR for that branch, it will properly auto-populate the title and body.
  • 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.

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.

Misc

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.

  • For example, to edit with Neovim: git config --global core.editor "nvim"
  • For VS Code, git config --global core.editor "code -n --wait"

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 |

Git Arguments

You can pass arguments to git through better-commits like so:

better-commits --git-dir="$HOME/.config" --work-tree="$HOME"

A practical example of this would be managing dotfiles, as described in this Atlassian Article


🪟 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"
}

flotes-g-2

Markdown Notetaking - Built for Learning