Dateiattribute
.gitattributes ist die wertvollste Datei in git, die fast niemand schreibt.
Damit bringt ein Repository git seine eigenen Inhalte bei: welche Dateien
binär sind, welche aneinandergehängt statt in Konflikt geführt werden sollen,
welche nie in einem Archiv landen, welche Zeilenenden alle bekommen.
Der entscheidende Punkt: sie wird committet. Eine Regel, die du hinzufügst, behebt das Problem für alle, die klonen, auf jedem Betriebssystem, für immer — anders als eine Einstellung in deiner eigenen Config, die es nur für dich behebt und deine Kolleginnen und Kollegen auf die harte Tour draufkommen lässt.
⌘K → Dateiattribute.

Was die Regeln bewirken
| Attribut | Behebt |
|---|---|
text=auto eol=lf |
Zeilenenden, die davon abhängen, wer die Datei ausgecheckt hat |
binary |
Dass git versucht, ein PSD, ein DOCX oder ein kompiliertes Asset zu diffen oder drei-Wege zu mergen |
merge=union |
Ein Changelog, an das alle anhängen und an dem alle in Konflikt geraten |
-merge |
Dateien, bei denen ein Drei-Wege-Merge Unsinn produziert — Lockfiles, generierter Code |
export-ignore |
CI-Konfiguration und Fixtures, die in einem Release-Tarball mitgeliefert werden |
diff=<driver> |
Unlesbare Diffs für Formate, die sehr wohl lesbar sind, wenn man einen Konverter hat |
filter=lfs |
Große Dateien, gespeichert über LFS |
linguist-vendored |
Fremdcode, der in der Sprachstatistik als deiner gezählt wird |
binary ist die Kurzform für -diff -merge -text, also drei Antworten auf
"hör auf, über diese Datei zu raten" in einem Wort.
Bearbeiten
Die Vorlagen füllen ein Muster und dessen Attribute aus; passe das Muster vor
dem Hinzufügen an — CHANGELOG.md ist ein Vorschlag, keine Aussage über dein
Projekt.
Änderungen sind chirurgisch. Fügst du eine Regel für ein Muster hinzu, das schon eine hat, wird diese Zeile an ihrer Stelle umgeschrieben, statt eine zweite Regel anzuhängen, die nur gewinnt, weil sie später steht. Kommentare in der Datei bleiben unangetastet, denn das "Warum" neben einer Regel ist meist mehr wert als die Regel selbst.
Jedes Speichern ist eine ganz normale Gitcito-Aktion: es toastet, und Rückgängig stellt die Datei exakt so wieder her, wie sie war.
Ein Repository kann mehrere Attributdateien haben. Eine im Wurzelverzeichnis,
eine in jedem Unterverzeichnis und eine private .git/info/attributes, die nie
committet wird und nur auf deiner Maschine gilt — der richtige Ort für eine
Regel, bei der es um dich geht und nicht um das Projekt. Gitcito listet sie alle
auf und sagt dir, welche welche ist.
Was gilt für einen Pfad?
Regeln kommen aus mehreren Dateien, die spezifischere gewinnt, und sie
durchzulesen, um die Antwort herzuleiten, ist Raterei. Was gilt für einen
Pfad? führt git check-attr aus und zeigt, was git selbst daraus schließt —
die einzige Antwort, die zählt.
Diff-Treiber: ein Word-Dokument lesbar machen
Ein .docx ist ein Zip. Ein .pdf ist ein komprimierter Objektgraph. Git
diffet sie als das, was sie sind — Rauschen — und so ist die Historie eines
Dokuments unlesbar, obwohl das Dokument es nicht ist.
Ein Diff-Treiber behebt das mit textconv: ein Befehl, der die Datei nur
zum Diffen in Text verwandelt. Die Datei in deinem Arbeitsverzeichnis bleibt
unangetastet; git vergleicht bloß den konvertierten Text.
Zwei Hälften, und beide werden gebraucht:
diff.<name>.textconvin der git-Config — der Konverter-Befehl.*.docx diff=<name>in.gitattributes— auf welche Dateien er zutrifft.
Die Buttons hier erledigen beides auf einmal. Für Word, Excel, JSON und .strings
liefert Gitcito den Konverter selbst mit — dieselbe Dokumenten-Analyse,
die auch seine Vorschauen nutzen, als kleiner gitcito-textconv-Befehl in der
App — diese vier funktionieren also ganz ohne Installation. Der Rest braucht
weiterhin ein echtes Tool in deinem PATH: Gitcito prüft das und graut aus, was
fehlt, statt einen Treiber zu schreiben, der beim ersten Diff scheitert.
| Treiber | Braucht | Bringt dir |
|---|---|---|
word |
nichts — wird mit Gitcito geliefert | Fließtext-Diffs von .docx |
excel |
nichts — wird mit Gitcito geliefert | Zeilen-Diffs (CSV je Blatt) von .xlsx/.xls |
json |
nichts — wird mit Gitcito geliefert | Nach Schlüsseln sortierte, stabile JSON-Diffs |
strings |
nichts — kommt mit Gitcito | Zeilendiffs einer UTF-16-.strings, die git binär nennt |
pdf |
pdftotext (poppler) |
Text-Diffs von .pdf |
exif |
exiftool |
Was sich an einem Bild geändert hat, wenn die Pixel undurchsichtig sind |
Der, der iOS-Projekte beißt
Localizable.strings ist über fast Xcodes gesamte Geschichte UTF-16, und UTF-16
steckt voller NUL-Bytes — also nennt git die Datei binär und zeigt nichts:
diff --git a/Localizable.strings b/Localizable.strings
Binary files a/Localizable.strings and b/Localizable.strings differ
Ausgerechnet dort ist es am wichtigsten zu sehen, welchen String jemand
verschoben hat. Der Treiber strings dekodiert sie nur fürs Diffen — und liest
dabei die Byte-Order-Markierung, statt sie zu unterstellen, sodass eine moderne
UTF-8-.strings unversehrt durchgeht statt zu Buchstabensalat zu werden.
String Catalogs (.xcstrings, ab Xcode 15) sind JSON, und der json-Treiber
deckt sie ab: Er sortiert Schlüssel, sodass eine oben eingefügte Übersetzung
nicht länger die ganze Datei im Diff neu schreibt.
Die Grenzen des mitgelieferten Konverters, klar benannt: .doc (das alte
binäre Word-Format) wird nicht verstanden, nur .docx; PDF ist nicht
abgedeckt — Gitcito zeigt PDFs mit dem Viewer des Browsers an und hat keinen
Textextraktor zum Wiederverwenden; und jeder Diff eines Dokuments zahlt eine
kurze Startzeit des Konverters. Mit git config diff.<name>.cachetextconv true
cacht git die Ausgabe pro Blob.
Die Konverter-Hälfte liegt in deiner Config, nicht im Repository — git führt
keine Befehle aus, die ein Klon dir unterschiebt, und das ist eine
Sicherheitseigenschaft, die man behalten will. Die mitgelieferten Treiber
zeigen außerdem auf deinen Gitcito-Installationspfad; wer also klont, bekommt
die diff=word-Regel und, bis er einen eigenen Konverter verdrahtet (Gitcito
oder etwas anderes), den alten unlesbaren Diff. Schreib das in dein README.
Clean-/Smudge-Filter — mit vorherigem Probelauf
Ein Filter schreibt Inhalte auf dem Weg ins Repository und wieder heraus
um: clean läuft beim Stagen (Arbeitsverzeichnis → Repo), smudge beim
Checkout (Repo → Arbeitsverzeichnis). So funktioniert git-lfs, und so entfernen
Teams Zugangsdaten oder generiertes Rauschen aus dem, was committet wird.
Es ist zugleich das Gefährlichste, worauf .gitattributes zeigen kann: ein
Filter läuft bei jedem Checkout jeder passenden Datei, und ein falscher
beschädigt stillschweigend dein Arbeitsverzeichnis. Deshalb weigert sich
Gitcito, hier ein bloßes Textfeld zu sein. Einen Filter zu konfigurieren führt
über einen Probelauf gegen echte passende Dateien in deinem Repository:
- Der
clean-Befehl läuft auf einer Kopie jeder passenden Datei (bis zu fünf) — nichts im Repository oder seiner Config wird angefasst. - Ist ein
smudge-Befehl angegeben, läuft er auf der bereinigten Ausgabe, und das Ergebnis wird Byte für Byte mit dem Original verglichen — die Roundtrip-Prüfung. Ein Filter, der den Roundtrip nicht besteht, bedeutet: ein Checkout stellt nicht wieder her, was du hattest. - Erst nach einem Probelauf mit genau den Werten, die du speicherst, wird der Speichern-Button scharf geschaltet. Ein gescheiterter Probelauf — Befehlsfehler, keine Treffer oder ein abweichender Roundtrip — lässt sich trotzdem speichern, aber nur über eine ausdrückliche Warnung, die sagt, was verloren gehen kann.
Speichern schreibt filter.<name>.clean/smudge in deine lokale git-Config
und die filter=<name>-Regel in die Attributdatei und hinterlässt einen
Eintrag zum Rückgängigmachen, der wiederherstellt, was die Config vorher
enthielt. Der Schalter required setzt filter.<name>.required, womit git
eine Operation fehlschlagen lässt, statt Dateien stillschweigend
durchzureichen, wenn der Filter kaputtgeht.
Die Grenzen, klar benannt: der Probelauf nimmt als Stichprobe bis zu fünf
passende Dateien von höchstens 5 MB, mit 10 Sekunden Timeout pro Befehl — ein
Filter, der sich an der Stichprobe gut verhält, kann an einer Datei, die die
Stichprobe verpasst hat, trotzdem danebengehen. Die Befehle liegen in deiner
Config; wer klont, bekommt also die filter=<name>-Regel, aber nicht die
Befehle — ohne sie (und ohne required) laufen die Dateien unverändert durch.
Grenzen, die man kennen sollte
text=autoändert, was committet wird, und normalisiert Zeilenenden auf dem Weg hinein. Füge es in einem bestehenden Repository hinzu und führe dann bewusstgit add --renormalize .aus, in einem eigenen Commit.- Attribute wirken nicht rückwirkend. Eine Datei heute als
binaryzu markieren, ändert nicht, wie ihre vergangenen Diffs gespeichert wurden; es ändert, wie git sie ab jetzt behandelt. - Regeln greifen nur dort, wo die Datei sichtbar ist. Eine Regel in
design/.gitattributessagt nichts übersrc/aus. - Gitcito schreibt ganze Dateien, eine von Hand formatierte Datei kommt also mit
ihrer Formatierung zurück — aber eine Regel, die Gitcito umschreibt, wird auf
gits kanonische
pattern attr attr-Abstände umformatiert.
Siehe auch: LFS & Sparse Checkout · Bundles & Archive · Merge-Optionen · Hooks