KDE sources and custom Git commit hooks
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 custompre-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.