Proposal: Clearer definitions for Conventional Commit types #219

Open
opened 2026-02-17 11:54:13 -06:00 by GiteaMirror · 16 comments
Owner

Originally created by @0x404 on GitHub (Jan 21, 2025).

We conducted a study and found that conventional commits are becoming increasingly popular among top open-source projects. Specifically, there is a stable uptrend in the adoption of conventional commits, with some projects mandating their use. By 2023, in repositories that do not require conventional commits, we found nearly 10% of commits were in line with the Conventional Commit format, indicating their popularity among developers.

During this process, we noticed that some commits, despite being conventional, clearly misused the commit message format, for example: feat: remove unnecessary lines from test file. This spurred our curiosity about the challenges developers face when categorizing commits using the conventional commits format. Therefore, we analyzed all the issues in this project, as well as the top 100 questions on Stack Overflow related to conventional commits. Our analysis identified four categories of challenges developers face, with the most common (around 57.7%) being confusion over which type to use. In the current CCS definition, categories other than 'feat' and 'fix' lack clear definitions, leading developers to rely on the categorizations used by Angular and other projects, which often overlap and lack clarity. For instance, in Angular's definition, 'refactor' is defined as "A code change that neither fixes a bug nor adds a feature," which could ambiguously include 'style', 'perf', 'test', among others.

We have proposed a clearer and less overlapping list of definitions based on our literature review and the documentation in repositories currently using conventional commits. Based on this, we have drafted an academic paper (you can find more detailed information about the above here), which has undergone peer review and been accepted by ICSE 2025, a premier software engineering conference.

We are happy to provide additional details or clarification about our methodology and findings. We look forward to any feedback you may have.

Originally created by @0x404 on GitHub (Jan 21, 2025). We conducted a study and found that conventional commits are becoming increasingly popular among top open-source projects. Specifically, there is a stable uptrend in the adoption of conventional commits, with some projects mandating their use. By 2023, in repositories that do not require conventional commits, we found nearly 10% of commits were in line with the Conventional Commit format, indicating their popularity among developers. During this process, we noticed that some commits, despite being conventional, clearly misused the commit message format, for example: feat: remove unnecessary lines from test file. This spurred our curiosity about the challenges developers face when categorizing commits using the conventional commits format. Therefore, we analyzed all the issues in this project, as well as the top 100 questions on Stack Overflow related to conventional commits. Our analysis identified four categories of challenges developers face, with the most common (around 57.7%) being confusion over which type to use. In the current CCS definition, categories other than 'feat' and 'fix' lack clear definitions, leading developers to rely on the categorizations used by Angular and other projects, which often overlap and lack clarity. For instance, in Angular's definition, 'refactor' is defined as "A code change that neither fixes a bug nor adds a feature," which could ambiguously include 'style', 'perf', 'test', among others. We have proposed a clearer and less overlapping list of definitions based on our literature review and the documentation in repositories currently using conventional commits. Based on this, we have drafted an academic paper (you can find more detailed information about the above [here](https://github.com/0x404/conventional-commit-classification/blob/main/paper.pdf)), which has undergone peer review and been accepted by [ICSE 2025](https://conf.researchr.org/home/icse-2025), a premier software engineering conference. We are happy to provide additional details or clarification about our methodology and findings. We look forward to any feedback you may have.
Author
Owner

@Aseem007-007 commented on GitHub (Feb 13, 2025):

Pal

@Aseem007-007 commented on GitHub (Feb 13, 2025): Pal
Author
Owner

@bcoe commented on GitHub (May 5, 2025):

@0x404 this is super interesting. Apologies that I'm a terrible open source maintainer these days, and am responding months after the fact.

If you would like to draft a recommendation for a better set of recommended types, I'm very open to the discussion. As long as we maintain the goal of simplicity and minimalism.

Personally, I think less is more in terms of categories, preferring to almost always use feat:, fix:, docs:, fix(deps): (for a dependency update).

@bcoe commented on GitHub (May 5, 2025): @0x404 this is super interesting. Apologies that I'm a terrible open source maintainer these days, and am responding months after the fact. If you would like to draft a recommendation for a better set of recommended types, I'm very open to the discussion. As long as we maintain the goal of simplicity and minimalism. Personally, I think less is more in terms of categories, preferring to almost always use `feat:`, `fix:`, `docs:`, `fix(deps):` (for a dependency update).
Author
Owner

@0x404 commented on GitHub (Jun 6, 2025):

Hi @bcoe, my sincere apologies for the late update, just been through an exceptionally busy month.

I would absolutely love to draft a definition list for conventional commit types. Below are the definitions we proposed in our paper:

  • feat: Code changes aim to introduce new features to the codebase, encompassing both internal and user-oriented features.
  • fix: Code changes aim to fix bugs and faults within the codebase.
  • perf: Code changes aim to improve performance, such as enhancing execution speed or reducing memory consumption.
  • style: Code changes aim to improve readability without affecting the meaning of the code. This type encompasses aspects like variable naming, indentation, and addressing linting or code analysis warnings.
  • refactor: Code changes aim to restructure the program without changing its functional behavior, aiming to improve maintainability. (To avoid confusion and overlap, we propose the constraint that this category does not include changes classified as "perf" or "style") Examples include enhancing modularity, refining exception handling, improving scalability, conducting code cleanup, and removing deprecated code.
  • docs: Code changes that modify documentation or text, such as correcting typos, modifying comments, or updating documentation.
  • test: Code changes that modify test files, including the addition or updating of tests.
  • ci: Code changes to CI (Continuous Integration) configuration files and scripts, such as configuring or updating CI/CD scripts, e.g., .travis.yml'' and .github/workflows''.
  • build: Code changes affecting the build system (e.g., Maven, Gradle, Cargo). Change examples include updating dependencies, configuring build configurations, and adding scripts.
  • chore: Code changes for other miscellaneous tasks that do not neatly fit into any of the above categories.

I completely agree that less is more when it comes to categories, but I believe having clear definitions helps users understand each type better. The current Conventional Commits 1.0 specification redirects to projects like Angular, but Angular's definitions are quite ambiguous with overlap. For example, their "refactor" definition ("A code change that neither fixes a bug nor adds a feature") is problematic.

I think we could streamline these proposed definitions while maintaining clarity to help users better understand each type. I'd greatly appreciate any insights you might have, and I'm available to collaborate on this, I'll respond as promptly as possible.

@0x404 commented on GitHub (Jun 6, 2025): Hi @bcoe, my sincere apologies for the late update, just been through an exceptionally busy month. I would absolutely love to draft a definition list for conventional commit types. Below are the definitions we proposed in our paper: - feat: Code changes aim to introduce new features to the codebase, encompassing both internal and user-oriented features. - fix: Code changes aim to fix bugs and faults within the codebase. - perf: Code changes aim to improve performance, such as enhancing execution speed or reducing memory consumption. - style: Code changes aim to improve readability without affecting the meaning of the code. This type encompasses aspects like variable naming, indentation, and addressing linting or code analysis warnings. - refactor: Code changes aim to restructure the program without changing its functional behavior, aiming to improve maintainability. (To avoid confusion and overlap, we propose the constraint that this category does not include changes classified as "perf" or "style") Examples include enhancing modularity, refining exception handling, improving scalability, conducting code cleanup, and removing deprecated code. - docs: Code changes that modify documentation or text, such as correcting typos, modifying comments, or updating documentation. - test: Code changes that modify test files, including the addition or updating of tests. - ci: Code changes to CI (Continuous Integration) configuration files and scripts, such as configuring or updating CI/CD scripts, e.g., ``.travis.yml'' and ``.github/workflows''. - build: Code changes affecting the build system (e.g., Maven, Gradle, Cargo). Change examples include updating dependencies, configuring build configurations, and adding scripts. - chore: Code changes for other miscellaneous tasks that do not neatly fit into any of the above categories. I completely agree that less is more when it comes to categories, but I believe having clear definitions helps users understand each type better. The current Conventional Commits 1.0 specification redirects to projects like Angular, but Angular's definitions are quite ambiguous with overlap. For example, their "refactor" definition ("A code change that neither fixes a bug nor adds a feature") is problematic. I think we could streamline these proposed definitions while maintaining clarity to help users better understand each type. I'd greatly appreciate any insights you might have, and I'm available to collaborate on this, I'll respond as promptly as possible.
Author
Owner

@Aseem007-007 commented on GitHub (Jun 6, 2025):

(null) - مفتاح وصول جهة الاتصال الوارثة 2.pdf

@Aseem007-007 commented on GitHub (Jun 6, 2025): [(null) - مفتاح وصول جهة الاتصال الوارثة 2.pdf](https://github.com/user-attachments/files/20623049/null.-.2.pdf)
Author
Owner

@stechio commented on GitHub (Jun 14, 2025):

As it's used to say, a picture is worth a thousand words... 😄

Image

This diagram represents the orthogonal relation between source code categories (black boxes, upper-left labels) and Conventional Commits types (colored boxes, lower-right labels).

Related commit types share the same color:

  • refactoring-related commit types are marked in yellow
  • configuration-related commit types are marked in orange

EDITS:

  • API code subset has been expanded to encompass API fixes
  • BREAKING CHANGE commit subset has been expanded to encompass all possible cases
  • feat, fix and style commit types have been expanded to encompass all possible cases
@stechio commented on GitHub (Jun 14, 2025): As it's used to say, a picture is worth a thousand words... 😄 <img width="782" height="1115" alt="Image" src="https://github.com/user-attachments/assets/9f806948-1de7-4627-955f-bfc5d3ea94df" /> [This diagram](https://gist.github.com/stechio/2eb279625b8a192d73bafe8f74008c63) represents the **orthogonal relation between source code categories** (black boxes, upper-left labels) **and Conventional Commits types** (colored boxes, lower-right labels). Related commit types share the same color: - refactoring-related commit types are marked in yellow - configuration-related commit types are marked in orange --- **EDITS:** - API code subset has been expanded to encompass API fixes - `BREAKING CHANGE` commit subset has been expanded to encompass all possible cases - `feat`, `fix` and `style` commit types have been expanded to encompass all possible cases
Author
Owner

@JohnnyWalkerDigital commented on GitHub (Dec 16, 2025):

There is a dire need for clear and clean definitions for each of the prefixes. It's kind of astonishing that the specification doesn't already have them.

@JohnnyWalkerDigital commented on GitHub (Dec 16, 2025): There is a dire need for clear and clean definitions for each of the prefixes. It's kind of astonishing that the specification doesn't already have them.
Author
Owner

@edenworky commented on GitHub (Dec 20, 2025):

I'll go a step further, building on the lovely picture above, and say that to organise commits by file type is pretty silly, really. As an example I ran into trying to adapt conventional commits: I write and update my tests and my code in tandem; a single update is reflected across both code and tests files and therefore (in my eyes) belong in a single commit, in which case I use a more appropriate type than test:. Likewise, if I change tests around or write a couple extra tests without changing the functionality of the code, that's more refactor: to me, and so I ended up never using test: for anything.

This is perhaps a somewhat belabored example, but not too uncommon I'm sure. In any case, commits surely are unified named units of changes across one or many files of one or many types, and if (and where) the types are restrictive of that, they'll either be unused or be used at the expense of the actual git log.

A potential solution might be supporting multiple types (messy, cluttered), and a better one might be a sort of hierarchy of types (i.e., "use test: if your commit contains tests" but with a "lower priority" than "use feat: if your commit adds a feature or changes functionality", which naturally should include tests).

This is not to say that everyone works or should work like this, just that I do and I know other who do, and that the current spec doesn't really address this.

@edenworky commented on GitHub (Dec 20, 2025): I'll go a step further, building on the lovely picture above, and say that to organise commits by file type is pretty silly, really. As an example I ran into trying to adapt conventional commits: I write and update my tests and my code in tandem; a single update is reflected across both code and tests files and therefore (in my eyes) belong in a single commit, in which case I use a more appropriate type than `test:`. Likewise, if I change tests around or write a couple extra tests without changing the functionality of the code, that's more `refactor:` to me, and so I ended up never using `test:` for anything. This is perhaps a somewhat belabored example, but not too uncommon I'm sure. In any case, commits surely are unified named units of changes across one or many files of one or many types, and if (and where) the types are restrictive of that, they'll either be unused or be used at the expense of the actual `git log`. A potential solution might be supporting multiple types (messy, cluttered), and a better one might be a sort of hierarchy of types (i.e., "use `test:` if your commit contains tests" but with a "lower priority" than "use `feat:` if your commit adds a feature or changes functionality", which naturally should include tests). This is not to say that everyone works or should work like this, just that I do and I know other who do, and that the current spec doesn't really address this.
Author
Owner

@stechio commented on GitHub (Dec 27, 2025):

@edenworky:

I'll go a step further, building on the lovely picture above, and say that to organise commits by file type is pretty silly, really. As an example I ran into trying to adapt conventional commits: I write and update my tests and my code in tandem; a single update is reflected across both code and tests files and therefore (in my eyes) belong in a single commit, in which case I use a more appropriate type than test:. Likewise, if I change tests around or write a couple extra tests without changing the functionality of the code, that's more refactor: to me, and so I ended up never using test: for anything.

The spec does NOT organize commits "by file type": they are organized by purpose, hence their orthogonality to source code categories. Nonetheless, there's indisputably a certain degree of semantic ambiguity in the spec which gives room to conflicting interpretations; however, after wrestling a bit to match real-world cases and respective commit types, implicit patterns tend to emerge (and should desirably be made explicit in future revisions of the spec). In particular, the answer to the spec FAQ "What do I do if the commit conforms to more than one of the commit types?" may sound somewhat misleading (emphasis is mine):

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.

The key here is "whenever possible": what the spec implies is that a commit should contain nothing but a cohesive set of modifications (like your first case, with production code and related tests); if such cohesive set of modifications spans multiple commit types (in your case, feat/fix for production code and test for related tests), the actual type of the commit is the most relevant one (which corresponds to your concept of commit type hierarchy — in your case, feat/fix will mark a single commit encompassing both production code and related test modifications). Conversely, your second case (a couple extra tests without changing the functionality of the production code) will be marked with test commit type, since refactor is specific to production code (as clearly shown in my diagram here above — its topology is significant, pay attention, please!). That's because production code, being at the core of a project and driving functions like semantic version bumping, enjoys the maximum granularity, whilst test code, being ancillary to a project, has test commit type encompassing ALL kinds of changes, except source formatting (which is marked by style commit type) and documentation (which is marked by docs commit type) .

Sometimes even a cohesive set of modifications may require to be split into separate commits, though: for example, if a modification in the build configuration causes the code formatting to change, it is more appropriate to commit the build configuration change first (with build commit type), then the affected code (with style commit type) — funneling both build configuration and affected code together into a single commit would bury the actual modification (build configuration) under tons of derivative code changes!

Recapping:

  • each and every commit MUST contain a cohesive set of modifications (possibly spanning multiple commit types)
  • the commit type of a commit MUST be the most relevant, according to the source hierarchy of the affected code (production code, then test code; documentation has always the lowest priority)
  • a cohesive set of modifications MUST be further split into separate commits if subsets of modifications are automatically derived from others; in such case, the first commit MUST contain the primary modifications, whilst the following commit MUST contain the derivative ones

I agree that the spec should indeed explicitly state these prescriptions, which currently are only subtly implied.

@stechio commented on GitHub (Dec 27, 2025): @edenworky: > I'll go a step further, building on the lovely picture above, and say that to organise commits by file type is pretty silly, really. As an example I ran into trying to adapt conventional commits: I write and update my tests and my code in tandem; a single update is reflected across both code and tests files and therefore (in my eyes) belong in a single commit, in which case I use a more appropriate type than `test:`. Likewise, if I change tests around or write a couple extra tests without changing the functionality of the code, that's more `refactor:` to me, and so I ended up never using `test:` for anything. *The spec does NOT organize commits "by file type"*: they are organized by purpose, hence their orthogonality to source code categories. *Nonetheless, there's indisputably a certain degree of semantic ambiguity in the spec which gives room to conflicting interpretations*; however, after wrestling a bit to match real-world cases and respective commit types, implicit patterns tend to emerge (and should desirably be made explicit in future revisions of the spec). In particular, the answer to the spec FAQ "What do I do if the commit conforms to more than one of the commit types?" may sound somewhat misleading (emphasis is mine): > 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. The key here is "whenever possible": what the spec implies is that *a commit should contain nothing but a **cohesive set of modifications*** (like your first case, with production code and related tests); if such cohesive set of modifications spans multiple commit types (in your case, `feat`/`fix` for production code and `test` for related tests), *the actual type of the commit is the most relevant one* (which corresponds to your concept of commit type hierarchy — in your case, `feat`/`fix` will mark a single commit encompassing both production code and related test modifications). Conversely, your second case (a couple extra tests without changing the functionality of the production code) will be marked with `test` commit type, since `refactor` is specific to production code (as clearly shown in [my diagram here above](https://github.com/conventional-commits/conventionalcommits.org/issues/634#issuecomment-2972312193) — its topology is significant, pay attention, please!). That's because production code, being at the core of a project and driving functions like semantic version bumping, enjoys the maximum granularity, whilst test code, being ancillary to a project, has `test` commit type encompassing ALL kinds of changes, except source formatting (which is marked by `style` commit type) and documentation (which is marked by `docs` commit type) . *Sometimes even a cohesive set of modifications may require to be split into **separate commits**, though*: for example, if a modification in the build configuration causes the code formatting to change, it is more appropriate to commit the build configuration change first (with `build` commit type), then the affected code (with `style` commit type) — funneling both build configuration and affected code together into a single commit would bury the actual modification (build configuration) under tons of derivative code changes! Recapping: - each and every **commit** MUST contain a *cohesive set of modifications* (possibly spanning multiple commit types) - the **commit type** of a commit MUST be *the most relevant, according to the source hierarchy of the affected code* (production code, then test code; documentation has always the lowest priority) - a cohesive set of modifications MUST be further split into **separate commits** if *subsets of modifications are automatically derived from others*; in such case, the first commit MUST contain the primary modifications, whilst the following commit MUST contain the derivative ones I agree that **the spec should indeed explicitly state these prescriptions, which currently are only subtly implied.**
Author
Owner

@edenworky commented on GitHub (Dec 27, 2025):

Hi, thanks for the detailed and enlightening response.

You're right, I totally missed that refactor: doesn't span over test code like style: does. I also note that perf: (performance?) is likewise limited only to production code.

Your prescriptions sound like a more refined version of what I naively intuited in my last post, and I agree they should be clear and explicit in the spec, and I'd go as far as to say that the FAQ you quoted is absolutely misleading in this regard, at least in lack of said prescriptions laid out with greater priority. If the answer to the question "What do I do if the commit conforms to [both fix and test]?" is to "go back and make multiple commits if possible", then in this case it's certainly possible, it would just lead to redundant commits and a messier log, if one were to act as prescribed in the spec currently.

Your prescriptions make much more sense to me, i.e. "if [one cohesive unit of diffs] fits both fix and test then it's one commit of type fix" makes much more sense (i.e., if I review a commit of type fix, I'd expect to see a production code change and a test (or a couple) reflecting it), but it's entirely possible to break it up into multiple commits, and that's what's explicitly prescribed by the FAQ you quoted.

So, agreed entirely. Maybe a little decision tree graph could show this clearly and simply (covering your recap essentially), and amending the FAQ; really the question being answered there is "what do I do if I'm trying to commit more than one cohesive set of modifications in one commit", which should be avoided, but it doesn't answer "what do I do if my one cohesive set of modifications fits more than one type", which is what it sounds like it's answering, and answering by "split it into multiple commits if at all possible", which I understand now is not the intent but that's really what it reads as.


Circling back to my earlier point about refactor and perf not applying to test in the graph you shared.

My particular needs are perhaps somewhat unconventional in this regard, but not terribly so.

I sometimes work with proof systems, and I often employ generative and/or property-based testing, as well as "golden"/snapshot testing. I've also had medium+ webdriver suites. In all these cases as well as many others (e.g. test DB seeding), both performance and code structure/factoring (e.g. page models, custom assertions, data/code generation, etc etc) matter a great deal, and I'll often refactor/optimise my tests (as well as the occasional fix). Perhaps in this case test is more scope than type? But certainly I've used these types for cohesive modification sets which were only over test files plus/minus some invocation change or smth. Certainly it's not a ci concern (running tests faster is moreso a dev env concern than a CI/CD concern tho it helps certainly). What should be prescribed in these cases?

@edenworky commented on GitHub (Dec 27, 2025): Hi, thanks for the detailed and enlightening response. You're right, I totally missed that `refactor:` doesn't span over test code like `style:` does. I also note that `perf:` (performance?) is likewise limited only to production code. Your prescriptions sound like a more refined version of what I naively intuited in my last post, and I agree they should be clear and explicit in the spec, and I'd go as far as to say that the FAQ you quoted is absolutely misleading in this regard, at least in lack of said prescriptions laid out with greater priority. If the answer to the question "What do I do if the commit conforms to [both `fix` and `test`]?" is to "go back and make multiple commits if possible", then in this case it's certainly *possible*, it would just lead to redundant commits and a messier log, if one were to act as prescribed in the spec currently. Your prescriptions make much more sense to me, i.e. "if [one cohesive unit of diffs] fits both `fix` and `test` then it's one commit of type `fix`" makes much more sense (i.e., if I review a commit of type `fix`, I'd expect to see a production code change and a test (or a couple) reflecting it), but it's entirely possible to break it up into multiple commits, and that's what's explicitly prescribed by the FAQ you quoted. So, agreed entirely. Maybe a little decision tree graph could show this clearly and simply (covering your recap essentially), and amending the FAQ; really the question being answered there is "what do I do if I'm trying to commit more than one cohesive set of modifications in one commit", which should be avoided, but it doesn't answer "what do I do if my one cohesive set of modifications fits more than one type", which is what it sounds like it's answering, and answering by "split it into multiple commits *if at all possible*", which I understand now is not the intent but that's really what it reads as. --- Circling back to my earlier point about `refactor` and `perf` not applying to `test` in the graph you shared. My particular needs are perhaps somewhat *un*conventional in this regard, but not terribly so. I sometimes work with proof systems, and I often employ generative and/or property-based testing, as well as "golden"/snapshot testing. I've also had medium+ webdriver suites. In all these cases as well as many others (e.g. test DB seeding), both performance and code structure/factoring (e.g. page models, custom assertions, data/code generation, etc etc) matter a great deal, and I'll often refactor/optimise my tests (as well as the occasional `fix`). Perhaps in this case `test` is more scope than type? But certainly I've used these types for cohesive modification sets which were only over test files plus/minus some invocation change or smth. Certainly it's not a `ci` concern (running tests faster is moreso a dev env concern than a CI/CD concern tho it helps certainly). What should be prescribed in these cases?
Author
Owner

@stechio commented on GitHub (Dec 28, 2025):

@edenworky:

Hi, thanks for the detailed and enlightening response.

If you agree with my points, please apply a reaction emoji to my comment, so it better sticks out as a contribution to the topic.

@edenworky:

Circling back to my earlier point about refactor and perf not applying to test in the graph you shared.

My particular needs are perhaps somewhat _un_conventional in this regard, but not terribly so.

I sometimes work with proof systems, and I often employ generative and/or property-based testing, as well as "golden"/snapshot testing. I've also had medium+ webdriver suites. In all these cases as well as many others (e.g. test DB seeding), both performance and code structure/factoring (e.g. page models, custom assertions, data/code generation, etc etc) matter a great deal, and I'll often refactor/optimise my tests (as well as the occasional fix). Perhaps in this case test is more scope than type? But certainly I've used these types for cohesive modification sets which were only over test files plus/minus some invocation change or smth. Certainly it's not a ci concern (running tests faster is moreso a dev env concern than a CI/CD concern tho it helps certainly). What should be prescribed in these cases?

First of all, a disclaimer: I'm NOT an author of the spec, so I'm NOT in a position to dictate what should be prescribed (the "prescriptions" I formulated in my previous comment are just an inference combining the spec with heuristics).

Going back to your question, you should ditch all your assumptions and simply fit your case into the spec: if you keep resisting and bending the spec to fit your assumptions, you are going nowhere, as the purpose of a spec is to provide a basic set of rules everyone agrees upon, NOT to push your assumptions onto others 😉 — so:

  • if your work on test suites revolves mainly around performance and code refactoring, it doesn't matter to the spec, at all: its commit type is just test, in ALL cases!
  • conversely, if your work involves code of a reusable test harness, then such code is production code in itself, so it should be applied the same commit types as any other production code (including refactor and perf). In this case, you could employ "test" as scope, BUT that would be totally arbitrary and unrelated to the spec
@stechio commented on GitHub (Dec 28, 2025): @edenworky: > Hi, thanks for the detailed and enlightening response. If you agree with my points, please apply a reaction emoji to my comment, so it better sticks out as a contribution to the topic. @edenworky: > Circling back to my earlier point about `refactor` and `perf` not applying to `test` in the graph you shared. > > My particular needs are perhaps somewhat _un_conventional in this regard, but not terribly so. > > I sometimes work with proof systems, and I often employ generative and/or property-based testing, as well as "golden"/snapshot testing. I've also had medium+ webdriver suites. In all these cases as well as many others (e.g. test DB seeding), both performance and code structure/factoring (e.g. page models, custom assertions, data/code generation, etc etc) matter a great deal, and I'll often refactor/optimise my tests (as well as the occasional `fix`). Perhaps in this case `test` is more scope than type? But certainly I've used these types for cohesive modification sets which were only over test files plus/minus some invocation change or smth. Certainly it's not a `ci` concern (running tests faster is moreso a dev env concern than a CI/CD concern tho it helps certainly). What should be prescribed in these cases? First of all, a disclaimer: I'm NOT an author of the spec, so I'm NOT in a position to dictate what should be *prescribed* (the "prescriptions" I formulated in my previous comment are just an inference combining the spec with heuristics). Going back to your question, *you should ditch all your assumptions and simply fit your case into the spec*: if you keep resisting and bending the spec to fit your assumptions, you are going nowhere, as the purpose of a spec is to provide a basic set of rules everyone agrees upon, NOT to push your assumptions onto others 😉 — so: - if your work on **test suites** revolves mainly around performance and code refactoring, it doesn't matter to the spec, at all: its commit type is just `test`, in ALL cases! - conversely, if your work involves code of a **reusable test harness**, then such code is production code in itself, so it should be applied the same commit types as any other production code (including `refactor` and `perf`). In this case, you could employ "test" as scope, BUT that would be totally arbitrary and unrelated to the spec
Author
Owner

@stechio commented on GitHub (Dec 28, 2025):

Reading the proposal definitions, I noted some details to amend.

@0x404:

  • feat: Code changes aim to introduce new features to the codebase, encompassing both internal and user-oriented features.

  • fix: Code changes aim to fix bugs and faults within the codebase.

TO IMPROVE: I'd replace "codebase" with "production code", as the former is ambiguous (a codebase includes also test code, build configuration, CI/CD configuration). Furthermore, fix should include also updates to production dependencies.

@0x404:

  • perf: Code changes aim to improve performance, such as enhancing execution speed or reducing memory consumption.

[...]

  • refactor: Code changes aim to restructure the program without changing its functional behavior, aiming to improve maintainability. (To avoid confusion and overlap, we propose the constraint that this category does not include changes classified as "perf" or "style") Examples include enhancing modularity, refining exception handling, improving scalability, conducting code cleanup, and removing deprecated code.

TO IMPROVE: I'd clarify perf and refactor apply to production code only (test code is always associated to test commit type).

@0x404:

  • build: Code changes affecting the build system (e.g., Maven, Gradle, Cargo). Change examples include updating dependencies, configuring build configurations, and adding scripts.

WRONG: you should think about dependencies as parts of the codebase delegated externally: updating production dependencies belongs to commit type fix (as already stated by @bcoe); on the other hand, updating build dependencies, which have no use outside the build process of the project, belongs to commit type build.

@stechio commented on GitHub (Dec 28, 2025): Reading the [proposal definitions](https://github.com/conventional-commits/conventionalcommits.org/issues/634#issuecomment-2948248673), I noted some details to amend. @0x404: > * feat: Code changes aim to introduce new features to the codebase, encompassing both internal and user-oriented features. > > * fix: Code changes aim to fix bugs and faults within the codebase. TO IMPROVE: I'd replace "codebase" with "production code", as the former is ambiguous (a codebase includes also test code, build configuration, CI/CD configuration). Furthermore, `fix` should include also updates to production dependencies. @0x404: > * perf: Code changes aim to improve performance, such as enhancing execution speed or reducing memory consumption. > > [...] > > * refactor: Code changes aim to restructure the program without changing its functional behavior, aiming to improve maintainability. (To avoid confusion and overlap, we propose the constraint that this category does not include changes classified as "perf" or "style") Examples include enhancing modularity, refining exception handling, improving scalability, conducting code cleanup, and removing deprecated code. TO IMPROVE: I'd clarify `perf` and `refactor` apply to production code only (test code is always associated to `test` commit type). @0x404: > * build: Code changes affecting the build system (e.g., Maven, Gradle, Cargo). Change examples include updating dependencies, configuring build configurations, and adding scripts. WRONG: you should think about dependencies as parts of the codebase delegated externally: updating production dependencies belongs to commit type `fix` (as already stated by @bcoe); on the other hand, updating build dependencies, which have no use outside the build process of the project, belongs to commit type `build`.
Author
Owner

@javier-godoy commented on GitHub (Dec 29, 2025):

@edenworky @stechio

  • each and every commit MUST contain a cohesive set of modifications (possibly spanning multiple commit types)

In our team's guidelines, we interpret Conventional Commits as a framework that encourages "logically atomic commits". The goal is for every commit to be a self-contained unit: valuable on its own, yet small enough to review or revert without friction.

While reverting isn't the expected action, we use "revertibility" as a helpful heuristic: if a revert would undo unrelated logic or too much context, the commit was likely too large; and if it leaves the codebase in an inconsistent or broken state, the commit was likely too small. It’s a common-sense way to gauge atomicity without relying on rigid rules.

More about atomic/logical commits:

@javier-godoy commented on GitHub (Dec 29, 2025): @edenworky @stechio > * each and every **commit** MUST contain a _cohesive set of modifications_ (possibly spanning multiple commit types) In [our team's guidelines](https://github.com/FlowingCode/DevelopmentConventions/blob/main/conventional-commits.md), we interpret Conventional Commits as a framework that encourages "logically atomic commits". The goal is for every commit to be a self-contained unit: valuable on its own, yet small enough to review or revert<sup>∗</sup> without friction. <sup>∗</sup> While reverting isn't the expected action, we use "revertibility" as a helpful heuristic: if a revert would undo unrelated logic or too much context, the commit was likely too large; and if it leaves the codebase in an inconsistent or broken state, the commit was likely too small. It’s a common-sense way to gauge atomicity without relying on rigid rules. More about atomic/logical commits: - https://benmatselby.dev/post/logical-commits/ - https://dev.to/cbillowes/why-i-create-atomic-commits-in-git-kfi
Author
Owner

@JohnnyWalkerDigital commented on GitHub (Dec 29, 2025):

Logically atomic commits are a great idea... Serious question: what do you do if you make a mistake and commit something only to discover it fails somewhere, and so the feature isn't complete? Do you make a new commit (fix: -- even though the feature was never even completed) or do you revert your commit until it's at least working?

Side note: IHMO tests and features/refactors are intrinsically linked. Adding a new feature should, in turn, mean news tests are added (especially if you're doing TDD). And getting bogged down in ensuring that no tests were updated as part of a refactoring or created as part of a new feature seems headache-inducing to me.

If only tests were updated, I'll use test, but if a new feature is added, along with accompanying tests, I'll place it under feat. Likewise if a refactor results in tests updating, I'll use refactor.

@JohnnyWalkerDigital commented on GitHub (Dec 29, 2025): Logically atomic commits are a great idea... Serious question: what do you do if you make a mistake and commit something only to discover it fails somewhere, and so the feature isn't complete? Do you make a new commit (`fix:` -- even though the feature was never even completed) or do you revert your commit until it's at least working? Side note: IHMO tests and features/refactors are intrinsically linked. Adding a new feature should, in turn, mean news tests are added (especially if you're doing TDD). And getting bogged down in ensuring that no tests were updated as part of a refactoring or created as part of a new feature seems headache-inducing to me. If only tests were updated, I'll use `test`, but if a new feature is added, along with accompanying tests, I'll place it under `feat`. Likewise if a refactor results in tests updating, I'll use `refactor`.
Author
Owner

@javier-godoy commented on GitHub (Dec 30, 2025):

@JohnnyWalkerDigital

Logically atomic commits are a great idea... Serious question: what do you do if you make a mistake and commit something only to discover it fails somewhere, and so the feature isn't complete? Do you make a new commit (fix: -- even though the feature was never even completed) or do you revert your commit until it's at least working?

If we find and correct a bug before merging the feature branch, then we amend/squash the original feat: commit to ensure it remains atomic. However, once the branch has been merged into the main history, we use a separate fix: commit. Personally, I view these post-merge adjustments (so long as they occur before a release) as "incremental changes", which I regard as a different beast than a fix:, though most of my colleagues disagree with that distinction.

@javier-godoy commented on GitHub (Dec 30, 2025): @JohnnyWalkerDigital > Logically atomic commits are a great idea... Serious question: what do you do if you make a mistake and commit something only to discover it fails somewhere, and so the feature isn't complete? Do you make a new commit (`fix:` -- even though the feature was never even completed) or do you revert your commit until it's at least working? If we find and correct a bug before merging the feature branch, then we amend/squash the original `feat:` commit to ensure it remains atomic. However, once the branch has been merged into the main history, we use a separate `fix:` commit. Personally, I view these post-merge adjustments (so long as they occur before a release) as "incremental changes", which I regard as a different beast than a `fix:`, though most of my colleagues [disagree with that distinction](https://github.com/FlowingCode/DevelopmentConventions/issues/26).
Author
Owner

@stechio commented on GitHub (Dec 31, 2025):

@JohnnyWalkerDigital:

Side note: IHMO tests and features/refactors are intrinsically linked. Adding a new feature should, in turn, mean news tests are added (especially if you're doing TDD). And getting bogged down in ensuring that no tests were updated as part of a refactoring or created as part of a new feature seems headache-inducing to me.

If only tests were updated, I'll use test, but if a new feature is added, along with accompanying tests, I'll place it under feat. Likewise if a refactor results in tests updating, I'll use refactor.

We have already discussed these cases a couple of comments above, here and here, no need to repeat all over again 😉

@stechio commented on GitHub (Dec 31, 2025): @JohnnyWalkerDigital: > Side note: IHMO tests and features/refactors are intrinsically linked. Adding a new feature should, in turn, mean news tests are added (especially if you're doing TDD). And getting bogged down in ensuring that no tests were updated as part of a refactoring or created as part of a new feature seems headache-inducing to me. > > If only tests were updated, I'll use `test`, but if a new feature is added, along with accompanying tests, I'll place it under `feat`. Likewise if a refactor results in tests updating, I'll use `refactor`. We have already discussed these cases a couple of comments above, [here](https://github.com/conventional-commits/conventionalcommits.org/issues/634#issuecomment-3693518196) and [here](https://github.com/conventional-commits/conventionalcommits.org/issues/634#issuecomment-3694827045), no need to repeat all over again 😉
Author
Owner

@makesnosense commented on GitHub (Jan 31, 2026):

@0x404 thank you for interesting research on the topic. Your finding that 57.7% of confusion stems from type selection closely matches my experience.

My biggest pain-point is categorizing commits that improve existing code without fixing bugs or adding features. Examples:

  • Adjusting a CSS variable color for better aesthetics
  • Changing placeholder text to be clearer
  • Reordering function parameters for better readability

The beta spec had improvement for exactly this case ("commits that improve a current implementation without adding a new feature or fixing a bug"), but it was removed. Using style creates ambiguity with code formatting, and refactor implies structural changes.

What's the current recommended approach for these incremental quality improvements?

@makesnosense commented on GitHub (Jan 31, 2026): @0x404 thank you for interesting research on the topic. Your finding that 57.7% of confusion stems from type selection closely matches my experience. My biggest pain-point is categorizing commits that improve existing code without fixing bugs or adding features. Examples: - Adjusting a CSS variable color for better aesthetics - Changing placeholder text to be clearer - Reordering function parameters for better readability The beta spec had `improvement` for exactly this case ("commits that improve a current implementation without adding a new feature or fixing a bug"), but it was removed. Using `style` creates ambiguity with code formatting, and `refactor` implies structural changes. What's the current recommended approach for these incremental quality improvements?
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: github-starred/conventionalcommits.org#219