A git hook is a script that Git executes before or after an event such as committing, pushing, or receiving code. Git hooks are a built-in feature of Git that allows you to perform custom actions at specific points in the Git workflow. They are stored in the .git/hooks
directory in a Git repository, and are typically named according to the event they are associated with.
There are several types of git hooks that can be used, including:
pre-commit
: runs before you commit your changespost-commit
: runs after you commit your changespre-push
: runs before you push your changes to a remote repositorypost-push
: runs after you push your changes to a remote repository
Git hooks are usually written in a shell script, but you can use any executable program as a git hook. They can be used for tasks such as checking for code formatting issues, running tests, or deploying code to a staging environment.
To use a git hook, you must create a script with the desired behavior and save it in the appropriate hook directory in your repository. Git will automatically execute the script at the appropriate time in the workflow.
For instance to apply clang-format on files before committing, create a file and name it “pre-commit
1 2 3 4 5 6 7 8 9 10 11 12 |
#!/bin/sh for FILE in $(git diff --cached --name-only) do case "${FILE: -4}" in ".cpp"|".hpp"|".cc"|".hh"|".h"|".c") #echo yes;; #echo "${FILE: -4}";; clang-format -i $FILE;; *) #echo no changes needed to apply on the file;; :;; esac done |
a better script:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 |
# Regexp for grep to only choose some file extensions for formatting exts="\.\(cpp\|hpp\|cc\|hh\|c\|h\)$" # The formatter to use formatter=`clang-format.exe` # Check availability of the formatter if [ -z "$formatter" ] then 1>&2 echo "$formatter not found. Pre-commit formatting will not be done." exit 0 fi # Format staged files for file in `git diff --cached --name-only --diff-filter=ACMR | grep $exts` do echo "Formatting $file" # Get the file from index git show ":$file" > "$file.tmp" # Format it "$formatter" -i "$file.tmp" # Create a blob object from the formatted file hash=`git hash-object -w "$file.tmp"` # Add it back to index git update-index --add --cacheinfo 100644 "$hash" "$file" # Formatting original file # echo "Formatting original file "."$file" "$formatter" -i "$file" # Remove the tmp file rm "$file.tmp" done # If no files left in index after formatting - fail ret=0 if [ ! "`git diff --cached --name-only`" ]; then 1>&2 echo "No files left after formatting" exit 1 fi |
Move your hooks to a hooks
tracked directory in your repository. Then, configure each instance of the repository to use the tracked hooks
instead of $GIT_DIR/hooks
:
1 |
git config core.hooksPath hooks |