tl-dr

python Django project git hooks tutorial for automating certain tasks and explanation about git hooks

What are git hooks

  • Git hooks are scripts/programs that Git executes before or after a particular event occurs in a Git repository. Git hooks are a built-in feature - no need to download anything. Git hooks are run locally.
  • they are placed in hooks directory to trigger actions at certain points in git’s execution. Hooks that don’t have the executable bit set are ignored.
  • They let you customize Git’s internal behavior and trigger customizable actions at key points in the development life cycle. for example I want to spell-check for commit message ( I have spellophobia ) or I want to check code for PEP8 maybe before commit or I want to run migrations after taking pull if one is available its only limited to what you can imagine and trust me it will make you fast and efficient also little lazy

How do I implement Git hooks?

The short and easy: Overwrite (or create) one of the scripts in .git/hooks and make it executable.

chmod +x .git/hooks/scipt

Git hooks for improving Python Django project Flow ( if you read it it can be used for other projects too )

pre-push

it is called after git push after it has checked the remote status, but before anything has been pushed. If this script exits with a non-zero status nothing will be pushed

we will start by creating a file in hooks folder

touch .git/hooks/pre-push

now lets edit the file and lets create a check that no one can push to master

#!/usr/bin/env bash
branch="$(git rev-parse --abberev-ref HEAD)"

if ["$branch" = "master"]; then
	echo "you cannot commit to '"$(branch)"' branch"
	exit 1
fi

now final step make it executable

chmod +x .git/hooks/pre-push

now whenever you will push to master it will fail it and throw you a message

post-merge ( runs after git pull )

we will start by creating a file in hooks called post-merge. so we can do many things after a pull request like if its a node project we can check for changes in package.json and run npm install similarly for python project we can check for requirement.txt file.

I have a new idea to not run migrations for a Django project after taking pull let it run automatically and let me forget that such a command exists.

#!/usr/bin/env bash

# lets check for changed files
changed_files = "$(git diff-tree -r --name-only --no-commit-id ORIG_HEAD HEAD)"

# function to check and run if we see file we want
check_and_run() {
	echo "$changed_files" | grep -i --quiet "$1" && eval "$2"
}

# using for python packages
check_and_run migration "python $(git rev-parse --show-toplevel)/manage.py migrate"

# using for checking packages and its update
check_and_run requirements.txt "pip install -r requirements.txt"

​ replace python and pip with the path of your virtual env

pre-commit ( this is one of the most useful hook to make sure you are not doing any mistake )

we are going to use a already available framework for this pre-commit but you can also make a file too.

  1. install pre-commit: pip install pre-commit

  2. Add pre-commit to requirements.txt (or requirements-dev.txt)

  3. Define .pre-commit-config.yaml with the hooks you want to include.

    repos:
    -   repo: https://github.com/ambv/black
        rev: stable
        hooks:
        - id: black
          language_version: python3.4
    -   repo: https://gitlab.com/pycqa/flake8
        rev: 3.7.9
        hooks:
        - id: flake8
    -   repo: https://github.com/pre-commit/pre-commit-hooks
        rev: v3.1.0  
        hooks:
        -   id: trailing-whitespace
    

    flake is used for checking python file format you can create a config file too if you want it to be more specific

    black will fix formating errors before commit

    also you can find many more plug ins at pre-commit-hooks git repo

  4. Execute pre-commit install to install git hooks in your .git/ directory.

Notes

Q: I don’t want to use hook. How to bypass it during commit ?

git commit --no-verify
# or
git commit --n

Q: I only want to run lint on diff ?

you can try a package called lint-diffs

References

https://githooks.com/ https://www.git-scm.com/doc https://github.com/aitemr/awesome-git-hooks