Best Practices mit Git

11:30 Kaffeeküche, Nürnberg

M. und Michael, ein weiteres Mitglied des Scrum-Teams, unterhalten sich gerade über die Resultate aus der letzten Retrospektive. Ein Punkt, der mehreren Teammitgliedern aufgefallen war, ist die relative Häufung von Flüchen und Kraftausdrücken in Commit Messages. Das Projekt ist schon weit fortgeschritten und alle Entwickler stehen unter Druck, also ein scheinbar typisches Phänomen [2]. M. verspricht Michael, sich eine Lösung einfallen zu lassen, denn aus rein professionellen Gesichtspunkten ist die Situation nicht tragbar.

Zurück an seinem Arbeitsplatz überprüft M. die Liste an Commits der letzten Zeit und wird tatsächlich sofort fündig:

git log --oneline
1334204 Provide some better comment shit for this crappy class
[.]

Natürlich könnte M. versuchen, das Problem organisatorisch zu lösen, dieser Ansatz erscheint aber wenig erfolgversprechend. Viel besser scheint eine technische Lösung. Git bietet für derartige Fälle so genannte Hooks. Das sind Skripte, die bei bestimmten Ereignissen (wie beispielsweise Commits, Rebases oder Pushes) ausgeführt werden. Die möglichen Hook-Skripte befinden sich im Git-Repository unter .git/hooks.

applypatch-msg.sample  post-update.sample         pre-rebase.sample
commit-msg.sample      pre-applypatch.sample      update.sample
post-commit.sample     pre-commit.sample
post-receive.sample    prepare-commit-msg.sample

Hook-Skripte können sowohl client- als auch serverseitig aktiviert werden. Um ein bestimmtes Skript zu aktivieren, muss lediglich das .sample aus dem Dateinamen entfernt werden.

Für M.s Problem bietet sich die Aktivierung des update-Hook im zentralen Repository an. Dieser Hook wird immer dann aktiviert, wenn ein Entwickler versucht, seine lokalen Änderungen mit git push in das zentrale Repository einzuchecken.

M. (dessen bash-Kenntnisse in etwa so rudimentär sind wie die des Autors) investiert einige Minuten und schreibt ein entsprechendes bash-Skript, welches die Commit Message auf Kraftausdrücke (aktuell die Ausdrücke shit, damn, ugly und crap) prüft:

#!/bin/bash
commit_msg=$(git log --pretty=%s $2..$3)
#list of expressions to deny
for string in shit damn ugly crap
do
 if [[ $commit_msg == *$string* ]]
  then
    echo "Keine Kraftausdrücke!!";
    exit 1;
  fi
done
exit 0;

Das Update-Hook wird von Git mit folgenden Parametern aufgerufen: refname sha1-old sha1-new. Interessant für M. sind die Parameter sha1-old und sha1-new, was den Hash-Werten des Commit-Objektes vor- bzw. nach dem Commit entspricht. Über folgende Expression kann M. die Commit Message auslesen.

commit_msg=$(git log --pretty=%s $2..$3)

Git akzeptiert einen Push nur dann, wenn das Update-Skript einen Wert zurückliefert, der nicht 1 ist. Zuletzt benennt M. das Update-Skript von update.sample in update um, um das Skript zu aktivieren.

Um das Skript zu testen erstellt M. einen Dummy-Commit mit folgender Commit Message „A crappy Dummy Commit“ und versucht diesen anschließend zu pushen (Listing 3).

Listing 3
git log --oneline
eef9feb A crappy Dummy Commit
1334204 Provide some better comment shit for this crappy class
#push to central repository
git push origin master
remote: Keine Kraftausdrücke!!
remote: error: hook declined to update refs/heads/master
To ../central_git_repo/
 ! [remote rejected] master -> master (hook declined)
error: failed to push some refs to '../central_git_repo/'

Das Skript scheint zu funktionieren, das zentrale Repository verbietet den Commit. M. ist stolz, denn damit ist ein weiterer Schritt in Richtung „sauberer“ Arbeit getan.

Vielleicht noch ein kleiner Hinweis. Git Hooks eignen sich auch ideal, um lokale Entwicklungsrichtlinien zu erzwingen. Der Phantasie eines Teams sind hier keine Grenzen gesetzt, beispielsweise könnte ein kompletter Build des Projektes angestoßen werden und ein Commit nur erlaubt, wenn dieser erfolgreich war. Eine Art minimalistisches Continuous-Integration-System. Ein anderes interessantes Beispiel wäre die automatische Verlinkung von Commits mit Jira-Issues [3].

17:00 Auf dem Weg zum Hauptbahnhof, Nürnberg

M. befindet sich jetzt auf dem Weg in den verdienten Feierabend. Zuvor hat er jedoch noch die Fahrt nach München vor sich. Hierfür hat sich M. einen weiteren wichtigen Produktions-Bug mitgenommen, der unbedingt morgen in das Produktivsystem geliefert werden muss. Als sich der Zug in Bewegung setzt ist M. bereits dabei, den Bug zu fixen.

Noch ein letzter Hinweis des Autors: Die Repositories von allen beteiligten Teammitgliedern befinden sich auf der Java-Magazin-Webseite, sodass die einzelnen Schritte sehr einfach nachvollzogen werden können. Ich hoffe, das Lesen des Artikels hat Ihnen genauso viel Freude gemacht wie mir das Schreiben und dass der Artikel Ihren Erwartungen entspricht. Ich freue mich über Fragen, Anregungen und konstruktive Kritik.

Martin Dilger ist Senior Consultant bei der PENTASYS AG in München und beschäftigt sich intensiv mit den Themen Git, Wicket, OSGi, Spring und Scala. Er bloggt regelmäßig unter http://splitshade.wordpress.com
Kommentare

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht.