GitLab: Pre-receive hooks
In GitLab, adding a pre-receive hook is not as straightforward as on a self-hosted Git server because GitLab does not provide direct access to the Git repository on the server. However, you can still use custom Git hooks by leveraging the GitLab’s server hooks feature available for self-managed GitLab instances.
Here’s how you can add a pre-receive hook in GitLab:
1. Ensure You’re Using a Self-Managed GitLab Instance
- This method is only available if you’re running a self-managed GitLab instance (not for GitLab.com or cloud-hosted GitLab).
- You need administrator access to the GitLab server to configure custom hooks.
2. Locate the GitLab Hooks Directory
GitLab has a centralized hooks directory where you can place hooks for all repositories.
The default location for this directory is:
/opt/gitlab/embedded/service/gitlab-shell/hooks
The hooks you place in this directory will be applied to all repositories managed by GitLab.
3. Create the Pre-Receive Hook
Inside the hooks directory, create a pre-receive
hook. This script will be executed every time a push is made to the GitLab server.
cd /opt/gitlab/embedded/service/gitlab-shell/hooks
sudo touch pre-receive
sudo chmod +x pre-receive
Open the pre-receive
file using your preferred editor:
sudo nano pre-receive
Add the necessary logic to the pre-receive hook script. For example, here’s a basic script that prevents force pushes to the main
branch:
#!/bin/sh
# Prevent force pushes to the main branch
while read oldrev newrev refname
do
if [ "$refname" = "refs/heads/main" ]; then
# Ensure it's not a force push
if ! git merge-base --is-ancestor $oldrev $newrev; then
echo "Force pushing to the main branch is not allowed!"
exit 1
fi
fi
done
exit 0
4. Make the Hook Executable
Make sure the hook script is executable:
sudo chmod +x /opt/gitlab/embedded/service/gitlab-shell/hooks/pre-receive
5. Restart GitLab (Optional)
In most cases, GitLab will automatically pick up changes to hooks, but you may want to restart GitLab to ensure everything is loaded correctly:
sudo gitlab-ctl restart
6. Testing the Hook
After setting up the pre-receive hook, you can test it by making a push to the repository. The pre-receive hook will run every time a user pushes to any repository on the GitLab instance.
For example, try force-pushing to the main
branch from a client:
git push --force origin main
If the hook is configured properly, the push should be blocked with the message Force pushing to the main branch is not allowed!
.
Advanced: Repository-Specific Hooks
If you want a pre-receive hook for specific repositories rather than all repositories on your GitLab instance, you can:
-
Find the repository’s storage location: GitLab stores each repository as a bare Git repository on the server. You can find the repository path from the admin area or by checking the GitLab configuration files.
-
Add hooks to that specific repository: After locating the repository’s
.git/hooks
directory, you can add the pre-receive hook there. Note that this is not recommended because GitLab periodically overwrites hooks in individual repositories, so using the global hooks directory is the preferred method.
GitLab Custom Hooks Using GitLab API or GitLab CI
If you are not on a self-managed GitLab instance or do not have server access, you can achieve similar results using GitLab CI or GitLab’s API:
- GitLab CI: Instead of a pre-receive hook, you can create a GitLab CI pipeline that checks certain conditions on commits or branches (e.g., code style, commit messages, etc.), and fails the build if necessary.
- GitLab API: Use the GitLab API to automate repository actions, such as preventing certain pushes or enforcing rules through bots or external scripts.
Summary:
- Pre-receive hooks in GitLab are available only for self-managed GitLab instances.
- Place the hook script in the global hooks directory (
/opt/gitlab/embedded/service/gitlab-shell/hooks
). - Write your pre-receive hook logic in a script and make it executable.
- For more granular control, use GitLab CI or the GitLab API if server access is not available.
This method ensures that all repositories on your GitLab server are governed by the pre-receive hook.