Conventional Commits

Good practices to help others and your future self.

December 12, 2023 (1y ago)

We've all seen it: Git histories where commit messages are simply just "fixed thing", "updated thing", random text, or even just ., at one point or another, we're all guilty of it. The issue with this "naming scheme" is that in the future, you may forget what you were doing, or someone else may need to look at your repository but is unable to get a high-level understanding from the commit history, which brings another set of problems as they'll have to read the code but is then dependent on whether if the code is well documented, structured, etc.

Documentation is applicable to various aspects of a developer lifecyle, from variable names and comments, to READMEs and commit messages, good and clear documentation is often overlooked and ignored while being a very important part of the development process.

While there are various ways to have good documentation, this article will focus on writing better commit messages by following the conventional commit structure to help commit messages convey the changes made within the commit.

What Are Conventional Commits?

As specified within the documentation, Conventional Commits is a specification for writing standardized commit messages by following a format to convey the changes made within the commit.

The format is as follows:

<type>([scope]): <description>

[body]

[footer(s)]

Each part of the format has a specific purpose to convey what changes were made:

  • type (required): The type of change that was made, this value should be a noun to describe the change. There are no strict list of types to choose from, you can use any string you feel is best, however, some examples are: feat for new features, fix for bug fixes, docs for documentation changes, etc.
  • scope (optional): An optional value you can specify to further categorize the change, often being the section of the codebase that was changed.
  • description (required): A short description of the change.
  • body (optional): A longer description describing the change in more detail, must be separated from the description by a blank line.
  • footer (optional): A footer section that can be used to reference issues or pull requests that are associated with the commit, each footer must be on a newline and must consist of a word followed by either :[space] or [space]#, followed by a string value.

Why Should We Use Conventional Commits?

There are two main benefits of using conventional commits: readability and automation.

Following this structure makes commit messages easily convey the goal of the respective commit, making it easier for everyone (including your future self) to understand the changes made and where they were made. The format also brings consistency to the commit history, allowing for other functionality, such as automation.

Beyond clarifying commit messages, the format allows tools to be built on top of commit messages, most notably, changelogs. The consistent commit history allows tools to read and generate changelogs, as an example, the changelog for the repository of this website is generated by using bump, a tool I created to generate changelogs from conventional commits.

Examples

For example, let's say you:

  • added a new feature to send an email to the customer when a product is shipped:
feat(api): send an email to the customer when a product is shipped
  • fixed a bug:
fix: fix a bug that caused a crash when users uploads a photo for their profile

closes: https://github.com/user/repo/issues/1
  • updated dependencies:
chore(deps): update `[package]` to `[version]`
  • changed the color for the foreground text of your application's dark theme:
style(theme): change the dark theme's foreground color to `[color]`

Resources