Search code examples
gitgithubdevopsgithub-apigithooks

Git Commit Message Linting as a gateway and not after it was already pushed


I want to verify a specific commit message structure across organisation, I want it to not be possible to merge/push to master/main commits unless the message fits a very certain format.

Commit message is linting is covered via a simple regular expression, expected format is something like:

\[[A-Z]{2}-(\d){5,7}\]\-(.|\r|\n)*

Adding commits to master/main happens in few ways:

  1. Commit locally on master, push to remote.
  2. Commit locally on branch, merge locally to master, push to remote.
  3. Commit locally to branch, open pull request (case of github) merge PR from the github UI.

I can easily cover the case of #1 with a git-commit hook, to cover both 2 and 3, I can use a CI hook, but this will AFTER the fact e.g. at this point fixing the commit format is too late.

For 2, I can probably also add a a pre-push hook, but for 3, given that the operation happens on the server side I can't seem to find a straight forward solution that will not execute the linting process after the commit is already on the master/main branch.


Solution

  • The proper way to do this with a repository on GitHub is to use a CI job for this, possibly using a bot to do the merge if necessary. The only two places you can effectively impose any control on a repository are in a pre-receive hook and a CI system, and GitHub does not allow you to custom the pre-receive hook beyond the configuration in your repository.

    Using a hook on the user side is easy to bypass and isn't an effective control. So if you care about the commit message, then the only place you can control it is using CI. The Git FAQ explains why this is the case.

    You should protect your main branch using the GitHub settings for that and set the option “Require status checks to pass before merging.” That means that people will either need to put their changes in a PR and pass your CI checks before merging, or push the commit they want to push to the main branch to a temporary branch, then fast-forward the main branch once the CI checks pass.

    If you want the merge message to also contain a specific string, then you need to have a bot do all PR merges and be responsible for the merge, since you can't check the merge message through a CI check before it happens.

    There aren't any other effective solutions to this problem: the alternatives can either be bypassed trivially or just aren't effective. It isn't exceptionally burdensome to require people to format their commit messages in a certain way, even when working on an in-progress PR. I've worked at jobs where this was the policy and it wasn't a problem.