Operations 10 min read

Enforce Custom Commit Message Formats in GitLab with Server Hooks

This guide explains how to create repository‑specific and global GitLab server hooks that validate commit messages against a custom pattern, showing step‑by‑step configuration, a Go pre‑receive script, and verification commands to ensure only properly formatted commits are accepted.

Ops Development Stories
Ops Development Stories
Ops Development Stories
Enforce Custom Commit Message Formats in GitLab with Server Hooks

Introduction

Git provides server‑side hooks such as pre-receive, post-receive and update that can enforce commit policies.

These hooks can be configured per repository or globally on the GitLab server.

Creating a repository‑specific hook

Locate the repository path (e.g., /home/git/repositories/<group>/<project>.git for source installations or

/var/opt/gitlab/git-data/repositories/<group>/<project>.git

for Omnibus installations). For hashed storage, find the hashed directory under /var/opt/gitlab/git-data/repositories/@hashed/….

Select Admin Area → Projects → your project.

Find the Gitaly relative path and create a custom_hooks directory under that path.

Inside custom_hooks, add a file named pre-receive (no extension) and make it executable, owned by git.

The hook receives three parameters (old commit ID, new commit ID, ref) via stdin. If the hook exits with a non‑zero status, GitLab rejects the push and returns the error message.

Sample pre‑receive hook

The following Go program allows only commit messages that match (.*build=(yes|no).*deploy=(yes|no).*)|^Merge\ branch(.*). If the pattern does not match, it prints a GL‑HOOK‑ERR block and exits with status 1.

package main

import (
    "fmt"
    "io/ioutil"
    "os"
    "os/exec"
    "regexp"
    "strings"
)

type CommitType string

const CommitMessagePattern = `(.*build=(yes|no).*deploy=(yes|no).*)|^Merge\ branch(.*)`

const checkFailedMessage = `GL-HOOK-ERR:########################
GL-HOOK-ERR:  Commit message format check failed!
GL-HOOK-ERR:  Expected pattern:
GL-HOOK-ERR:  (.*build=(yes|no).*deploy=(yes|no).*)|^Merge\ branch(.*)
GL-HOOK-ERR:  Example: Update date.html build=no,deploy=yes
GL-HOOK-ERR:########################`

const strictMode = false

var commitMsgReg = regexp.MustCompile(CommitMessagePattern)

func main() {
    input, _ := ioutil.ReadAll(os.Stdin)
    param := strings.Fields(string(input))

    // allow branch/tag delete
    if param[1] == "0000000000000000000000000000000000000000" {
        os.Exit(0)
    }

    commitMsg := getCommitMsg(param[0], param[1])
    for _, tmpStr := range commitMsg {
        commitTypes := commitMsgReg.FindAllStringSubmatch(tmpStr, -1)
        if len(commitTypes) != 1 {
            checkFailed()
        } else {
            fmt.Println(" ")
        }
        if !strictMode {
            os.Exit(0)
        }
    }
}

func getCommitMsg(oldCommitID, commitID string) []string {
    cmd := exec.Command("git", "log", oldCommitID+".."+commitID, "--pretty=format:%s")
    cmd.Stdin = os.Stdin
    cmd.Stderr = os.Stderr
    b, err := cmd.Output()
    if err != nil {
        fmt.Print(err)
        os.Exit(1)
    }
    return strings.Split(string(b), "
")
}

func checkFailed() {
    fmt.Fprintln(os.Stderr, checkFailedMessage)
    os.Exit(1)
}

Testing the hook

After placing the script and making it executable, a push with an invalid message is rejected with the formatted error block. Amending the commit to include [build=no,deploy=no] satisfies the pattern and the push succeeds.

Creating a global hook

To apply a hook to all repositories, place it in the global server‑hook directory ( /home/git/gitlab-shell/hooks for source installs or /opt/gitlab/embedded/service/gitlab-shell/hooks for Omnibus). Configure custom_hooks_dir in the Gitaly configuration ( gitlab.rb for older versions or gitaly/config.toml for newer) to point to the desired directory.

Navigate to the global hooks directory on the GitLab server.

Create a subdirectory such as pre-receive.d, post-receive.d or update.d.

Copy your hook script into this directory and ensure it is executable and owned by git.

References:

https://docs.gitlab.com/ee/administration/server_hooks.html

https://mritd.com/2018/05/11/add-commit-message-style-check-to-your-gitlab/

Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

ci/cdGitLabcommit messageGit Hooks
Ops Development Stories
Written by

Ops Development Stories

Maintained by a like‑minded team, covering both operations and development. Topics span Linux ops, DevOps toolchain, Kubernetes containerization, monitoring, log collection, network security, and Python or Go development. Team members: Qiao Ke, wanger, Dong Ge, Su Xin, Hua Zai, Zheng Ge, Teacher Xia.

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.