Skip to content

Commit 09f5aaa

Browse files
gitattributes: restore canonical ruleset from main; add vault guards
The 110-line case-folded LFS + eol ruleset was deleted in 2658311d6, leaving zero attributes resolving: LFS orphaned (1,845 pointers, no patterns), no eol authority (system core.autocrlf=true unchecked - the mechanism behind the 2026-08-11 .ollama model-blob corruption). Base = origin/main:.gitattributes adopted verbatim (incl. #954's anchored extensionless-config block) so the eventual logan/obsidian -> main merge stays suffix-only. Vault-local section appends: .ollama byte-exactness guard (-text -diff -merge -filter), LF-anchored repo plumbing, and census binary classes (fonts/ico/pyc/etl/dat/sqlite-wal). Historical raw blobs (440 jpg / 130 png / 52 mp4 / 16 MOV) deliberately NOT converted - no renormalize churn; they migrate individually on next modification. Future adds of all media classes go to LFS automatically.
1 parent 610484c commit 09f5aaa

1 file changed

Lines changed: 168 additions & 0 deletions

File tree

.gitattributes

Lines changed: 168 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,171 @@
1+
# Git LFS tracking for binary/media types.
2+
#
3+
# IMPORTANT: .gitattributes pattern matching is CASE-SENSITIVE. A bare `*.mov`
4+
# does NOT match `CLIP.MOV`, and cameras/decks/phones routinely write UPPERCASE
5+
# extensions (XD4_6602.MXF, MVI_1487.MOV). To avoid that gap, every extension
6+
# below uses character classes — `*.[Mm][Oo][Vv]` — so all case permutations
7+
# (mov / MOV / Mov / …) are tracked. When adding a new binary type, follow the
8+
# same case-folding form. See VAULT-MEDIA-STORAGE.md § Enforcement.
9+
#
10+
# This is the first line of defense only; .github/scripts/check_large_files.py
11+
# is the case-agnostic backstop that blocks any >100 MB file lacking LFS
12+
# attributes and any file over the 2 GB GitHub ceiling.
13+
14+
# Audio / video
15+
*.[Mm]4[Aa] filter=lfs diff=lfs merge=lfs -text
16+
*.[Mm][Pp]3 filter=lfs diff=lfs merge=lfs -text
17+
*.[Mm][Pp]4 filter=lfs diff=lfs merge=lfs -text
18+
*.[Mm][Oo][Vv] filter=lfs diff=lfs merge=lfs -text
19+
*.[Aa][Vv][Ii] filter=lfs diff=lfs merge=lfs -text
20+
*.[Mm][Kk][Vv] filter=lfs diff=lfs merge=lfs -text
21+
*.[Mm][Xx][Ff] filter=lfs diff=lfs merge=lfs -text
22+
# AVCHD camera containers are written UPPERCASE (.MTS / .M2TS). `.mts`
23+
# (lowercase) is the TypeScript module-source extension, so the .MTS LFS rule is
24+
# intentionally UPPERCASE-ONLY — lowercase `.mts`/`.cts` are normalized as text
25+
# in the normalization section below, and no filter override is needed. A stray
26+
# lowercase camera `.mts` is still caught by check_large_files.py. .M2TS has no
27+
# source-format collision, so it stays case-folded.
28+
*.MTS filter=lfs diff=lfs merge=lfs -text
29+
*.[Mm]2[Tt][Ss] filter=lfs diff=lfs merge=lfs -text
30+
*.[Ww][Aa][Vv] filter=lfs diff=lfs merge=lfs -text
31+
*.[Aa][Aa][Cc] filter=lfs diff=lfs merge=lfs -text
32+
*.[Ff][Ll][Aa][Cc] filter=lfs diff=lfs merge=lfs -text
33+
*.[Oo][Gg][Gg] filter=lfs diff=lfs merge=lfs -text
34+
*.[Ww][Mm][Aa] filter=lfs diff=lfs merge=lfs -text
35+
36+
# Images
37+
*.[Jj][Pp][Gg] filter=lfs diff=lfs merge=lfs -text
38+
*.[Jj][Pp][Ee][Gg] filter=lfs diff=lfs merge=lfs -text
39+
*.[Pp][Nn][Gg] filter=lfs diff=lfs merge=lfs -text
40+
*.[Gg][Ii][Ff] filter=lfs diff=lfs merge=lfs -text
41+
*.[Ww][Ee][Bb][Pp] filter=lfs diff=lfs merge=lfs -text
42+
*.[Bb][Mm][Pp] filter=lfs diff=lfs merge=lfs -text
43+
*.[Tt][Ii][Ff][Ff] filter=lfs diff=lfs merge=lfs -text
44+
*.[Tt][Ii][Ff] filter=lfs diff=lfs merge=lfs -text
45+
*.[Hh][Ee][Ii][Cc] filter=lfs diff=lfs merge=lfs -text
46+
*.[Hh][Ee][Ii][Ff] filter=lfs diff=lfs merge=lfs -text
47+
*.[Cc][Rr]2 filter=lfs diff=lfs merge=lfs -text
48+
*.[Pp][Ss][Dd] filter=lfs diff=lfs merge=lfs -text
49+
*.[Ss][Vv][Gg] filter=lfs diff=lfs merge=lfs -text
50+
51+
# Documents
52+
*.[Pp][Dd][Ff] filter=lfs diff=lfs merge=lfs -text
53+
*.[Dd][Oo][Cc] filter=lfs diff=lfs merge=lfs -text
54+
*.[Dd][Oo][Cc][Xx] filter=lfs diff=lfs merge=lfs -text
55+
*.[Xx][Ll][Ss] filter=lfs diff=lfs merge=lfs -text
56+
*.[Xx][Ll][Ss][Xx] filter=lfs diff=lfs merge=lfs -text
57+
*.[Pp][Pp][Tt] filter=lfs diff=lfs merge=lfs -text
58+
*.[Pp][Pp][Tt][Xx] filter=lfs diff=lfs merge=lfs -text
59+
60+
# Geospatial
61+
*.[Gg][Ee][Oo][Jj][Ss][Oo][Nn] filter=lfs diff=lfs merge=lfs -text
62+
*.[Kk][Mm][Ll] filter=lfs diff=lfs merge=lfs -text
63+
*.[Kk][Mm][Zz] filter=lfs diff=lfs merge=lfs -text
64+
*.[Ss][Hh][Pp] filter=lfs diff=lfs merge=lfs -text
65+
*.[Gg][Pp][Xx] filter=lfs diff=lfs merge=lfs -text
66+
67+
# Archives
68+
*.[Zz][Ii][Pp] filter=lfs diff=lfs merge=lfs -text
69+
*.[Tt][Aa][Rr] filter=lfs diff=lfs merge=lfs -text
70+
*.[Gg][Zz] filter=lfs diff=lfs merge=lfs -text
71+
*.7[Zz] filter=lfs diff=lfs merge=lfs -text
72+
*.[Rr][Aa][Rr] filter=lfs diff=lfs merge=lfs -text
73+
74+
# Binaries / databases / mail
75+
*.[Dd][Mm][Gg] filter=lfs diff=lfs merge=lfs -text
76+
*.[Ee][Xx][Ee] filter=lfs diff=lfs merge=lfs -text
77+
*.[Bb][Ii][Nn] filter=lfs diff=lfs merge=lfs -text
78+
*.[Dd][Bb] filter=lfs diff=lfs merge=lfs -text
79+
*.[Ss][Qq][Ll][Ii][Tt][Ee] filter=lfs diff=lfs merge=lfs -text
80+
*.[Ss][Qq][Ll][Ii][Tt][Ee]3 filter=lfs diff=lfs merge=lfs -text
81+
*.[Mm][Ss][Gg] filter=lfs diff=lfs merge=lfs -text
82+
*.[Ee][Mm][Ll] filter=lfs diff=lfs merge=lfs -text
83+
84+
# Text file normalization — enforce LF line endings across platforms
85+
*.md text eol=lf
86+
*.txt text eol=lf
87+
*.py text eol=lf
88+
*.yml text eol=lf
89+
*.yaml text eol=lf
90+
*.json text eol=lf
91+
*.sh text eol=lf
92+
*.toml text eol=lf
93+
*.css text eol=lf
94+
*.js text eol=lf
95+
*.ts text eol=lf
96+
# TypeScript .mts/.cts module sources (lowercase). The .MTS media rule above is
97+
# uppercase-only, so these are plain text and never LFS — no filter override needed.
98+
*.mts text eol=lf
99+
*.cts text eol=lf
100+
*.ps1 text eol=lf
101+
*.psm1 text eol=lf
102+
*.psd1 text eol=lf
103+
*.bat text eol=lf
104+
*.cmd -text
105+
*.ini text eol=lf
106+
*.cfg text eol=lf
107+
*.conf text eol=lf
108+
*.csv -text
109+
*.tsv text eol=lf
110+
*.mdx text eol=lf
111+
112+
# Tool configs with no extension, plus one XML that needs naming individually.
113+
# check_character_conformity.py judges only files whose `text` attribute is
114+
# set; anything unspecified is skipped and counted as a gap. Without these,
115+
# the configs added in #950 join that bucket.
116+
#
117+
# Leading slashes anchor these to the repo root. Without one, a .gitattributes
118+
# pattern with no slash is a BASENAME match at any depth -- the same rule as
119+
# .gitignore -- so a bare `.pylintrc` would also claim any nested one.
120+
#
121+
# NOT `*.xml`: RSS.xml is committed with CRLF, and a blanket `text eol=lf`
122+
# would rewrite its line endings as a side effect of declaring a config file.
123+
/.bandit text eol=lf
124+
/.pylintrc text eol=lf
125+
/.remarkrc text eol=lf
126+
/.shellcheckrc text eol=lf
127+
/.stylelintrc text eol=lf
128+
/ruleset.xml text eol=lf
129+
130+
# =====================================================================
131+
# VAULT-LOCAL ADDITIONS (logan/obsidian) — everything above this line is
132+
# the canonical main ruleset, adopted verbatim; add vault rules HERE only
133+
# so the eventual logan/obsidian -> main merge stays suffix-only.
134+
# Later rules win: anchored guards below override generic classes above.
135+
# =====================================================================
136+
137+
# --- .ollama model store: byte-exact or nothing ----------------------
138+
# 2026-08-11 incident: core.autocrlf CRLF conversion + truncation
139+
# corrupted model blobs while .ollama/models was briefly tracked. Blobs
140+
# are gitignored (.ollama/models/blobs/**); the tracked manifests are
141+
# extensionless JSON keyed into a content-addressed store. Everything
142+
# under .ollama is opted out of eol conversion, text diff/merge, and
143+
# every clean/smudge filter (including LFS).
144+
/.ollama/** -text -diff -merge -filter
145+
# The one human document in the store stays normal prose:
146+
/.ollama/OLLAMA.md text eol=lf
147+
148+
# --- Repo plumbing must land LF on disk ------------------------------
149+
# Extensionless (no generic rule matches); core.autocrlf=true would
150+
# smudge a fresh Windows checkout to CRLF, breaking sh hooks. Anchored.
151+
/.githooks/* text eol=lf
152+
/.gitattributes text eol=lf
153+
/.gitignore text eol=lf
154+
/.editorconfig text eol=lf
155+
156+
# --- Binary classes in the vault census with no rule above -----------
157+
# Declared binary (no eol/diff/merge mangling). Deliberately NOT LFS:
158+
# small classes; LFS stays reserved for plausibly-large media.
159+
*.[Ww][Oo][Ff][Ff] binary
160+
*.[Ww][Oo][Ff][Ff]2 binary
161+
*.[Tt][Tt][Ff] binary
162+
*.[Oo][Tt][Ff] binary
163+
*.[Ii][Cc][Oo] binary
164+
*.[Pp][Yy][Cc] binary
165+
*.[Ee][Tt][Ll] binary
166+
*.[Dd][Aa][Tt] binary
167+
*.[Ss][Qq][Ll][Ii][Tt][Ee]-[Ww][Aa][Ll] binary
168+
*.[Ss][Qq][Ll][Ii][Tt][Ee]-[Ss][Hh][Mm] binary
1169

2170
# ---------------------------------------------------------------
3171
# THE WORLD IS QUIET HERE.ESTO PERPETUA!

0 commit comments

Comments
 (0)