Mastering Git: The Power of Conventional Commit Messages

Amirhosein Gharaati
Stackademic
Published in
6 min readSep 2, 2023

--

Among the various version control systems available, Git stands out as the undisputed champion, thanks to its robust features and flexibility.

While many developers are familiar with the basics of Git, there’s one often-overlooked aspect that can greatly enhance your development workflow: Conventional Commit Messages

The conventional commit message format is a simple yet powerful convention that enforces consistency in commit messages, making them more informative and easier to understand for both humans and machines.

In this article, we are going to introduce and introduce a convention for git commit messages.

Be aware: There is no general rule about git commit messages. Any developer or team can have their own conventions. So you can also take inspiration some ideas from the things we are going to mention.

Table of contents

  1. Why conventional commit message
  2. Convention
  3. Examples
  4. Best practices
  5. QA
  6. More resources & References

Why conventional commit message

  • Automatically generating CHANGELOGs.
  • Automatically determining a semantic version bump (based on the types of commits landed).
  • Communicating the nature of changes to teammates, the public, and other stakeholders (consistency).
  • Triggering build and publish processes.
  • Making it easier for people to contribute to your projects, by allowing them to explore a more structured commit history.

Convention

A typical standard git commit message is structured as follows:

<type>[optional scope]: <subject>

for example:

feat(shopping cart): add the amazing button

But we will introduce a more structured way. You can see the resources at the end.

<type>[optional scope]: <subject>

[optional body]

[optional footer(s)]

for example:

feat(database): onUrlChange event (popstate/hashchange/polling)

Added new event to $browser:
- forward popstate event if available
- forward hashchange event if popstate not available
- do polling when neither popstate nor hashchange available

BREAKING CHANGE: $browser.onHashChange, which was removed (use onUrlChange instead)

<type>

In this field, you specify the type of work you have done in the commit. This can be different things:

  • feat: introduces a new feature to the codebase
  • fix: patches a bug in your codebase
  • refactor: rewrite/restructure your code, however does not change any behaviour
  • style: do not affect the meaning (white-space, formatting, missing semi-colons, etc)
  • test: add missing tests or correcting existing tests
  • docs: affect documentation only
  • build: affect build components like build tool, ci pipeline, dependencies, project version, …
  • ops: affect operational components like infrastructure, deployment, backup, recovery, …
  • chore: Miscellaneous commits e.g. modifying .gitignore
  • or everything else that you want to include in your team convention

[scope]

The scope provides additional contextual information.

  • Is an optional part of the format
  • Allowed Scopes depends on the specific project
  • Don’t use issue identifiers as scopes
  • Breaking changes should be indicated by an ! before the : in the subject line e.g. feat(api)!: remove status endpoint which is an optional part of the format

<subject>

The subject contains a succinct description of the change, a short summary of the things you have done in the commit.

  • Is a mandatory part of the format
  • Use the imperative, present tense: “change” not “changed” nor “changes”. Think of This commit will <subject>

Also for better messages you can have these things too:

  • Don’t capitalize the first letter
  • No dot (.) at the end

[body]

Includes motivation for the change and contrasts with previous behavior.

  • Is an optional part of the format
  • Use the imperative, present tense: “change” not “changed” nor “changes”
  • This is the place to mention issue identifiers and their relations

[footer(s)]

Any information about Breaking Changes and is also the place to Reference Issues that this commit refers to.

  • Is an optional part of the format
  • optionally reference an issue by its id.
  • Breaking Changes should start with the word BREAKING CHANGES: followed by space or two newlines. The rest of the commit message is then used for this.

Breaking changes

All breaking changes have to be mentioned in footer with the description of the change, justification and migration notes.

BREAKING CHANGE: isolate scope bindings definition has changed and
the inject option for the directive controller injection was removed.

To migrate the code follow the example below:

Before:

scope: {
myAttr: 'attribute',
myBind: 'bind',
myExpression: 'expression',
myEval: 'evaluate',
myAccessor: 'accessor'
}

After:

scope: {
myAttr: '@',
myBind: '@',
myExpression: '&',
// myEval - usually not useful, but in cases where the expression is assignable, you can use '='
myAccessor: '=' // in directive's template change myAccessor() to myAccessor
}

The removed `inject` wasn't generaly useful for directives so there should be no code using it.

Referencing issues

You can mention closed bugs or issues with keyword “Closes”

Closes #234

or reference a ticket with “Refs” keyword:

Refs: #123 #234

Examples

feat(shopping cart): add the amazing button
fix: add missing parameter to service call

The error occurred because of <reasons>.
refactor: implement calculation method as recursion
feat(database): onUrlChange event (popstate/hashchange/polling)

Added new event to $browser:
- forward popstate event if available
- forward hashchange event if popstate not available
- do polling when neither popstate nor hashchange available

BREAKING CHANGE: $browser.onHashChange, which was removed (use onUrlChange instead)

Best Practices

Here are some recommended best practices for writing Git commit messages:

  1. Keep it concise: A commit message should be a short summary of the changes made, ideally no more than 50 characters.
  2. Use the imperative mood: Start the commit message with an imperative verb, such as “Add”, “Fix”, “Update”, or “Remove”.
  3. Provide details in the body: After the summary line, provide additional details in the commit message body, including any relevant context, motivation, or explanation of the changes made.
  4. Separate subject and body with a blank line: Use a blank line between the subject and the body of the commit message.
  5. Use proper formatting: Use proper formatting, such as bullet points or paragraphs, to make the commit message easy to read and understand.
  6. Reference issue numbers: If the commit message is related to a specific issue or ticket, reference the issue number in the message body or commit message.
  7. Be consistent: Use consistent formatting and style across all commit messages in the project.

You can read more about some other things in:

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

QA

Are the types in the commit title uppercase or lowercase?

Any casing may be used, but it’s best to be consistent.

What do I do if the commit conforms to more than one of the commit types?

Go back and make multiple commits whenever possible. Part of the benefit of Conventional Commits is its ability to drive us to make more organized commits and PRs.

Doesn’t this discourage rapid development and fast iteration?

It discourages moving fast in a disorganized way. It helps you be able to move fast long term across multiple projects with varied contributors.
There is quote in Clean Architecture that says:

The only way to go fast, is to go well

Do all the contributors need to use the Conventional Commits specification?

No! If you use a squash based workflow on Git lead maintainers can clean up the commit messages as they’re merged — adding no workload to casual committers.
A common workflow for this is to have your git system automatically squash commits from a pull request and present a form for the lead maintainer to enter the proper git commit message for the merge.

Bonus

There are somethings regarding to conventional messages that you can automatically validate commit message convention before commit. In other expression: git hooks

You can read more about them here:

https://gist.github.com/qoomon/5dfcdf8eec66a051ecd85625518cfd13#git-hook-scripts-to-ensure-commit-message-header-format

More resources & References

Take your time to gather more information about conventional messages. Believe it or not, this will make you a better developer and lead to better team consistency, resulting in cleaner actions.

There are some resources that you can find more things about conventional messages:

Conclusion

Conventional Commit Messages offer a straightforward yet impactful approach to version control, promoting clarity and consistency in documenting code changes.

By adhering to this standardized format, developers can enhance communication, simplify project management, and automate essential tasks.
Whether you’re a solo coder or part of a collaborative team, embracing Conventional Commit Messages can significantly improve your Git workflow and contribute to more efficient and effective software development.

Thank you for reading until the end. Please consider following the writer and this publication. Visit Stackademic to find out more about how we are democratizing free programming education around the world.

--

--