{"id":24315641,"url":"https://github.com/devtobi/clean-commits-example","last_synced_at":"2026-04-16T17:01:24.541Z","repository":{"id":241796031,"uuid":"806567330","full_name":"devtobi/clean-commits-example","owner":"devtobi","description":"Example repository to demonstrate how to do clean commits","archived":false,"fork":false,"pushed_at":"2025-11-10T23:40:56.000Z","size":564,"stargazers_count":0,"open_issues_count":8,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-11-11T01:14:57.127Z","etag":null,"topics":["clean","conventional-commits","git","gitmoji"],"latest_commit_sha":null,"homepage":"","language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/devtobi.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2024-05-27T12:52:08.000Z","updated_at":"2024-11-03T16:24:35.000Z","dependencies_parsed_at":"2024-11-29T23:18:57.321Z","dependency_job_id":"3ba3fbdc-ee4e-4dd6-b408-24c3e36f1a15","html_url":"https://github.com/devtobi/clean-commits-example","commit_stats":null,"previous_names":["devtobi/clean-commits"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/devtobi/clean-commits-example","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/devtobi%2Fclean-commits-example","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/devtobi%2Fclean-commits-example/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/devtobi%2Fclean-commits-example/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/devtobi%2Fclean-commits-example/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/devtobi","download_url":"https://codeload.github.com/devtobi/clean-commits-example/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/devtobi%2Fclean-commits-example/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":31895650,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-04-16T11:36:10.202Z","status":"ssl_error","status_checked_at":"2026-04-16T11:36:09.652Z","response_time":69,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.5:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["clean","conventional-commits","git","gitmoji"],"created_at":"2025-01-17T11:18:15.022Z","updated_at":"2026-04-16T17:01:24.522Z","avatar_url":"https://github.com/devtobi.png","language":"JavaScript","readme":"[![Last commit][commit-shield]][commit-url]\n\n[![Open issues][issues-shield]][issues-url]\n[![Open pull requests][pr-shield]][pr-url]\n\n[![License][license-shield]][license-url]\n\n\u003cbr /\u003e\n\u003cp align=\"center\"\u003e\n  \u003ch3 align=\"center\"\u003eclean-commits-example\u003c/h3\u003e\n\n  \u003cp align=\"center\"\u003e\n    This is a example repository on how to do clean commits and force conventions like \u003ca href=\"https://www.conventionalcommits.org/en/v1.0.0/\"\u003eConventional Commits\u003c/a\u003e or \u003ca href=\"https://gitmoji.dev/specification\"\u003eGitmoji\u003c/a\u003e\n    \u003cbr /\u003e\n    \u003cbr /\u003e\n    \u003ca href=\"https://github.com/devtobi/clean-commits-example/issues/new/choose\"\u003eReport Bug\u003c/a\u003e\n    ·\n    \u003ca href=\"https://github.com/devtobi/clean-commits-example/issues/new/choose\"\u003eRequest Feature\u003c/a\u003e\n  \u003c/p\u003e\n\u003c/p\u003e\n\n\u003c!-- TABLE OF CONTENTS --\u003e\n\n## Table of Contents\n\n- [About the Project](#about-the-project)\n  - [Built With](#built-with)\n- [Getting Started](#getting-started)\n  - [Prerequisites](#prerequisites)\n  - [Installation](#installation)\n- [Usage](#usage)\n- [Authors](#authors)\n- [License](#license)\n\n## About The Project\n\nThis little example repository utilizes different tools to force developers to use a convention for commit messages. This is especially useful when working with tools for automated releases and versioning like [semantic-release](https://github.com/semantic-release/semantic-release) or [release-it](https://github.com/release-it/release-it). It forces the developer to better think about the purpose and effects of the commits.\n\nAs a bonus, this repository also shows how to enforce running of formatters of linters (or even unit tests) before commitin by using Git Hooks. This can be another 'security' mechanism for good code on top of the mechanisms inside CI/CD pipelines and will lead to fewer unnecessary pipeline runs (and save money).\n\n### Built With\n\n- [husky](https://github.com/typicode/husky) (to easily work with git hooks)\n- [commitlint](https://github.com/conventional-changelog/commitlint) (to check commit messages for compliance to chosen convention)\n- [commitizen](https://github.com/commitizen/cz-cli) (to help write commit messages as defined in the chosen convention)\n- [lint-staged](https://github.com/lint-staged/lint-staged) (to automatically lint staged files when commiting)\n- [prettier](https://github.com/prettier/prettier) (as an example formatter, could be anything)\n- [eslint](https://github.com/eslint/eslint) (as an example linter, could be anything)\n\nFurthermore:\n\n- [@commitlint/config-conventional](@commitlint/config-conventional) (as a example convention to use for commit messages, in my opinion also the best)\n- [@commitlint/cz-commitlint](https://www.npmjs.com/package/@commitlint/cz-commitlint) (to integrate commitlint configuration with commitizen)\n\nDocumentation for the tools mentioned:\n\n- [husky documentation](https://typicode.github.io/husky/how-to.html)\n- [commitlint documentation](https://commitlint.js.org/reference/configuration.html)\n- [commitizen documentation](http://commitizen.github.io/cz-cli/)\n- [lint-staged documentation](https://github.com/lint-staged/lint-staged?tab=readme-ov-file#configuration)\n\n## Getting Started\n\nTo try out the mechanisms for yourself, you can use this repository as a 'playground' locally on your computer.\n\nTo get a local copy up and running follow these simple steps.\n\n### Prerequisites\n\nI assume you have a current version of [git](https://git-scm.com) running on your system.\n\nBecause the tools heavily rely on Node you need to have a up-to-date (LTS) version of [Node](https://nodejs.org/en) installed on your system.\n\nThe project manages its dependencies via [bun](https://bun.sh) (in my opinion the better npm, never went back). You need to have `bun` installed on your system if you want this repository to work out-of-the-box.\n\n**Tip**: If you (for some reason) don't want or can't use `bun`, see step 2 in installation below.\n\n### Installation\n\n1. Clone the repo:\n\n   ```sh\n   git clone https://github.com/devtobi/clean-commits-example.git\n   ```\n\n2. (**Optional**): Switch to `npm` (if you don't have `bun`):\n\n   - Replace hook call inside `.husky` directory to use `npm` instead of `bun`\n   - Remove `bun.lockb` from the file system\n\n3. Install dependencies and initialize the git hooks via `husky`:\n\n   - bun: `bun install` or\n   - npm: `npm install`\n\n4. You are ready to go and checkout the features setup in this repository! Congratulations!\n\n## husky\n\nThe tool `husky` integrates the above-mentioned tools `commitlint`, `commitizen` and `lint-staged` into the normal workflow with `git` via Git Hooks. Tools can therefore be integrated via regular commands such as `git commit`.\n\n**Tip**: Git Hooks can be created file-based via the `.husky` folder and Git Hooks can be shared with all project members. These must therefore always be checked in to VCS.\n\nAn `npm install` (see step 2 above) also installs the hooks. Alternatively, the script `npm run prepare` can be called explicitly.\n\n**Attention**: After changing a hook, all developers must run `npm run prepare` again to activate the changes on their own machine.\n\n## Usage\n\n### 1. Perform valid commit\n\nFirst try to change the example file `dummy.txt` and create a commit using `git commit -m \"mymessage\"`. This project uses the [Conventional Commits](https://www.conventionalcommits.org/en/v1.0.0/#specification) convention, so the commit message must correspond to the format `type(scope): description`.\n\nExample: `git commit -m \"refactor(api): refactored dummy api endpoint\"`\n\nThe commit should be successful.\n\n### 2. Perform invalid commit\n\nChange the `dummy.txt` again and try a second commit. This time, however, explicitly violate the configured convention.\n\nExample: `git commit -m \"This is a test\"`\n\nThe commit should fail and `commitlint` should display a message about the errors and warnings found in the message. It looks like this, for example:\n\n\u003cimg src=\"./docs/commitlint-output.png\" alt=\"Error output from commitlint\" width=\"50%\"/\u003e\n\nThe convention used by `commitlint` is defined in [`commitlint.config.mjs`](commitlint.config.mjs). You can experiment with other conventions by installing [additional npm packages](https://www.npmjs.com/search?q=commitlint%2Fconfig) or extend the configuration file to meet your own specific needs by [creating your own rules](https://commitlint.js.org/reference/rules-configuration.html).\n\nA minimal configuration for `commitlint` looks like this (and follows the convention \"Conventional Commits\"):\n\n```js\nexport default {\n  extends: [\"@commitlint/config-conventional\"],\n};\n```\n\n### 3. Commit interactively\n\nIf you need help writing your commit message, simply run `git commit` and the interactive CLI `commitizen` will appear to assist you according to the configured convention.\n\nThe interactive interface will look like this:\n\n\u003cimg src=\"./docs/commitizen-output.png\" alt=\"Output of commitizen\" width=\"50%\"/\u003e\n\nThe interactive CLI can be configured via the file [`.czrc`](/.czrc). There are various [adapter packages](https://github.com/commitizen/cz-cli?tab=readme-ov-file#adapters) to support different conventions.\n\n**Tip:** We recommend using the adapter [`@commitlint/cz-commitlint`](https://www.npmjs.com/package/@commitlint/cz-commitlint), as this integrates the two tools `commitlint` and `commitizen` and the `commitlint` configuration is also automatically used for the interactive CLI.\n\nA minimal configuration for `commitizen` (with inheritance of the `commitlint` convention) looks as follows:\n\n```json\n{\n  \"path\": \"@commitlint/cz-commitlint\"\n}\n```\n\n### 4. Linting and formatting before committing\n\nPut an invalid change to the file `dummy.js` in the git staging area (via IDE or via `git add dummy.js`) and try to commit it. `lint-staged` scans files in the staging area and has them checked by the configured tools. An error should then have occurred due to `prettier` or `eslint`, depending on whether it is a formatting problem or a coding problem. The commit was not carried out.\n\nAn example error message looks like this:\n\n\u003cimg src=\"./docs/lintstaged-output.png\" alt=\"Output from lint-staged\" width=\"25%\"/\u003e\n\nThe linter and formatter to be used by `lint-staged` can be configured in the file [`.lintstagedrc.json`](/.lintstagedrc.json). CLI tools to be executed are specified here using pattern matching on file extensions. If several patterns are matched, several tools are also executed in parallel.\n\nAn example configuration for `lint-staged` looks as follows:\n\n```json\n{\n  \"*.{js,ts}\": [\"eslint\"],\n  \"*\": \"prettier --check\"\n}\n```\n\nWith the above configuration, for example, a `dummy.js` file is checked in parallel using `eslint` and `prettier --check`. A file `dummy.json` would only be checked by `prettier --check`. More information on the configuration can be found [in the official documentation](https://github.com/lint-staged/lint-staged?tab=readme-ov-file#configuration).\n\n### End\n\nCongratulations! You have tried out all the use cases!\n\nFurther examples can be found in the documentation of the tools used:\n\n- [husky documentation](https://typicode.github.io/husky/how-to.html)\n- [commitlint documentation](https://commitlint.js.org/reference/configuration.html)\n- [commitizen documentation](http://commitizen.github.io/cz-cli/)\n- [lint-staged-documentation](https://github.com/lint-staged/lint-staged?tab=readme-ov-file#configuration)\n\n## Authors\n\n- **Tobias Stadler** - [devtobi](https://github.com/devtobi)\n\n\u003c!-- LICENSE --\u003e\n\n## License\n\nDistributed under the MIT License. See [LICENSE][license-url] for more information.\n\n\u003c!-- MARKDOWN LINKS \u0026 IMAGES --\u003e\n\u003c!-- https://www.markdownguide.org/basic-syntax/#reference-style-links --\u003e\n\n[issues-shield]: https://img.shields.io/github/issues-raw/devtobi/clean-commits-example?style=for-the-badge\u0026logo=github\n[issues-url]: https://github.com/devtobi/clean-commits-example/issues?q=is%3Aopen+is%3Aissue+\n[pr-shield]: https://img.shields.io/github/issues-pr-raw/devtobi/clean-commits-example?style=for-the-badge\u0026logo=github\u0026label=Pull%20Requests\n[pr-url]: https://github.com/devtobi/clean-commits-example/pulls?q=is%3Apr+is%3Aopen\n[license-shield]: https://img.shields.io/github/license/devtobi/clean-commits-example.svg?style=for-the-badge\u0026logo=github\n[license-url]: https://github.com/devtobi/clean-commits-example/blob/main/LICENSE\n[commit-shield]: https://img.shields.io/github/last-commit/devtobi/clean-commits-example?style=for-the-badge\u0026logo=github\n[commit-url]: https://github.com/devtobi/clean-commits-example/commit/main\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdevtobi%2Fclean-commits-example","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fdevtobi%2Fclean-commits-example","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdevtobi%2Fclean-commits-example/lists"}