iTranslated by AI

The content below is an AI-generated translation. This is an experimental feature, and may contain errors. View original article
✍️

Conventional Commits: Basics and Supporting Technologies (commitlint + husky)

に公開1

What is this?

This article summarizes the basic knowledge of Conventional Commits, a specification for unifying the format of commit messages, along with the know-how to smoothly advance development processes that incorporate it.

What is Conventional Commits?

https://www.conventionalcommits.org/en/v1.0.0/

Conventional Commits is a specification for providing a consistent set of rules for creating an explicit commit history. It is designed to be easily understood by both humans and machines, allowing for the description of concise yet clear commit messages. This not only makes it easier to track the evolution of a codebase later on but also facilitates integration with tools that automate release workflows and code reviews.

Basic Format

<type>[optional scope]: <description>
  │     │                │
  │     │                └─ Briefly describe the commit content
  │     │
  │     └─ Scope specifying the impact area of the commit (optional)

  └─ Type specifying the kind of commit
Example
feat: add new feature
fix(api): fix a bug

type

Among the types defined by the official Conventional Commits specification, the following two are representative:

  • fix: A patch for fixing a bug
  • feat: Addition of a new feature

In addition to these, the following types are defined, allowing you to cover almost all types of changes:

  • docs: Documentation changes
  • style: Changes in code style (e.g., adding semicolons, fixing line breaks)
  • refactor: Code refactoring (excluding bug fixes or new feature additions)
  • perf: Performance improvements
  • test: Adding or correcting tests
  • build: Changes to the build system or dependency updates
  • ci: Changes to CI/CD configuration
  • chore: Other changes

BREAKING CHANGE

Conventional Commits includes a special keyword called BREAKING CHANGE. By including this in the footer of a commit message, you can explicitly state that the commit introduces a breaking change to the existing code.

Example
feat: add new feature

BREAKING CHANGE: this is a breaking change

Alternatively, you can use a ! after the type/scope to substitute for the BREAKING CHANGE keyword.

Example
feat!: add new feature
feat(api)!: add new feature

Tools for checking commit messages

To incorporate Conventional Commits into your development process, it is effective to introduce tools that check the format of commit messages.

commitlint

https://commitlint.js.org/

As the name suggests, it is a linter for checking commit messages. You can configure Conventional Commits or your own message conventions to check if commit messages comply with the rules. In this article, I will introduce a setup to check messages for compliance with Conventional Commits.

Installing packages
npm install --save-dev @commitlint/cli @commitlint/config-conventional
# or yarn
yarn add --dev @commitlint/cli @commitlint/config-conventional

https://www.npmjs.com/package/@commitlint/cli

https://www.npmjs.com/package/@commitlint/config-conventional

@commitlint/config-conventional is a package that provides the configuration for Conventional Commits. With this single package, you can easily implement the Conventional Commits specification. It fully supports the type definitions and BREAKING CHANGE checks mentioned earlier.

Next, create a configuration file. Write the following content in a file named commitlint.config.js in the root directory of your repository.

commitlint.config.js
module.exports = {
  // Reference the installed package
  extends: ['@commitlint/config-conventional'],
};

Since it is a commit message, it is appropriate to check it at the time of committing. Therefore, we will build a mechanism where the commit message is checked upon execution of the commit by combining it with husky.

https://typicode.github.io/husky/

Installing packages
npm install --save-dev husky
# or yarn
yarn add --dev husky

Next, run the following command in the root directory of the repository to create the husky configuration file.

npx husky install

When the command is successful, a .husky directory is created in the root directory.

 .
+├── .husky/
+│   └── _/
 └── package.json

Husky configuration files are stored in the .husky/_ directory. These files are added to .gitignore by default, so they are not managed by Git. Therefore, you need to regenerate the husky configuration files every time the repository is cloned. To automate this task, add a prepare script.

package.json
{
  "scripts": {
    "prepare": "husky install"
  }
}

https://docs.npmjs.com/cli/v10/using-npm/scripts#life-cycle-scripts

The prepare script is a type of Lifecycle script that is automatically executed every time npm install is run. Therefore, the husky configuration files are generated in conjunction with the frequently executed npm install, preventing you from forgetting the setup.

Finally, configure husky to run the commit message check upon committing. Create the .husky/commit-msg file and write the following content.

 .
 ├── .husky/
 │   ├── _/
+│   └── commit-msg
 └── package.json
.husky/commit-msg
npx --no-install commitlint --edit $1

Now, a Git hook called commit-msg will trigger upon committing, and the commit message will be checked. Let's actually commit and see if an error occurs.

Example failure
# Entering an invalid commit message will cause an error and abort the commit.
git commit -m "add new feature"

   input: add new feature
   subject may not be empty [subject-empty]
   type may not be empty [type-empty]

   found 2 problems, 0 warnings
   Get help: https://github.com/conventional-changelog/commitlint/#what-is-commitlint
Example success
# Entering a proper commit message will complete the commit without any issues.
git cm -a -m 'feat: add new feature'

[ci/commitlint 2aef98a] feat: add new feature
 1 file changed, 2 insertions(+), 1 deletion(-)

Conclusion

Writing commit messages is a routine task in the process of software implementation, but its importance is rarely noticed. Especially in projects where small-scale and rapid development is required, commit messages tend to be neglected. This is because right after a commit, the changes are vividly remembered, making it hard to feel the need to record them in a message. However, commit messages are a crucial source of information for tracking the evolution of a codebase. If the format is inconsistent or the contents are unclear, it becomes difficult to trace the history of the codebase later on.

Conventional Commits is a very refined specification for unifying the format of commit messages. Additionally, many excellent tools exist to support it beyond those introduced in this article. We encourage you to adopt Conventional Commits and build a codebase that is easy to read and track for your future self and your team members.

References

Discussion

kiiiyokiiiyo

タイムリーでありがたい記事っす😁🙏