Commit Hygiene in Android-Projekten
Saubere Commits erklären, warum du etwas geändert hast. Sie erleichtern Debugging, Reviews und Rollbacks in Android-Projekten.
Commit Hygiene bedeutet, dass deine Git-Historie lesbar, nachvollziehbar und nützlich bleibt. In Android-Projekten hilft dir das besonders dann, wenn du Kotlin-Code, Compose-UI, Architekturentscheidungen, Tests und Release-Fixes über längere Zeit gemeinsam mit anderen pflegst.
Was ist das?
Commit Hygiene ist die Gewohnheit, Änderungen so zu speichern, dass ein anderer Entwickler den Zweck eines Commits versteht. Ein Commit ist dabei nicht nur ein Speicherpunkt. Er ist eine kleine Erklärung: Was wurde geändert, warum wurde es geändert, und welche Absicht steckt dahinter?
Das wichtigste Denkmodell lautet: Ein Commit sollte eine fachlich oder technisch zusammenhängende Einheit sein. Wenn du einen Login-Screen in Jetpack Compose baust, sollte ein Commit nicht gleichzeitig eine Datenbankmigration, eine neue Farbe im Designsystem und einen Hotfix für Push-Nachrichten enthalten. Diese Themen haben unterschiedliche Gründe, unterschiedliche Risiken und unterschiedliche Reviewer. Werden sie gemischt, wird die Historie schwerer zu lesen.
In modernem Android betrifft das viele alltägliche Bereiche. Du änderst ViewModels, Repositorys, Compose-Funktionen, Navigation, Gradle-Konfiguration, Tests oder Qualitätsregeln. Saubere Commits helfen dir, diese Änderungen später wiederzufinden. Sie helfen auch beim Zurückrollen, wenn ein Release ein Problem zeigt. Wenn ein einzelner Commit genau eine Sache ändert, kannst du ihn gezielter prüfen oder rückgängig machen.
Commit Hygiene ist deshalb kein Formalismus für Leute mit viel Git-Erfahrung. Sie ist ein praktisches Werkzeug für Qualität. Android-Dokumentation zu Tests und App-Qualität betont nicht zufällig, dass Verhalten prüfbar und zuverlässig sein soll. Deine Commit-Historie unterstützt genau das: Sie verbindet Codeänderungen mit überprüfbarer Absicht.
Wie funktioniert es?
Commit Hygiene besteht aus drei Bausteinen: atomare Commits, klare Nachrichten und eine brauchbare Historie.
Ein atomarer Commit enthält eine Änderung, die für sich sinnvoll ist. „Atomar“ heißt hier nicht „winzig“. Ein Commit darf mehrere Dateien ändern, wenn diese Dateien gemeinsam eine Aufgabe erfüllen. Beispiel: Du ergänzt eine Validierung im ViewModel, passt den UI-Zustand in Compose an und erweiterst den Unit-Test. Das ist ein guter einzelner Commit, wenn alles dieselbe Änderung beschreibt: fehlerhafte Eingaben sollen im Login-Formular korrekt behandelt werden.
Schlecht wäre dagegen ein Commit, der diese Validierung zusammen mit einer Umbenennung des Themes, einem Gradle-Update und einer Refaktorierung der Netzwerk-Schicht verbindet. Selbst wenn alles kompiliert, ist der Commit als Erklärung schwach. Ein Reviewer muss mehrere Themen gleichzeitig prüfen. Ein späteres Git Bisect liefert weniger klare Hinweise. Ein Rollback wird riskanter, weil du vielleicht nur einen Teil der Änderung zurücknehmen möchtest.
Die Commit-Nachricht ist der zweite Baustein. Sie sollte nicht nur beschreiben, welche Datei geändert wurde. Dateinamen sieht Git bereits. Wichtiger ist die Absicht. „Fix login“ ist knapp, aber oft zu ungenau. Besser ist: „Handle empty password before login request“. Noch besser wird es, wenn der Body kurz erklärt, warum die Änderung nötig ist: „The previous validation allowed an empty password to reach the repository, which created an avoidable API error state.“
Du musst nicht jede Commit-Nachricht lang machen. Für kleine Änderungen reicht eine präzise Betreffzeile. Für riskante Änderungen, Architekturentscheidungen oder Bugfixes mit Kontext lohnt sich ein kurzer Body. Denke dabei an dein zukünftiges Ich: Wenn du in drei Monaten einen Fehler in einem Compose-Screen suchst, soll die Historie dir helfen, nicht im Weg stehen.
Der dritte Baustein ist die Historie als Arbeitsmittel. Eine saubere Historie macht Code Reviews leichter, weil Reviewer Schritt für Schritt verstehen, wie du ein Problem gelöst hast. Sie unterstützt Debugging, weil du mit Git Log oder Git Bisect schneller eingrenzen kannst, welche Änderung ein Verhalten eingeführt hat. Sie unterstützt Releases, weil einzelne Bugfixes gezielt ausgewählt oder zurückgenommen werden können.
Im Alltag entstehen unsaubere Commits oft durch Zeitdruck. Du arbeitest an einem Feature, bemerkst nebenbei eine Formatierung, aktualisierst eine Dependency, reparierst einen Test und commitest alles zusammen. Das fühlt sich schnell an, erzeugt aber später Kosten. Besser ist, während der Arbeit kleine gedankliche Grenzen zu ziehen: Gehört diese Änderung noch zum aktuellen Ziel? Wenn nein, kommt sie in einen eigenen Commit oder in einen späteren Task.
In der Praxis
Stell dir vor, du arbeitest an einer Android-App mit Jetpack Compose. Das Login-Formular soll eine Fehlermeldung anzeigen, wenn die E-Mail leer ist. Beim Implementieren bemerkst du außerdem, dass ein Testname unklar ist und dass eine alte Farbe im Theme nicht mehr verwendet wird.
Eine saubere Commit-Aufteilung könnte so aussehen:
Add empty email validation to login formCover login validation with ViewModel testRename unclear login test caseRemove unused legacy theme color
Der erste Commit enthält die produktive Änderung: UI-Zustand, ViewModel-Logik oder Validierungsfunktion. Der zweite Commit enthält den passenden Test, falls du ihn bewusst getrennt halten möchtest. Oft ist es aber besser, Code und Test in einem Commit zu bündeln, wenn der Test direkt dieselbe Änderung absichert. Dann könnte der erste Commit heißen: Validate empty email in login form. Darin liegen Implementierung und Test zusammen.
Der dritte und vierte Commit sind bewusst getrennt. Die Umbenennung eines Tests und das Entfernen einer Farbe sind Aufräumarbeiten. Sie sind nicht falsch, aber sie erklären nicht die Login-Validierung. Wenn du sie in denselben Commit mischst, wird der Commit unklarer.
Eine einfache Entscheidungsregel hilft dir:
Wenn du den Commit mit einem Satz beschreiben kannst, ohne „und außerdem“ zu verwenden, ist er wahrscheinlich gut geschnitten.
Beispiel für einen guten Satz: „Dieser Commit verhindert, dass ein leerer E-Mail-Wert an die Login-Anfrage weitergegeben wird.“ Beispiel für einen problematischen Satz: „Dieser Commit validiert die E-Mail und benennt Tests um und entfernt alte Theme-Werte.“ Das zweite Beispiel zeigt, dass mehrere Ziele vermischt wurden.
Achte auch auf die Reihenfolge deiner Commits. Ein Commit sollte das Projekt in einem sinnvollen Zustand hinterlassen. In einem Android-Projekt heißt das nicht immer, dass jede Zwischenstufe releasefähig ist. Aber sie sollte möglichst kompilieren, Tests sollten nicht ohne Grund brechen, und die Änderung sollte im Review nachvollziehbar bleiben. Besonders bei Kotlin, Compose und Architekturkomponenten ist das wichtig, weil Änderungen oft über mehrere Schichten laufen: UI ruft ViewModel auf, ViewModel ruft Use Case oder Repository auf, Repository spricht mit Datenquelle oder API.
Eine typische Stolperfalle ist der Sammelcommit am Ende eines Arbeitstags. Du hast viel geschafft, aber git status zeigt zehn Dateien aus drei Themen. Statt alles blind zu committen, kannst du mit git add -p gezielt Teile auswählen. So kannst du zusammengehörige Hunks in einen Commit legen und andere Änderungen später speichern. Das kostet ein paar Minuten, spart aber Zeit im Review und beim Debugging.
Eine zweite Stolperfalle sind nichtssagende Nachrichten wie changes, fix, wip oder update. Solche Nachrichten sind während privater Arbeit manchmal verständlich, sollten aber nicht in der gemeinsamen Historie bleiben. Vor dem Push kannst du lokale Commits ordnen, umbenennen oder zusammenführen. Wichtig ist dabei: Ändere veröffentlichte Historie nur, wenn dein Team diese Arbeitsweise kennt. In gemeinsamen Branches kann nachträgliches Umschreiben andere Entwickler stören.
In Code Reviews zeigt sich Commit Hygiene sehr deutlich. Ein Reviewer kann einen gut geschnittenen Commit einzeln prüfen: zuerst die fachliche Änderung, dann die Tests, dann eine unabhängige Aufräumaktion. Dadurch sinkt die Wahrscheinlichkeit, dass ein Fehler zwischen vielen Nebensachen übersehen wird. Für Junior-Devs ist das ein guter Lernpunkt: Saubere Commits zeigen nicht nur, dass Code funktioniert. Sie zeigen, dass du deine eigene Änderung verstanden hast.
Auch beim Testen ist die Verbindung direkt. Wenn du einen Bugfix commitest, sollte der zugehörige Test entweder im selben Commit oder direkt daneben liegen. Das macht klar, welches Verhalten du absichern wolltest. Die Android-Testgrundlagen unterscheiden verschiedene Testebenen, etwa lokale Tests und instrumentierte Tests. Für Commit Hygiene ist nicht entscheidend, welche Testart du nutzt. Entscheidend ist, dass deine Historie erkennen lässt, welche Prüfung zu welcher Änderung gehört.
Bei Qualitätsarbeit gilt dasselbe. Wenn du eine App für bessere Stabilität, Performance oder Nutzererfahrung anpasst, sollte die Commit-Nachricht den Qualitätsaspekt benennen. Reduce unnecessary recomposition in profile header ist hilfreicher als optimize UI. Show offline state when profile request fails ist hilfreicher als fix error. Gute Nachrichten machen sichtbar, welches Risiko du reduziert hast.
Du kannst deine eigene Praxis mit einer kleinen Übung prüfen. Nimm einen lokalen Feature-Branch und lies nur die Commit-Betreffzeilen. Verstehst du daraus die Entwicklung der Änderung? Kannst du jeden Commit einem Ziel zuordnen? Würdest du einen einzelnen Commit zurücknehmen können, ohne andere Themen zu beschädigen? Wenn du diese Fragen nicht beantworten kannst, ist die Historie wahrscheinlich zu grob oder zu ungenau.
Fazit
Commit Hygiene ist eine einfache, aber sehr wirksame Arbeitsgewohnheit: Schneide Commits nach Absicht, schreibe Nachrichten mit Kontext und behandle die Historie als Werkzeug für Review, Debugging und Rollback. Prüfe das aktiv an deinem nächsten Android-Branch: Lies deine Commit-Liste vor dem Push, führe passende Tests aus, bitte im Code Review auch um Feedback zur Commit-Struktur und korrigiere unklare Nachrichten, solange die Historie noch lokal ist.