Attributi dei file
.gitattributes è il file di git con il rapporto valore/diffusione più
squilibrato: quasi nessuno lo scrive. È il modo in cui un repository insegna a
git com'è fatto il suo contenuto: quali file sono binari, quali devono
concatenarsi invece di andare in conflitto, quali non devono mai finire in un
archivio, quali fine riga tocca a tutti.
La parte che conta: viene committato. Una regola che aggiungi risolve il problema per chiunque cloni, su ogni sistema operativo, per sempre — al contrario di un'impostazione nella tua configurazione personale, che lo risolve per te e lascia i colleghi a scoprirlo nel modo peggiore.
⌘K → Attributi dei file.

Cosa fanno le regole
| Attributo | Risolve |
|---|---|
text=auto eol=lf |
Fine riga che cambiano a seconda di chi ha fatto il checkout |
binary |
Git che tenta di fare il diff o il merge a tre vie di un PSD, un DOCX, un asset compilato |
merge=union |
Un changelog a cui tutti aggiungono in fondo, e su cui tutti vanno in conflitto |
-merge |
File in cui un merge a tre vie produce assurdità — lockfile, codice generato |
export-ignore |
Configurazioni CI e fixture spedite dentro un tarball di release |
diff=<driver> |
Diff illeggibili per formati che sarebbero leggibili, dato un convertitore |
filter=lfs |
File grandi conservati tramite LFS |
linguist-vendored |
Codice di terze parti conteggiato come tuo nelle statistiche dei linguaggi |
binary è l'abbreviazione di -diff -merge -text, cioè tre risposte a "smettila
di fare congetture su questo file" in una parola sola.
Modifica
I preset compilano un pattern e i suoi attributi; modifica il pattern prima di
aggiungerlo — CHANGELOG.md è un suggerimento, non una regola sul tuo progetto.
Le modifiche sono chirurgiche. Aggiungere una regola per un pattern che ne ha già una riscrive quella riga dove si trova, invece di accodare una seconda regola che vince solo perché viene dopo. I commenti nel file sopravvivono intatti, perché il "perché" accanto a una regola di solito vale più della regola stessa.
Ogni salvataggio è una normale azione di Gitcito: produce un toast, e Annulla riporta il file esattamente com'era.
Un repository può avere più file di attributi. Uno alla radice, uno in
qualsiasi sottodirectory, e un .git/info/attributes privato che non viene mai
committato e vale solo sulla tua macchina — il posto giusto per una regola che
riguarda te, non il progetto. Gitcito li elenca tutti e dice quale è quale.
Cosa si applica a un percorso?
Le regole arrivano da più file, vince la più specifica, e leggerle per dedurre la
risposta è tirare a indovinare. Cosa si applica a un percorso? esegue
git check-attr e mostra cosa conclude git stesso — l'unica risposta che conta.
Diff driver: rendere leggibile un documento Word
Un .docx è uno zip. Un .pdf è un grafo di oggetti compressi. Git ne fa il
diff per quello che sono — rumore — e così la storia di un documento diventa
illeggibile anche se il documento non lo è.
Un diff driver risolve la cosa con textconv: un comando che trasforma il
file in testo solo ai fini del diff. Il file nel tuo albero di lavoro resta
intatto; git confronta semplicemente il testo convertito.
Due metà, e servono entrambe:
diff.<name>.textconvnella configurazione git — il comando di conversione.*.docx diff=<name>in.gitattributes— a quali file si applica.
I pulsanti qui fanno entrambe le cose insieme. Per Word, Excel, JSON e .strings, Gitcito
include il convertitore esso stesso — lo stesso parsing dei documenti usato
dalle sue anteprime, esposto come un piccolo comando gitcito-textconv dentro
l'app — quindi quei quattro funzionano senza installare nulla. Gli altri richiedono
ancora uno strumento vero nel tuo PATH: Gitcito controlla e disattiva ciò che
manca, invece di scrivere un driver che fallisce al primo diff.
| Driver | Richiede | Ti dà |
|---|---|---|
word |
niente — incluso in Gitcito | Diff in prosa dei .docx |
excel |
niente — incluso in Gitcito | Diff riga per riga (CSV per foglio) dei .xlsx/.xls |
json |
niente — incluso in Gitcito | Diff JSON stabili, con chiavi ordinate |
strings |
niente — arriva con Gitcito | Diff per righe di un .strings UTF-16, che git chiama binario |
pdf |
pdftotext (poppler) |
Diff testuali dei .pdf |
exif |
exiftool |
Cosa è cambiato in un'immagine, quando i pixel sono opachi |
Quello che morde i progetti iOS
Localizable.strings è UTF-16 per quasi tutta la storia di Xcode, e l'UTF-16 è
pieno di byte NUL: git lo chiama binario e non mostra niente.
diff --git a/Localizable.strings b/Localizable.strings
Binary files a/Localizable.strings and b/Localizable.strings differ
Ed è proprio il file dove vedere quale stringa ha spostato qualcuno conta di
più. Il driver strings lo decodifica solo per il diff — leggendo il marcatore
d'ordine dei byte invece di darlo per scontato, così un .strings moderno in
UTF-8 passa intatto anziché diventare accozzaglia.
Gli String Catalog (.xcstrings, da Xcode 15) sono JSON, e il driver json li
copre: ordina le chiavi, così una traduzione aggiunta in cima smette di
riscrivere l'intero file nel diff.
I limiti del convertitore incluso, detti chiaramente: .doc (il vecchio
formato binario di Word) non è compreso, solo .docx; il PDF non è coperto —
Gitcito mostra l'anteprima dei PDF con il visore del browser e non ha un
estrattore di testo da riusare —; e ogni diff di un documento paga un breve
costo di avvio del convertitore.
Con git config diff.<name>.cachetextconv true git mette in cache l'output
per blob.
La metà del convertitore vive nella tua configurazione, non nel repository:
git non esegue comandi che un clone gli mette in mano, ed è una proprietà di
sicurezza che vale la pena conservare. I driver inclusi, inoltre, puntano al
tuo percorso di installazione di Gitcito, quindi un collega che clona riceve
la regola diff=word e, finché non collega un proprio convertitore (Gitcito o
altro), il vecchio diff illeggibile. Scrivilo nel tuo README.
Filtri clean/smudge — con una prova a secco prima
Un filtro riscrive il contenuto in entrata e in uscita dal repository:
clean gira allo stage (albero di lavoro → repo), smudge al checkout (repo →
albero di lavoro). È così che funziona git-lfs, ed è così che i team eliminano
credenziali o rumore generato da ciò che viene committato.
È anche la cosa più pericolosa a cui .gitattributes possa puntare: un filtro
gira a ogni checkout di ogni file corrispondente, e uno sbagliato corrompe
in silenzio il tuo albero di lavoro. Per questo qui Gitcito si rifiuta di
essere una semplice casella di testo.
Configurare un filtro passa per una prova a secco contro file reali del tuo
repository che corrispondono:
- Il comando
cleangira su una copia di ogni file corrispondente (fino a cinque) — niente nel repository o nella sua configurazione viene toccato. - Se è indicato un comando
smudge, gira sull'output pulito e il risultato viene confrontato byte per byte con l'originale — la verifica di andata e ritorno. Un filtro che non completa il giro significa che un checkout non ripristinerà quello che avevi. - Solo dopo una prova a secco su esattamente i valori che stai salvando il pulsante di salvataggio si attiva. Una prova a secco fallita — errore del comando, nessun file corrispondente, o un'andata e ritorno che differisce — si può comunque salvare, ma solo attraverso un avviso esplicito che dice cosa si può perdere.
Salvare scrive filter.<name>.clean/smudge nella tua configurazione git
locale e la regola filter=<name> nel file di attributi, e lascia una voce
di annullamento che ripristina ciò che la configurazione conteneva prima.
L'interruttore required imposta filter.<name>.required, con cui git fa
fallire l'operazione invece di lasciar passare i file in silenzio quando il
filtro si rompe.
I limiti, detti chiaramente: la prova a secco campiona fino a cinque file
corrispondenti di al massimo 5 MB ciascuno, con un timeout di 10 secondi per
comando — un filtro che si comporta bene sul campione può comportarsi male su
un file che il campione non ha visto. I comandi vivono nella tua
configurazione, quindi un collega che clona riceve la regola filter=<name> ma
non i comandi; senza di essi (e senza required) i suoi file passano
invariati.
Limiti da conoscere
text=autocambia cosa viene committato, normalizzando i fine riga in ingresso. Su un repository esistente, aggiungilo e poi eseguigit add --renormalize .deliberatamente, in un commit tutto suo.- Gli attributi non si applicano retroattivamente. Marcare oggi un file come
binarynon cambia come sono stati memorizzati i suoi diff passati; cambia come git lo tratta d'ora in avanti. - Le regole valgono solo dove il file è visibile. Una regola in
design/.gitattributesnon dice nulla susrc/. - Gitcito riscrive file interi, quindi un file formattato a mano torna con la sua
formattazione — ma una regola che Gitcito riscrive viene riformattata secondo
la spaziatura canonica di git,
pattern attr attr.
Vedi anche: LFS e sparse checkout · Bundle e archivi · Opzioni di merge · Hook