Mit pre-commit Hooks in git verwalten

pre-commit ist ein Framework mit dem Hooks in git verwaltet werden können. Durch Hooks können zum Beispiel Tools für die Prüfung der zu commitenden Dateien durchgeführt werden.

In der Versionsverwaltung git können sogenannte Hook Scripte erstellt werden. Diese erlauben es zum Beispiel vor einem Commit bestimmte Aktionen auszuführen. So bietet es sich zum Beispiel an, noch einmal einen Syntax Check auf eine geänderte Datei zu machen, bevor sie endgültig commited wird.

Hier kommt pre-commit ins Spiel. Dabei handelt es sich um ein Framework zur Verwaltung von Commit Hooks. Das Tool selbst ist in Python geschrieben, jedoch bietet es auch Tools für viele andere Programmiersprachen und Dateiformate an. So kann zum Beispiel ein Syntaxcheck für YAML und TOML Dateien durchgeführt werden. Auch ist es möglich einen Style- und Syntaxcheck für Go, C, Python, Java, JavaScript, CSS und viele mehr durchzuführen. Die Liste der Checks ist sehr umfangreich und lässt sich auch durch eigene Checks erweitern.

Installation

Zunächst muss das Tool zum Beispiel mit dem folgenden Befehl installiert werden.

$ pip install pre-commit

Im aktuell neusten Ubuntu 20.10 ist pre-commit auch bereits als installierbares Paket enthalten. Hier kann es über den Paketmanager wie folgt installiert werden.

$ apt-get install pre-commit

Wie es scheint, wird es zukünftig auch in anderen Distributionen enthalten sein.

Die Config

Ist das Tool installiert muss eine Config-Datei mit dem Namen .pre-commit-config.yaml(Punkt am Anfang nicht vergessen) im Wurzelverzeichnis des Repository angelegt werden. Eine relativ einfache Beispiel Konfiguration erhält man mit folgendem Befehl.

$ pre-commit sample-config

Ich verwende aktuell für die meisten meiner Repositories folgende Grundkonfiguration.

repos:
  - repo: https://github.com/pre-commit/pre-commit-hooks
    rev: v3.2.0
    hooks:
      # Forbid files which have a UTF-8 byte-order marker
      - id: check-byte-order-marker
      # Check for files that would conflict in case-insensitive filesystems
      - id: check-case-conflict
      # Ensures that (non-binary) executables have a shebang
      - id: check-executables-have-shebangs
      # Check for files that contain merge conflict strings
      - id: check-merge-conflict
      # Checks for symlinks which do not point to anything
      - id: check-symlinks
      # This hook checks yaml files for parseable syntax
      - id: check-yaml
      # Detects the presence of private keys
      - id: detect-private-key
      # Ensures that a file is either empty, or ends with one newline
      - id: end-of-file-fixer
      # Replaces or checks mixed line ending
      - id: mixed-line-ending
      # This hook trims trailing whitespace
      - id: trailing-whitespace

Achtung: Nicht vergessen die Datei mit zu commiten und in der README darauf hinzuweisen.

Hook erstellen

Ist die Config-Datei angelegt, kann das Hook-Script für das Repository wie folgt angelegt werden.

$ pre-commit install

Dieser Schritt muss jeder Entwickler einmal nach dem klonen des Repository einmalig machen.

Einer für alle

Bei einem Commit werden nur die Dateien geprüft, die auch wirklich in dem Commit enthalten sind. Nicht enthaltene jedoch geänderte Dateien werden nicht geprüft. So ist es bei der initialen Einrichtung oder auch bei Continuous Integration(CI) wichtig, dass alle Dateien geprüft werden.

$ pre-commit run --all-files

Fazit

Ich selbst verwende pre-commit jetzt schon ein paar Monate bei vielen internen Repositories und beginne jetzt langsam es auch bei öffentlichen Repositories einzuführen. Sehr auffällig war, dass die Anzahl der Commits in denen extrem viele Whitespaces durch einen Editor korrigiert wurden wesentlich abgenommen hat, da jetzt ein Check dieses prüft und teilweise sogar mit einem Hinweis direkt korrigiert. Auch die Prüfungen auf Style und Type Hinting bei Python wärend der CI Builds fürten nicht mehr zu Fehlern und mussten daher auch nicht mehr nachträglich durch einen weiteren Commit berichtigt werden.

Wird ein Check zum ersten Mal ausgeführt, dauert es etwas länger, weil teilweise das entsprechende Paket, Modul, Skript oder Tool erst heruntergeladen werden muss. Anschließend laufen die Checks selbst bei großen Repositories sehr schnell durch und würden vermutlich nicht auffallen, wenn bei einem Commit auf der Kommandozeile nicht noch ein paar Log-Ausgaben kommen würden, bevor der Editor für die Commit Nachricht aufgeht.

Links

Verwandte Artikel