Skip to content

Binary file change by hook not detected due to Git textconv #2742

@adamchainz

Description

@adamchainz

search you tried in the issue tracker

textconv

describe your issue

I’ve set up Git to use exiftool as a text conversion filter for JPEGs, with this in ~/.config/git/config:

[diff "exiftool"]
    textconv = exiftool --composite -x 'Exiftool:*' -x 'File:*' -g0
    cachetextconv = true
    xfuncname = "^-.*$"

…and this in ~/.config/git/attributes:

*.jpeg diff=exiftool

In my repo, I’m using jpegoptim to optimize JPEG's with the below .pre-commit-config.yaml.

Take an unoptimized JPEG:

$ git status
On branch main
Changes to be committed:
        new file:   donut.jpeg

Running pre-commit, the hook passes:

$ pre-commit run jpegoptim
Optimize JPEGs...........................................................Passed

(There’s no option to make jpegoptim exit with a non-zero status code when it changes files.)

However, the tool did actually modify the image:

$ git status
On branch main
Changes to be committed:
        new file:   donut.jpeg

Changes not staged for commit:
        modified:   donut.jpeg

This behaviour means commits don't include the optimized version of a flie, instead they’re left around unstaged.

pre-commit doesn't detect the change because the text conversions of the binary file before/after are the same, leading to an empty diff:

$ git diff donut.jpeg

But using --no-textconv shows the tool actually made a change:

$ git diff --no-textconv donut.jpeg |cat
diff --git a/donut.jpeg b/donut.jpeg
index 3bd0743..d66a2f4 100644
Binary files a/donut.jpeg and b/donut.jpeg differ


The `git diff` call that pre-commit uses to check for changes, in [`_git_diff()`](https://github.com/pre-commit/pre-commit/blob/e846829992a84ce8066e6513a72a357709eec56c/pre_commit/commands/run.py#L273C6-L277) already uses `--no-ext-diff` to make diffs reproducible
I think it should also use `--no-textconv`.
This would also make it a little faster.

### pre-commit --version

3.0.3 / main

### .pre-commit-config.yaml

```yaml
repos:
-   repo: local
    hooks:
    -   id: jpegoptim
        name: Optimize JPEGs
        entry: jpegoptim
        language: system
        types: [jpeg]

~/.cache/pre-commit/pre-commit.log (if present)

No response

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions