Repository: compilerla/conventional-pre-commit

Issue:
Support --allow-merge-commits flag to skip validation of merge commits
Hi!
Currently, conventional-pre-commit fails on merge commits because their commit messages (like Merge branch 'master' into feature/my-branch) do not follow the Conventional Commits standard.

It would be very useful to have an option like --allow-merge-commits to skip validation of merge commits automatically.

Use Case:
- Developers merging master or other branches into feature branches.
- CI pipelines where automatic merges happen.
- Keeping history clean without manually editing merge commit messages.

Proposal:
- Add a flag --allow-merge-commits.
- If this flag is set, conventional-pre-commit should skip validation for commits that start with Merge ....
- Ideally, detection could be done by checking if the commit message starts with Merge or using Git’s metadata.

Why it’s important:
- Merge commits are common in many workflows.
- Developers are forced to rewrite merge commit messages manually, which can break Git history clarity or cause frustration.

Hints from issue comments:
@thekaveman: Thanks for the detailed write-up @bagowix.

What version of `conventional-pre-commit` are you using? Since the latest version ([`v4.0.0`, December 2024](https://github.com/compilerla/conventional-pre-commit/releases/tag/v4.0.0)) the default behavior is to skip checking merge commits, meaning there is no need for a flag.

The `--strict` flag can be used to _disallow_ merge commits and e.g. `fixup!` style commits. But otherwise, these are allowed by default.@bagowix: Hi, thanks again for the quick response!

I’m actually using conventional-pre-commit version v4.0.0, but I’m still consistently encountering this issue.
When I perform a regular merge (like merging master into my feature branch), the pre-commit hook blocks the commit with an error about a bad commit message, even though it’s a standard merge message.

```
  - repo: https://github.com/compilerla/conventional-pre-commit
    rev: v4.0.0
    hooks:
      - id: conventional-pre-commit
        stages: [commit-msg]
        args: [--verbose]
```

Here’s an example of the error I get:

```
Conventional Commit......................................................Failed
- hook id: conventional-pre-commit
- exit code: 1
[Bad commit message] >> Merge remote-tracking branch 'refs/remotes/origin/master' into feat/*****
Your commit message does not follow Conventional Commits formatting
https://www.conventionalcommits.org/
Conventional Commit messages follow a pattern like:
    type(scope): subject
    extended body
Please correct the following errors:
  - Expected value for type from: build, chore, ci, docs, feat, fix, perf, refactor, revert, style, test
Run:
    git commit --edit --file=.git/COMMIT_EDITMSG
to edit the commit message and retry the commit.
Not committing merge; use 'git commit' to complete the merge.
```

It seems like merge commits are still being validated.
Maybe there’s a configuration or usage detail I’m missing?

Would appreciate any advice or suggestions! Thanks again!@thekaveman: Ah, thank you for sharing the error output, that was helpful! I think I see the issue:

```log
[Bad commit message] >> Merge remote-tracking branch 'refs/remotes/origin/master' into feat/*****
```

We check for [commit messages that start with `"Merge branch"`](https://github.com/compilerla/conventional-pre-commit/blob/main/conventional_pre_commit/format.py#L77), which of course doesn't work for your use-case of merging a remote branch. Sorry for this oversight!

I would happily accept a PR (with tests) to fix this. @bagowix: I’d be happy to jump in and fix this!@thekaveman: Thanks again @bagowix! This fix is now released in `v4.1.0`:

* https://github.com/compilerla/conventional-pre-commit/releases/tag/v4.1.0
* https://pypi.org/project/conventional-pre-commit/4.1.0/@bagowix: Thanks a lot for the quick review and merge! Appreciate the responsiveness - happy to contribute!

Solution patch:
diff --git a/conventional_pre_commit/format.py b/conventional_pre_commit/format.py
index 3eab9e3..e4023a2 100644
--- a/conventional_pre_commit/format.py
+++ b/conventional_pre_commit/format.py
@@ -70,11 +70,16 @@ class Commit:
 
     def is_merge(self, commit_msg: str = ""):
         """
-        Returns True if input starts with "Merge branch"
-        See the documentation, please https://git-scm.com/docs/git-merge.
+        Returns True if the commit message indicates a merge commit.
+        Matches messages that start with "Merge", including:
+        - Merge branch ...
+        - Merge pull request ...
+        - Merge remote-tracking branch ...
+        - Merge tag ...
+        See https://git-scm.com/docs/git-merge.
         """
         commit_msg = self.clean(commit_msg)
-        return commit_msg.lower().startswith("merge branch ")
+        return bool(re.match(r"^merge\b", commit_msg.lower()))
 
 
 class ConventionalCommit(Commit):


Test patch:
diff --git a/tests/test_format.py b/tests/test_format.py
index 6ad99eb..a46005b 100644
--- a/tests/test_format.py
+++ b/tests/test_format.py
@@ -397,8 +397,16 @@ def test_has_autosquash_prefix(commit, input, expected_result):
     [
         ("Merge branch '2.x.x' into '1.x.x'", True),
         ("merge branch 'dev' into 'main'", True),
+        ("Merge remote-tracking branch 'origin/master'", True),
+        ("Merge pull request #123 from user/feature-branch", True),
+        ("Merge tag 'v1.2.3' into main", True),
+        ("Merge origin/master into develop", True),
+        ("Merge refs/heads/main into develop", True),
         ("nope not a merge commit", False),
         ("type: subject", False),
+        ("fix: merge bug in auth logic", False),
+        ("chore: merged upstream changes", False),
+        ("MergeSort implemented and tested", False),
     ],
 )
 def test_is_merge_commit(input, expected_result):