One important note: hooks are not part of the repository itself. Everyone can install a hook on it’s own checkout of a repository, but by default the hook is not there when you clone/checkout the repository. This avoids security problems by executing arbitrary code during
git commit, or any
Because of this implication it is common that developers install a hook from somewhere in the repository into the
.git/hooks directory. And in addition, the server side (the repository) can run the same checks during
git push, to enforce the rules.
Hooks in git work in a simple way: whatever program or script is run as the hook has to set a return code. If the return code is
0, git proceeds. If it’s not
0, git aborts the operation.
Back to the hook: the first problem is how to identify the to-be-committed files? “git diff” lists the files:
--staged: lists all files which are stated for the next commit.
--stagedis an alias for
--cached, both versions can be used.
--name-only: lists only the filenames, not the entire diff.
--diff-filter: selects what kind of files will be included in the diff.
A: Added files
C: Copied files
M: Modified files
git diff above does not select
Deleted files. A renamed file might violate naming rules, in this case you have to include this option as well. And a deleted file is about to be removed from the repository, and most likely does not need to be checked.
Let’s put this all together into a small shell script which runs as the git hook. In my example I want to enforce two things:
- No double spaces in the file
- No spaces at the end of the line
Here is the
The first part identifies the changed files. The loop runs over all changed files, and checks them for the two conditons. The
$exit_status variable is set by any error. Finally the last
if-then-else part returns an error if there is any problem in the files.