Skip to content

scope .gitattributes bluepilot/ binary override to actual binaries - #187

Open
kevin-david wants to merge 1 commit into
BluePilotDev:bp-devfrom
kevin-david:fix/gitattributes-bluepilot-text
Open

scope .gitattributes bluepilot/ binary override to actual binaries#187
kevin-david wants to merge 1 commit into
BluePilotDev:bp-devfrom
kevin-david:fix/gitattributes-bluepilot-text

Conversation

@kevin-david

@kevin-david kevin-david commented Aug 19, 2026

Copy link
Copy Markdown
Contributor

The problem

.gitattributes currently has:

# BluePilot: keep BP-owned binaries as raw git objects (not LFS) so they need no LFS hosting
bluepilot/** -filter -diff -merge

-filter is the part that does the stated job, and only 11 files under bluepilot/ need it: 10 png icons and material-icons.ttf. Those are the only files there matching an LFS rule earlier in the file. The glob matches all 256 tracked files under bluepilot/, so the other 245 pick up -diff and -merge too. Those 245 are Python, TypeScript/TSX, CSS, JS, JSON, and Markdown.

Marking text as binary costs three things.

Pull requests under bluepilot/ show no reviewable diff

GitHub honors .gitattributes, so it renders every change under bluepilot/ as "Binary file not shown". A PR that touches the backend or the web portal arrives with no patch to read.

Conflicts under bluepilot/ cannot be 3-way merged

-merge selects the binary merge driver, which has no 3-way merge. A conflict keeps one whole side, drops the other, and prints Cannot merge binary files. Recovery means extracting the three stages and running git merge-file by hand. bluepilot/backend_switch.py conflicts routinely when merging between branches, so this happens in practice. The silent drop is the risky part, because nothing tells you a side went missing.

The tree is invisible to grep-based tooling

git grep -I also honors the diff attribute, so every tool that skips binaries skips all of bluepilot/: CI greps, secret and credential scanners, license scanners, and manual audits. Measured on bp-dev:

$ git grep -IoE '([A-Za-z0-9_-]+\.)*comma\.ai' -- 'bluepilot/*' | wc -l
0      # current attributes
1      # with this patch  ->  bluepilot/backend_switch.py:connect.comma.ai

A file that git cannot grep is a file nobody can audit.

The fix

Replace the catch-all with the seven extensions the LFS rules above claim, scoped to bluepilot/. Text files get no override at all, so git applies its own binary detection to them.

Naming the binaries is better than re-enabling diff and merge on the text files, for two reasons:

  1. Git detects binary content by NUL byte, so a new binary type under bluepilot/ is handled correctly with no attribute at all. An explicit diff would instead force text treatment on it, which recreates a smaller version of this bug.
  2. The seven extensions here are exactly the set the global LFS rules cover, so a new BP-owned binary of any of those types still bypasses LFS. The catch-all did that too, and this keeps it.

Verification

git check-attr diff merge filter over all 256 tracked files under bluepilot/:

binaries (11) everything else (245)
before diff: unset, merge: unset, filter: unset diff: unset, merge: unset, filter: unset
after unchanged unspecified for all three, which is git's default

No file moves into or out of LFS.

Alternatives considered

Deleting the bluepilot/** line outright, with no replacement: the 11 binaries then resolve to filter: lfs, which is the LFS hosting the comment exists to avoid.

Deleting the inherited *.onnx *.svg *.png *.gif *.ttf *.otf *.wav filter=lfs block instead, so nothing under bluepilot/ needs a -filter override at all: this breaks the repo. 263 tracked files currently resolve to filter: lfs, and their blobs are pointers rather than content. git cat-file -p HEAD:selfdrive/modeld/models/dmonitoring_model.onnx returns 132 bytes of version https://git-lfs.github.com/spec/v1 / oid sha256:... / size 7494962. Without the filter rule, git checks those pointers out as the model files, and the model build fails. Reversing the LFS setup would mean migrating all 263 objects back into git history first.

Appending one line to bluepilot/backend_switch.py, before and after:

before:  bluepilot/backend_switch.py | Bin 10127 -> 10135 bytes
                                       1 file changed, 0 insertions(+), 0 deletions(-)
after:   bluepilot/backend_switch.py | 1 +
                                       1 file changed, 1 insertion(+)

This PR's own diff renders normally, because the bug affects files under bluepilot/ rather than .gitattributes itself. To reproduce it, edit any bluepilot/*.py and run git diff with and without the patch applied.

The change touches one file and no code.

@kevin-david
kevin-david force-pushed the fix/gitattributes-bluepilot-text branch from 601bcf0 to 28218fa Compare August 19, 2026 20:56
The `bluepilot/** -filter -diff -merge` line keeps BP-owned binaries as raw git
objects instead of LFS. Only 11 files under bluepilot/ need that: 10 png icons
and material-icons.ttf. Those are the only ones matching an LFS rule above. The
glob matches all 256 tracked files there, so the other 245 inherit `-diff` and
`-merge` as well. Those 245 are Python, TypeScript/TSX, CSS, JS, JSON, and
Markdown.

Marking text as binary costs three things.

GitHub honors .gitattributes, so it renders every change under bluepilot/ as
"Binary file not shown". A pull request that touches the backend or the web
portal shows no reviewable patch.

`-merge` selects the binary merge driver, which cannot perform a 3-way merge. A
conflict under bluepilot/ keeps one whole side and drops the other, and recovery
requires extracting the three stages and running `git merge-file` by hand.
bluepilot/backend_switch.py conflicts routinely when merging between branches, so
this happens in practice, and nothing warns you that a side was dropped.

`git grep -I` also honors the `diff` attribute, so the tree is invisible to any
tool that skips binaries: CI greps, secret scanners, license scanners, and manual
audits. A `git grep -I` for comma.ai under bluepilot/ returns 0 hits today and 1
hit after this change, in backend_switch.py.

Replace the catch-all with the seven extensions the LFS rules above claim, scoped
to bluepilot/. Text files get no override at all, so git applies its own binary
detection to them. That is the behavior the original comment describes.

Naming the binary extensions rather than re-enabling diff and merge on the text
ones matters for two reasons. Git auto-detects binary content by NUL byte, so a
new binary type under bluepilot/ is handled correctly with no attribute, while an
explicit `diff` would force text treatment on it. And the seven extensions listed
here are exactly the set the global LFS rules cover, so a new BP-owned binary of
any of those types still bypasses LFS, which the catch-all also did.

Verified with `git check-attr diff merge filter` over all 256 tracked files under
bluepilot/. Before: all 256 report `diff: unset, merge: unset, filter: unset`.
After: the 11 binaries keep that, and the other 245 report `unspecified` for all
three, which is git's default handling. No file moves into or out of LFS.
Appending one line to backend_switch.py now produces `1 file changed, 1
insertion(+)` instead of `Bin 10127 -> 10135 bytes`.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@kevin-david
kevin-david force-pushed the fix/gitattributes-bluepilot-text branch from 28218fa to d227feb Compare August 19, 2026 21:26
@kevin-david kevin-david changed the title gitattributes: stop treating bluepilot/ text sources as binary gitattributes: scope the bluepilot/ binary override to actual binaries Aug 19, 2026
@kevin-david
kevin-david marked this pull request as ready for review August 19, 2026 21:47
@kevin-david kevin-david changed the title gitattributes: scope the bluepilot/ binary override to actual binaries scope .gitattributes bluepilot/ binary override to actual binaries Aug 19, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant