GitLab Merge Request Diffs bei grossen Migrationen lesbar halten
AI generated
CI/CD
.yml
GitLab · Code Review · Migration
Grosse Merge Request Diffs
lesbar halten: wie Reviewer bei Framework-Upgrades noch den Ueberblick behalten

Ein Framework-Upgrade, ein automatisiertes Refactoring oder eine Formatierungsumstellung kann in einem einzigen Merge Request zehntausende Zeilen veraendern, obwohl die eigentliche inhaltliche Aenderung nur einen Bruchteil davon ausmacht. Ohne Gegenmassnahmen ertrinkt jeder Reviewer in Rauschen und uebersieht genau die Zeile, die tatsaechlich ein Risiko traegt. Dieser Artikel zeigt konkrete Techniken, von .gitattributes fuer generierte Dateien ueber saubere Commit-Trennung bis zu GitLab-spezifischen Diff-Ansicht-Einstellungen, mit denen grosse, unvermeidbare Diffs trotzdem review-faehig bleiben.

16 Min. Lesezeit Code Review · Merge Requests GitLab · Migration

1. Das Problem grosser, unvermeidbarer Diffs

Bei einem PHP-Versionswechsel, einem Composer-Major-Upgrade oder der Einfuehrung eines neuen Code-Formatters wie PHP-CS-Fixer entstehen fast zwangslaeufig Merge Requests mit zehntausenden veraenderten Zeilen, obwohl der grosse Teil davon rein mechanisch ist, etwa veraenderte Einrueckung, umbenannte Methoden oder automatisch aktualisierte Typedeklarationen. Ein menschlicher Reviewer, der einen solchen Diff Zeile fuer Zeile durchgeht, verliert innerhalb weniger Minuten die Faehigkeit, echte inhaltliche Risiken von reinem Formatierungsrauschen zu unterscheiden.

Das eigentliche Risiko liegt dabei selten in der Masse der Aenderungen selbst, sondern in den wenigen Zeilen, die zwischen tausenden mechanischen Aenderungen versteckt tatsaechlich Verhalten aendern, etwa eine automatisch generierte, aber semantisch falsche Typkonvertierung. Genau diese Zeilen muss ein Review-Prozess zuverlaessig sichtbar machen, statt sie im allgemeinen Rauschen untergehen zu lassen.

2. .gitattributes fuer generierte Dateien konfigurieren

Git und GitLab unterstuetzen ueber die Datei .gitattributes das Attribut linguist-generated, mit dem bestimmte Dateien oder Verzeichnisse als automatisch generiert markiert werden koennen. GitLab blendet fuer so markierte Dateien den Diff in der Merge-Request-Ansicht standardmaessig eingeklappt an, sodass Reviewer sie nicht zwangslaeufig zu Gesicht bekommen, aber bei Bedarf jederzeit ausklappen koennen.

Typische Kandidaten dafuer sind automatisch generierte Interception-Klassen in generated/, kompilierte Static-Content-Artefakte oder Lock-Dateien wie composer.lock, deren Diff fuer eine inhaltliche Bewertung selten relevant ist. Wichtig ist, die Markierung bewusst und nicht pauschal zu setzen, denn eine zu breite linguist-generated-Regel kann auch tatsaechlich review-relevante Aenderungen unsichtbar machen, was das eigentliche Risiko nur verlagert statt es zu loesen.


# .gitattributes im Projekt-Root

# Automatisch generierte Magento Interception-Klassen
generated/ linguist-generated=true

# Kompilierte Static-Content-Artefakte
pub/static/ linguist-generated=true

# Lock-Dateien: als generiert markieren, Diff bleibt aber
# bei Bedarf einsehbar
composer.lock linguist-generated=true
package-lock.json linguist-generated=true

# Binaerdateien vom Diff komplett ausschliessen
*.png -diff
*.jpg -diff

3. Separate Commits: Formatierung von Logik trennen

Die wirksamste einzelne Massnahme ist, rein mechanische Aenderungen wie ein automatisiertes Reformatieren in einen eigenen, isolierten Commit zu packen, der ausschliesslich diese eine Operation enthaelt und mit keiner inhaltlichen Aenderung vermischt wird. Ein solcher Commit traegt idealerweise eine klare, standardisierte Commit-Message wie chore: apply php-cs-fixer across src/, damit sofort erkennbar ist, dass hier keine Logikaenderung zu erwarten ist.

GitLab erlaubt es, ueber die URL-Parameter eines Merge Requests gezielt einzelne Commits statt des Gesamt-Diffs zu betrachten, sodass ein Reviewer den Formatierungs-Commit bewusst ueberspringen und sich ausschliesslich auf die Commits mit inhaltlichen Aenderungen konzentrieren kann. Diese Trennung funktioniert allerdings nur, wenn die Commit-Historie im Merge Request nicht am Ende squashed wird, weshalb bei grossen Migrationen Squash-Merges meist bewusst deaktiviert werden sollten.

4. GitLab-spezifische Diff-Ansicht-Tricks fuer Reviewer

In der Merge-Request-Diff-Ansicht von GitLab lassen sich reine Whitespace-Aenderungen ueber den Schalter Show whitespace changes gezielt ausblenden, was bei einer Neuformatierung durch einen Code-Formatter oft schon den Grossteil des sichtbaren Rauschens beseitigt. Ebenso hilft der Dateipfad-Filter oben in der Diff-Ansicht, gezielt nur Aenderungen in bestimmten Verzeichnissen anzuzeigen, etwa nur app/code/Mironsoft/ statt der kompletten Vendor-Baumstruktur.

Fuer sehr grosse Merge Requests bietet GitLab zusaetzlich die Ansicht einzelner Commits ueber den Reiter Commits an, in der jeder Commit einzeln kommentiert und approved werden kann, statt den gesamten Merge Request als eine einzige, unteilbare Review-Einheit zu behandeln. Diese commit-weise Review-Praxis verteilt die kognitive Last spuerbar besser als ein einziger monolithischer Diff-Durchlauf.


# Lokal pruefen, welche Dateien ausserhalb generierter
# Verzeichnisse tatsaechlich veraendert wurden
git diff origin/main...HEAD --stat -- \
    ':!generated' ':!pub/static' ':!composer.lock'

# Nur Commits nach dem Formatierungs-Commit anzeigen
git log --oneline <format-commit-sha>..HEAD

5. Composer- und Package-Lock-Dateien im Diff sinnvoll behandeln

Lock-Dateien wie composer.lock oder package-lock.json aendern sich bei jedem Dependency-Update fast vollstaendig, weil sie Hashes, Versionsnummern und Abhaengigkeitsbaeume in einer fuer Menschen kaum lesbaren Form enthalten. Ein Reviewer sollte hier nicht versuchen, den Diff Zeile fuer Zeile zu pruefen, sondern stattdessen gezielt auf die im Merge-Request-Text genannten, tatsaechlich veraenderten Top-Level-Pakete schauen.

Praktisch bewaehrt sich, in der Merge-Request-Beschreibung explizit eine kurze Zusammenfassung der wichtigsten Versionsspruenge aufzufuehren, etwa symfony/console 6.2 auf 6.4, guzzlehttp/guzzle 7.4 auf 7.8, damit der Reviewer nicht selbst aus dem unlesbaren Lock-Datei-Diff rekonstruieren muss, was sich inhaltlich tatsaechlich geaendert hat.

6. Automatisiertes Refactoring-Tooling in eigenem Pipeline-Job isolieren

Werkzeuge wie Rector fuer automatisierte PHP-Code-Transformationen oder php-cs-fixer fuer Formatierung sollten in einem eigenen, dediziert benannten CI-Job laufen, dessen Output als separater Commit oder sogar als eigener, vorgelagerter Merge Request eingebracht wird, statt still in denselben Commit wie eine funktionale Aenderung eingemischt zu werden. So bleibt jederzeit nachvollziehbar, welcher Teil einer Codebasis-Aenderung maschinell und welcher manuell entstanden ist.

Ein bewaehrtes Muster ist ein eigener geplanter Pipeline-Job, der Rector regelmaessig auf einem eigenen Branch ausfuehrt und automatisch einen Merge Request mit ausschliesslich mechanischen Aenderungen eroeffnet. Dieser MR laesst sich dann mit deutlich geringerem Reviewaufwand pruefen und mergen, bevor die naechste inhaltliche Migration darauf aufbaut, statt beides in einem einzigen riesigen Merge Request zu vermischen.


rector_autofix:
  stage: maintenance
  script:
    - vendor/bin/rector process app/code/Mironsoft --dry-run=false
    - git config user.email "ci@mironsoft.de"
    - git config user.name "Rector Bot"
    - git checkout -b "rector/auto-$(date +%Y%m%d)"
    - git commit -am "chore: automated rector refactoring"
    - git push origin "rector/auto-$(date +%Y%m%d)"
  rules:
    - if: '$CI_PIPELINE_SOURCE == "schedule"'

7. Merge Request Beschreibungen als Review-Leitfaden fuer grosse Migrationen

Bei einer grossen Migration lohnt es sich, in der Merge-Request-Beschreibung nicht nur zu beschreiben, was geaendert wurde, sondern explizit anzugeben, welche Dateien oder Verzeichnisse ein Reviewer wirklich pruefen muss und welche sicher uebersprungen werden koennen. Eine GitLab-Merge-Request-Vorlage mit festen Abschnitten wie Manuell zu pruefende Aenderungen und Rein mechanische Aenderungen, kein Review noetig gibt jedem Reviewer sofort Orientierung.

Ergaenzend hilft ein Link auf eine kurze Review-Anleitung, etwa in der Projekt-Wiki, die beschreibt, in welcher Reihenfolge die Commits sinnvoll durchzugehen sind und welche automatisierten Checks, etwa PHPStan oder Rector-Dry-Run, bereits vorab in der Pipeline gelaufen sind und deshalb nicht nochmal manuell nachvollzogen werden muessen.

8. Den Review-Prozess selbst an grosse Migrationen anpassen

Statt eine gesamte Migration in einem einzigen Merge Request zu buendeln, bewaehrt sich in der Praxis meist eine Kette mehrerer kleinerer, aufeinander aufbauender Merge Requests, jeder mit einem klar abgegrenzten Umfang, etwa erst das Composer-Upgrade, dann die notwendigen Code-Anpassungen fuer geaenderte Signaturen, dann die eigentliche neue Funktionalitaet. GitLab unterstuetzt das ueber Merge-Request-Ketten mit expliziten Target-Branches statt eines einzigen main-Branches als Ziel.

Fuer Migrationen, die sich zeitlich nicht sauber aufteilen lassen, hilft der GitLab-Draft-Status, um klarzumachen, dass ein Merge Request noch nicht review-bereit ist, waehrend parallel bereits erste Kommentare zu einzelnen Commits gesammelt werden koennen. Das verhindert, dass ein Reviewer einen unfertigen, riesigen Diff vorschnell komplett durchgeht, obwohl sich einzelne Teile davon noch aendern werden.

9. Checkliste fuer die naechste grosse Migration

Vor dem Eroeffnen eines grossen Migrations-Merge-Requests lohnt sich eine kurze Selbstpruefung: Sind generierte Dateien in .gitattributes markiert, ist die Formatierung in einem eigenen Commit isoliert, enthaelt die Beschreibung eine klare Anleitung fuer den Reviewer, und ist die Commit-Historie so aufgebaut, dass sie beim Merge nicht versehentlich squashed wird.

Die folgende Tabelle fasst die wichtigsten Techniken noch einmal zusammen und ordnet sie danach ein, wie viel Aufwand die Einrichtung kostet und wie gross der Nutzen fuer die Review-Qualitaet typischerweise ausfaellt.

Technik Einrichtungsaufwand Nutzen fuer Reviewer Wann besonders sinnvoll
.gitattributes linguist-generated Gering, einmalig Hoch, Diff automatisch eingeklappt Generierte Verzeichnisse, Static Content
Separate Commits fuer Formatierung Mittel, Disziplin noetig Sehr hoch Framework-Upgrades, Formatter-Einfuehrung
GitLab Whitespace-Filter Keine Mittel Reine Einrueckungsaenderungen
Kette kleinerer Merge Requests Hoch, mehr Planung Sehr hoch Zeitlich planbare Migrationen
Eigener Rector-Pipeline-Job Hoch, einmalig Hoch, langfristig Wiederkehrende automatisierte Refactorings

Mironsoft

CI/CD-Pipelines, Zero-Downtime-Deployments und Release-Automatisierung

Deployments, die ohne Ausfallzeit und ohne Nervenkitzel laufen?

Wir prüfen bestehende GitLab-Pipelines auf fragile Deployment-Schritte und fehlende Absicherung und bauen daraus einen Release-Prozess mit Zero-Downtime-Deployments, automatisierten Checks und einem Rollback, dem ihr im Ernstfall vertrauen könnt.

Pipeline-Review

Bestehende .gitlab-ci.yml auf Fragilität, fehlende Stages und Sicherheitslücken prüfen.

Zero-Downtime-Deployment

Symlink-Releases, Health-Checks und Rollback-Strategien für Magento-Shops aufbauen.

CI/CD-Automatisierung

Tests, Security-Scans und Deployments zu einer zuverlässigen Pipeline verbinden.

10. Zusammenfassung

Grosse Diffs lesbar halten: Das Wichtigste auf einen Blick

Kernproblem

Zehntausende mechanische Zeilenaenderungen verdecken die wenigen Zeilen, die tatsaechlich Verhalten aendern.

Wichtigster Hebel

Rein mechanische Aenderungen in eigene Commits isolieren, niemals mit inhaltlichen Aenderungen vermischen.

GitLab-Werkzeuge

.gitattributes mit linguist-generated, Whitespace-Filter und commit-weise Review ueber den Commits-Reiter.

Prozess-Ebene

Migrationen in mehrere kleinere Merge Requests aufteilen statt eine unteilbare Review-Einheit zu erzwingen.

11. FAQ: Grosse Diffs lesbar halten: Das Wichtigste auf einen Blick

1Was bewirkt das linguist-generated Attribut in .gitattributes konkret?
Dateien mit diesem Attribut werden in der GitLab-Merge-Request-Ansicht standardmaessig eingeklappt dargestellt, koennen aber bei Bedarf jederzeit manuell ausgeklappt werden. Das reduziert sichtbares Rauschen, ohne die Information komplett zu verstecken.
2Warum sollte ich Formatierung und Logikaenderung nie im selben Commit mischen?
Vermischte Commits lassen sich weder einzeln nachvollziehen noch gezielt ueberspringen. Ein Reviewer kann dann nicht mehr unterscheiden, welche Zeile rein mechanisch und welche inhaltlich riskant ist, ohne den gesamten Commit im Detail zu lesen.
3Funktioniert die commit-weise Review auch nach einem Squash-Merge noch?
Nein, nach einem Squash gehen die einzelnen Commit-Grenzen im Zielbranch verloren. Fuer grosse Migrationen sollte Squash-Merge deshalb bewusst deaktiviert oder zumindest fuer diesen einen Merge Request ausgeschaltet werden.
4Wie blende ich reine Whitespace-Aenderungen in der GitLab Diff-Ansicht aus?
Ueber den Schalter Show whitespace changes oberhalb des Diffs in der Merge-Request-Ansicht. Das entfernt Aenderungen, die nur aus veraenderter Einrueckung oder Leerzeichen bestehen, aus der sichtbaren Darstellung.
5Sollte composer.lock als linguist-generated markiert werden?
Ja, sinnvollerweise schon, weil der Diff fuer Menschen kaum lesbar ist. Die eigentlich relevante Information, welche Top-Level-Pakete sich geaendert haben, gehoert stattdessen explizit in die Merge-Request-Beschreibung.
6Wie strukturiere ich eine Merge Request Kette fuer eine grosse Migration?
Am besten mit klar abgegrenztem Umfang pro Merge Request, etwa erst das Dependency-Upgrade, dann notwendige Signatur-Anpassungen, dann die neue Funktionalitaet, jeweils mit dem vorherigen Merge Request als Ziel-Branch statt direkt main.
7Lohnt sich ein eigener Pipeline-Job fuer automatisiertes Refactoring wirklich?
Bei wiederkehrenden Refactorings ja, weil dadurch mechanische Aenderungen konsequent von inhaltlichen getrennt bleiben. Fuer einmalige Migrationen reicht oft ein manuell ausgefuehrter, dedizierter Commit.
8Was gehoert in eine gute Merge Request Beschreibung fuer grosse Migrationen?
Eine kurze Zusammenfassung der wichtigsten Versionsspruenge, eine klare Angabe, welche Dateien tatsaechlich manuell geprueft werden muessen, und ein Hinweis auf bereits automatisiert gelaufene Checks wie PHPStan oder Rector-Dry-Run.
9Kann ich in GitLab einzelne Dateien komplett vom Diff ausschliessen?
Nicht direkt vom Anzeigen, aber ueber -diff in .gitattributes laesst sich fuer bestimmte Dateitypen wie Binaerdateien verhindern, dass Git ueberhaupt versucht, einen textuellen Diff zu berechnen.
10Wie gehe ich mit einem bereits eroeffneten, unuebersichtlich grossen Merge Request um?
Nachtraeglich in kleinere, aufeinander aufbauende Merge Requests aufzuteilen ist aufwendig, aber oft sinnvoller, als zu versuchen, den riesigen Diff wie er ist zu reviewen. Alternativ hilft zumindest eine nachtraegliche, klare Review-Anleitung in der Beschreibung.