Skip to content

KDE sources and custom Git commit hooks

Saturday, 19 July 2025  |  Ivan Čukić

KDE’s Gitlab setup has a branch naming rule that I always forget about – branch names should start with work/ if you want the server to allow you to rebase and push rebased commits (that is, only work branches can be --force pushed to).

I had to abandon and open new PRs a few times now because of this.

Something like this is easy to check on the client side with pre-commit hooks. (a pre-push hook can also be used, but I like the check to be as early as possible)

A simple hook script that checks your branch name starts with work/YOUR_USER_NAME (I like to have the username in the branch name) is rather simple to write:

#!/bin/bash

REPO_URL=$(git remote get-url origin)
KDE_REPO_HOST="invent.kde.org"

if [[ "${REPO_URL}" == *"${KDE_REPO_HOST}"* ]]; then

    BRANCH=$(git rev-parse --abbrev-ref HEAD)
    BRANCH_REGEX="^work/$USER/.*$"

    if ! [[ $BRANCH =~ $BRANCH_REGEX ]]; then
      echo "Your commit was rejected due to its name '$BRANCH', should start with 'work/$USER'"
      exit 1
    fi

fi

It checks that the Git repository is on invent.kde.org, and if it is, it checks if the current branch follows the desired naming scheme.

KDEGitCommitHooks

But the question is where to put this script?

Saving it as .git/hooks/pre-commit in the cloned source directory would work in general, but there are two problems:

  • Manually putting it into every single cloned KDE source directory on your system would be a pain;
  • KDEGitCommitHooks, which is used by many KDE projects, will overwrite the custom pre-commit hook script you define.

The second issue is not a problem since a few hours ago. KDEGitCommitHooks (a part of the extra-cmake-modules framework) now generates a pre-commit hook that, additionally to what it used to do before, executes all the custom scripts you place in the .git/hooks/pre-commit.d/ directory.

So, if a project uses KDEGitCommitHooks you can save the aforementioned script as .git/hooks/pre-commit.d/kde-branches-should-start-with-work.sh and it should be automatically executed any time you create a new commit (after KDEGitCommitHooks updates the main pre-commit hook in your project).

For projects that do not use KDEGitCommitHooks, you will need to add a pre-commit hook that executes scripts in pre-commit.d, but more on that in a moment.

Git templates

The first problem remains – putting this into a few hundred local source directories is a pain and error-prone.

Fortunately, Git allows creating a template directory structure which will be reproduced for any repository you init or clone.

I placed my template files into ~/.git_templates_global and added these two lines to ~/.gitconfig:

[init]
    templatedir = ~/.git_templates_global

I have two KDE-related hook scripts there.

The above one is saved as ~/.git_templates_global/hooks/pre-commit.d/kde-branches-should-start-with-work.

And the second file is the default main pre-commit (~/.git_templates_global/hooks/pre-commit) script:

#!/usr/bin/env bash

# If the user has custom commit hooks defined in pre-commit.d directory,
# execute them
PRE_COMMIT_D_DIR="$(dirname "$0")/pre-commit.d/"

if [ -d "$PRE_COMMIT_D_DIR" ]; then
    for PRE_COMMIT_D_HOOK in "$PRE_COMMIT_D_DIR"/*; do
        ./"$PRE_COMMIT_D_HOOK"
        RESULT=$?
        if [ $RESULT != 0 ]; then
            echo "$PRE_COMMIT_D_HOOK returned non-zero: $RESULT, commit aborted"
            exit $RESULT
        fi
    done
fi

exit 0

It tries to run all the scripts in pre-commit.d and reports if any of them fail.

This default main pre-commit script will be used in projects that do not use KDEGitCommitHooks. In the projects that do, KDEGitCommitHooks will replace it with a script that executes everything in pre-commit.d same as this one does, but with a few extra steps.