When using version control tools such as Git, commit messages are always useful to describe the types of changes, the changes, and a brief description of why these changes were necessary.
These messages must have some kind of meaning, not only for the author of the changes but also for the rest of the team, since once the changes are entered into the tree, they will be the only source of information about why they were entered in the foreground.
#.Introducing Conventional Commits
Conventional Commits is a convention and/or specification for how we should write these commits messages. This convention provides a simple and straightforward set of rules to maintain a uniform history of changes.
Likewise, Conventional Commits provide a series of tools to help developers write these messages in an easier and more consistent way, and at the same time are aligned with Semantic Versioning.
#.Basic rules and specifications of Conventional Commits
- They must provide a type of the changes, which could be:
feat,fix,chore, among others. This type is a noun (noun). - They can provide (optional) a scope of these changes, to indicate the scope of them at the system level. For example, if your system is divided into different modules and your scope is only intended for one particular module, this would be your scope.
- They must provide a description immediately after the type and the scope. This is written in the infinitive (imperative) and must be short.
- A body of the changes may be provided, which should be a more detailed description of the changes. This body must be written in the infinitive (imperative) as well.
- They can provide a footer, which can be used to provide additional information, such as references to issues or pull requests.
You can read the complete specification at this link, taking into account that it is in English and that it uses RFC 2119 to indicate the importance of each rule (“MUST”, “MUST NOT”, “REQUIRED”, “SHALL”, etc.).
#.Examples of Conventional Commits
feat: add new login validatorfix: fix validation for usernamechore: fix typo in README.md# Estos cambios solo están planeados para ser utilizados en el módulo de login
feat(login): add new login validator# Estos cambios solo están planeados para ser utilizados en el módulo de login
fix(login): fix validation for usernametest(login): update snapshots on login page# Estos cambios están planeados para ser utilizados en el módulo de login.
# Adicionalmente se utiliza el body con más descripción y un footer donde se
# señala quién aprobó este cambio y el número de tiquete asociado a él.
fix(login): prevent null password at login
Introduce a new validation to prevent null passwords at login.
Remove the old validation rule for the password.
Create a new validation process and helper for the password.
Reviewed-by: John Doe
Refs: #123123#.Using CommitizenCommitizen is a tool that allows us to use Conventional Commits in an easier and more consistent way. The problem with Conventional Commits is that there is no easy way to write them manually, so we must have some template with us to be able to write them.
Commitizen solves this problem by providing us with a template (generated through a small form) to write commit messages in a way that conforms to Conventional Commits.
With Commitizen, we can also use tools like commitlint to validate that the commit messages comply with the Conventional Commits rules and other tools to generate the history of changes automatically (like a CHANGELOG).
If we are working on a project in JavaScript/TypeScript, we can use existing tools to integrate Commitizen into our project.
#.Installation
We must add two libraries to our project:
yarn add commitizen cz-customizable -DTo make it easier, we are going to add a script in our package.json to be able to run Commitizen more easily:
{
"scripts": {
"commit": "cz"
}
}#.Configuration
Since we are going to use cz-customizable to configure Commitizen, we must create a configuration file called .czrc and reference the library configuration:
{
"path": "node_modules/cz-customizable"
}Additionally, cz-customizable requires us to create a configuration file in order to use it. This file should be called .cz-config.js and should be in the root of our project. The project already provides us with a configuration example, so we can copy and paste it into our project.
module.exports = {
types: [
{ value: 'feat', name: 'feat: A new feature' },
{ value: 'fix', name: 'fix: A bug fix' },
{ value: 'docs', name: 'docs: Documentation only changes' },
{
value: 'style',
name: 'style: Changes that do not affect the meaning of the code
(white-space, formatting, missing semi-colons, etc)',
},
{
value: 'refactor',
name: 'refactor: A code change that neither fixes a bug nor adds a feature',
},
{
value: 'perf',
name: 'perf: A code change that improves performance',
},
{ value: 'test', name: 'test: Adding missing tests' },
{
value: 'chore',
name: 'chore: Changes to the build process or auxiliary tools
and libraries such as documentation generation',
},
{ value: 'revert', name: 'revert: Revert to a commit' },
{ value: 'WIP', name: 'WIP: Work in progress' },
],
scopes: [{ name: 'accounts' }, { name: 'admin' }, { name: 'exampleScope' }, { name: 'changeMe' }],
usePreparedCommit: false, // to re-use commit from ./.git/COMMIT_EDITMSG
allowTicketNumber: false,
isTicketNumberRequired: false,
ticketNumberPrefix: 'TICKET-',
ticketNumberRegExp: '\d{1,5}',
// it needs to match the value for field type. Eg.: 'fix'
/*
scopeOverrides: {
fix: [
{name: 'merge'},
{name: 'style'},
{name: 'e2eTest'},
{name: 'unitTest'}
]
},
*/
// override the messages, defaults are as follows
messages: {
type: "Select the type of change that you're committing:",
scope: '
Denote the SCOPE of this change (optional):',
// used if allowCustomScopes is true
customScope: 'Denote the SCOPE of this change:',
subject: 'Write a SHORT, IMPERATIVE tense description of the change:
',
body: 'Provide a LONGER description of the change (optional). Use "|" to break new line:
',
breaking: 'List any BREAKING CHANGES (optional):
',
footer: 'List any ISSUES CLOSED by this change (optional). E.g.: #31, #34:
',
confirmCommit: 'Are you sure you want to proceed with the commit above?',
},
allowCustomScopes: true,
allowBreakingChanges: ['feat', 'fix'],
// skip any questions you want
// skipQuestions: ['scope', 'body'],
// limit subject length
subjectLimit: 100,
// breaklineChar: '|', // It is supported for fields body and footer.
// footerPrefix : 'ISSUES CLOSED:'
// askForBreakingChangeFirst : true, // default is false
};#.Using it
To use Commitizen, we must run the script we created earlier:
yarn commitThis will show us a form with the options we have to write the commit message, which will look like the following:
yarn commit
yarn run v1.22.19
$ cz
cz-cli@4.2.5, cz-customizable@7.0.0
All lines except first will be wrapped after 100 characters.
? Select the type of change that you're committing: feat: A new feature
?
Denote the SCOPE of this change (optional): accounts
? Write a SHORT, IMPERATIVE tense description of the change:
change on something
? Provide a LONGER description of the change (optional). Use "|" to break new line:
change providing more changes
? List any BREAKING CHANGES (optional):
? List any ISSUES CLOSED by this change (optional). E.g.: #31, #34:
###--------------------------------------------------------###
feat(accounts): change on something
change providing more changes
###--------------------------------------------------------###
? Are you sure you want to proceed with the commit above? Yes
Auto packing the repository in background for optimum performance.
See "git help gc" for manual housekeeping.
warning: The last gc run reported the following. Please correct the root cause
and remove .git/gc.log
Automatic cleanup will not be performed until the file is removed.If we verify the git log, we will notice that the tool helped us to have a clearer and more organized commit message:
git log
commit f1eb95cacf7385d8f44d31c44317f1a5f283b813 (HEAD -> master)
Author: Demostenes Garcia G <...>
Date: ...
feat(accounts): change on something
change providing more changesNow, after here, we could implement other tools: such as one to ensure that the message complies with the standard we decide, that it does not have certain words or even implement versioning automatically.