pre-commit checks are like prenups. They run before you commit, get the dirty stuff out of the way, and may even save your relationship(s) in the long run. The difference is that pre-commit checks are written by programmers and not lawyers, so they are a lot easier to read and implement.
There are several types of pre-commit checks that can be run. Some common features you could chose are:
- git sanity checks (no huge files, no bad merge lines, etc…)
- code style enforcement
- whitespace fixes
- python specific checks
Why pre-commit?
Just as you should do a quick check in the mirror before heading out, pre-commits are a quick reflection of your code before making it public. They quickly check everything you’re about to add to git
to make sure it’s copasetic. Many even automatically fix common issues for you.
Basically pre-commits make sure your code’s tee-shirt isn’t on inside out.
How to pre-commit
There are three basic steps to get pre-commit working with your code repo.
- Install the pre-commit tool onto your system
- Add a pre-commit configuration file to your repo
- Install the git hook for the repo
1. Install pre-commit
There are several different official ways to install pre-commit. I personally do not like packages polluting my global python site-packages. Instead, I install it with user level only privileges. Then I make sure its install path is added to the system path.
pip install pre-commit --user
You will receive a warning that the script installation location is not on the system path. (Unless you have done this before, and then you can skip the next part.)
If you really don’t care and are very good about using isolated virtual environment, you can just install it globally with pip install pre-commit
without the --user
flag and skip the next part.
Windows
Installing collected packages: pre-commit WARNING: The scripts pre-commit-validate-config.exe, pre-commit-validate-manifest.exe and pre-commit.exe are installed in 'C:\Users\Chris\AppData\Roaming\Python\Python39\Scripts' which is not on PATH.
The above warning is what I received while installing this on windows. So I coped that path C:\Users\Chris\AppData\Roaming\Python\Python39\Scripts
to my clipboard and then went through the following process to add it to my system path.
First, search for “edit system” on the window search bar and click the highlighted link.
Second, click on the “Environment Variables…” button at the bottom.
Third, in the bottom section under “System variables” click on “Path” and hit “Edit…”
Finally on the new window hit “New” in the top right and add the path previously copied to the clipboard. Then Hit Ok on all the windows to close them.
You will have to restart any cmd
sessions you have opened. When you do, you should be able to run pre-commit
just fine.
Linux
It’s a bit simpler to add the custom install location to the system path on linux.
INSTALL_PATH=/home/james/.local/bin # Change to the path printed in your warning echo "export PATH=\"${INSTALL_PATH}:\$PATH\"" >> ~/.bashrc source ~/.bashrc
2. The config file
In your repo, you will need to create a file named .pre-commit-config.yaml
and chose which checks to add for your code. This is a config file that I use (with opinionated formatters and mypy removed). You can find the full list of built-in supported checks at the pre-commit github repo.
# .pre-commit-config.yaml repos: - repo: https://github.com/pre-commit/pre-commit-hooks rev: v4.3.0 hooks: # Identify invalid files - id: check-ast - id: check-yaml - id: check-json - id: check-toml # git checks - id: check-merge-conflict - id: check-added-large-files - id: detect-private-key - id: check-case-conflict # Python checks - id: check-docstring-first - id: debug-statements - id: requirements-txt-fixer - id: fix-encoding-pragma - id: fix-byte-order-marker # General quality checks - id: mixed-line-ending - id: trailing-whitespace args: [--markdown-linebreak-ext=md] - id: check-executables-have-shebangs - id: end-of-file-fixer
Personally I also always use black
code formatter. It is not part of the standard checks, but is still easy to add.
repos: - repo: https://github.com/pre-commit/pre-commit-hooks rev: v4.3.0 hooks: # ... # Add at same level as the first pre-commit-hooks repo - repo: https://github.com/psf/black rev: 22.1.0 hooks: - id: black
3. Adding the pre-commit hook to git
Go into the repo with the config file at it’s root, and simply type:
pre-commit install
The first time you add it you will also want to update it to latest version, then run it on all the files in the repo to shore them all up (usually it only runs on the changed files).
pre-commit autoupdate pre-commit run --all-files
It will take a few minutes to install the virtual env for running these checks, but will be much faster after the first time. It should look something like:
pre-commit run --all-files [INFO] Initializing environment for https://github.com/pre-commit/pre-commit-hooks. [INFO] Initializing environment for https://github.com/psf/black. [INFO] Installing environment for https://github.com/pre-commit/pre-commit-hooks. [INFO] Once installed this environment will be reused. [INFO] This may take a few minutes... [INFO] Installing environment for https://github.com/psf/black. [INFO] Once installed this environment will be reused. [INFO] This may take a few minutes... Check python ast.........................................................Passed Check Yaml...............................................................Passed Check JSON...........................................(no files to check)Skipped Check Toml...............................................................Passed Check for merge conflicts................................................Passed Check for added large files..............................................Passed Detect Private Key.......................................................Passed Check for case conflicts.................................................Passed Check docstring is first.................................................Passed Debug Statements (Python)................................................Passed Fix requirements.txt.....................................................Passed Fix python encoding pragma...............................................Passed fix UTF-8 byte order marker..............................................Passed Mixed line ending........................................................Passed Trim Trailing Whitespace.................................................Failed - hook id: trailing-whitespace - exit code: 1 - files were modified by this hook Fixing README.md Fixing docs/README.md Fixing docs/build-licenses.txt Check that executables have shebangs.....................................Passed Fix End of Files.........................................................Failed - hook id: end-of-file-fixer - exit code: 1 - files were modified by this hook Fixing docs/build-licenses.txt Fixing .pre-commit-config.yaml black....................................................................Passed
4. Sit back and relax
Congrats, you are now totally almost protected from the most common silly mistakes you used to make. You now have the opportunity to make completely new mistakes you wouldn’t have thought of before!