📜 ⬆️ ⬇️

How to generate meaningful commits. Apply Conventional Commits Standard



Habitual chaos in commit names. Familiar picture?

Surely you know git-flow . This is a great set of conventions for organizing work with branches in Git. It is well documented and widely distributed. Usually we are familiar with the correct branching and talk a lot about it, but, unfortunately, we pay too little attention to the name of commits, so often the messages in Git are written haphazardly.
')
My name is Yerzhan Tashbenbetov, I work in one of the Yandex.Market teams. And today I will tell Habr's readers what tools to create meaningful commits we use in the team. I invite you to join the discussion of this topic.


The lack of agreement on commits makes it difficult to work with history in Git. That was on our team. Before using common for all regulations and implementation of automation, typical commits looked as follows:

SECRETMRKT-700:     , . SECRETMRKT-701, SECRETMRKT-702:     ... 

First, each developer wrote messages as he wanted: someone described the task, someone listed the changes made, someone used a random phrase generator. Everything was at odds with each other. Second, task numbers that were present in commits often shortened useful text. All this made it difficult to work effectively with history in Git.

For this reason, we implemented the Conventional Commits standard in the team, began to generate commits in the commitizen console utility and check the result using commitlint . As a result, commits have changed and become like this:

 refactor(tutorial):      feat(products):      fix(products):      

Reading the history and recognizing the changes made easier. We didn’t refuse to specify task numbers, everything was neatly transferred inside commits according to Conventional Commits convention .

Next, I'll tell you how to achieve a similar order in Git.



Best practices, recommendations, and common solutions for committing names


If you try to understand what practices are used in the industry, you can find the following options:


We need more order in commits!

Conventional Commits methodology stands out against other standards and deserves close examination for several reasons:

  1. It is well documented and worked out. In its specification answers to the most common questions.
  2. The creators of the convention were inspired by the requirements for writing commits, which are used in the popular and time-tested framework AngularJS .
  3. Several large and popular open-source libraries (such as yargs and lerna ) follow the rules of the convention.
  4. The advantages include preparation for the automatic formation of the Release Notes and Change Log.

An example of a commit to this standard:

 fix(products):             -     .  : SECRETMRKT-578, SECRETMRKT-602 



Basic abstracts of Conventional Commits




In addition to the rules listed in the convention, we use the following popular recommendations:






Conventional Commits standard is used by lerna distributors.



How easy is it to switch to the correct name of commits?


Need to add automation and convenience. To solve this issue, we need two tools: a commit generator and a liter commit that is configured to be checked before pushing to the repository.



Configure the commitizen utility


This tool allows you to generate commits using the built-in wizard. In addition, commitizen is well supported by the community and, thanks to additional modules, is perfectly customizable.

  1. Install the commitizen utility globally (you may need administrator privileges).

     npm i -g commitizen 
  2. Next install the adapter cz-customizable . It is needed to set up a template with questions used by the commitizen utility.

     npm i -D cz-customizable 
  3. Create a file commitizen.js, it is needed to configure cz-customizable. Place the created file in the directory ./config/git. I recommend not to litter the root of the project with configuration files and try to group the files in the folder prepared for this. Content:

    Show commitizen.js
     "use strict"; module.exports = { //         types: [ { value: "build", name: "build:      " }, { value: "ci", name: "ci:  CI    " }, { value: "docs", name: "docs:  " }, { value: "feat", name: "feat:   " }, { value: "fix", name: "fix:  " }, { value: "perf", name: "perf:     " }, { value: "refactor", name: "refactor:         " }, { value: "revert", name: "revert:    " }, { value: "style", name: "style:    (, , ,   ..)" }, { value: "test", name: "test:  " } ], // .    ,    scopes: [ { name: "components" }, { name: "tutorial" }, { name: "catalog" }, { name: "product" } ], //         (  'fix') /* scopeOverrides: { fix: [ {name: 'style'}, {name: 'e2eTest'}, {name: 'unitTest'} ] }, */ //    messages: { type: "   ?", scope: "\n ,    ():", //   allowCustomScopes  true customScope: "  :", subject: "     :\n", body: '   ().  "|"   :\n', breaking: " BREAKING CHANGES ():\n", footer: "    (,   ). : SECRETMRKT-700, SECRETMRKT-800:\n", confirmCommit: "   ?" }, //    allowCustomScopes: true, //   Breaking Changes allowBreakingChanges: false, //     footerPrefix: " :", // limit subject length subjectLimit: 72 }; 


  4. Add the package.json links to the cz-customizable and previously created configuration file:

    Show part package.json
     { "config": { "commitizen": { "path": "node_modules/cz-customizable" }, "cz-customizable": { "config": "config/git/commitizen.js" } }, } 

  5. Let's check the resulting result. Type the following command in the terminal:

     git cz 

The commitizen wizard will first collect information about the type and area of ​​the commit, then sequentially ask for the text that will be in the description, in the body, in the footer, and after your consent will create a commit.

Be sure to look at an example of how the commitizen utility is configured and the cz-cusomizable adapter connected to it.



Configure the husky and commitlint utilities


  1. Install husky and commitlint in the project:

     npm i -D husky @commitlint/cli 
  2. With the help of husky we will add check of kommit. To do this, in package.json immediately after the scripts, add the following hook and specify a link to the commitlint.js file in it:

    Show part package.json
     { "scripts": { "test": "echo \"Error: no test specified\" && exit 1" }, "husky": { "hooks": { "commit-msg": "commitlint -E HUSKY_GIT_PARAMS -g './config/git/commitlint.js'" } }, "devDependencies": { "@commitlint/cli": "^7.2.1", "husky": "^1.1.3", } 


  3. Create a file commitlint.js, necessary for the correct operation of the linter. Place the created file in the directory ./config/git. File contents:

    Show commitlint.js
     //     @commitlint/config-conventional module.exports = { rules: { //        "body-leading-blank": [2, "always"], //         "footer-leading-blank": [2, "always"], //    72  "header-max-length": [2, "always", 72], //       "scope-case": [2, "always", "lower-case"], //      "subject-empty": [2, "never"], //     '.' "subject-full-stop": [2, "never", "."], //       "type-case": [2, "always", "lower-case"], //      "type-empty": [2, "never"], //      "type-enum": [ 2, "always", [ "build", "ci", "docs", "feat", "fix", "perf", "refactor", "revert", "style", "test" ] ] } }; 



Everything. Now all commits will be checked before being sent to the repository :)

Be sure to look at an example of the work of the configured commitlint utility.



So choose commitizen or commitlint?


Both! In combination, they bring excellent results: the first generates commits, the second checks them.


Why do standards recommend imperative use?


This is a very interesting question. A commit is a change in code; a message in a commit can be interpreted as a guide to changing this code. Make, change, add, update, fix - all these are specific instructions for the developer.

By the way, the imperative is recommended in the Git versioning system itself :

 [[imperative-mood]] Describe your changes in imperative mood, eg "make xyzzy do frotz" instead of "[This patch] makes xyzzy do frotz" or "[I] changed xyzzy to do frotz", as if you are giving orders to the codebase to change its behavior. 


Why stick to any conventions? Is it worth spending time on it? What is the profit in this?


Worth it. In general, I noticed that we were more willing to detail the changes made to the code base. In the body of a commit, we describe in detail why we had to use certain solutions. Understanding the history has become objectively easier. Plus, our product is developing, and we are waiting for replenishment in the team. I am sure that thanks to the implementation of the standard and automation, it will be easier for new users to integrate into the development process.

Try and share the result.


Useful links:


Source: https://habr.com/ru/post/431432/


All Articles